2010-02-02 20 views
12

Estoy trabajando en una aplicación de Android que muestra fotos que se descargan desde Flickr. Puedo obtener un objeto de mapa de bits a partir de una matriz de bytes, que a su vez se lee de la URL correspondiente Flickr, de la siguiente manera:Android: BitmapFactory.decodeByteArray da bitmap pixelado

BitmapFactory.Options opt = new BitmapFactory.Options(); 
opt.inDither = true; 
opt.inPreferredConfig = Bitmap.Config.ARGB_8888; 
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opt); 

entonces dibujar el mapa de bits en un lienzo en el método onDraw de un objeto View:

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); 
canvas.drawBitmap(bitmap, 0, 0, paint); 

El problema es que la imagen resultante está pixelada y no puedo entender por qué; He intentado varias variaciones de los objetos de opt y paint sin suerte. La diferencia entre la imagen que aparece en mi aplicación y la imagen en la dirección URL original es más o menos lo demuestra el siguiente:

Bad image, see pixelation in top left corner http://homepages.inf.ed.ac.uk/s0677975/bad.jpg

Good picture, this is the expected result http://homepages.inf.ed.ac.uk/s0677975/good.jpg

Mira, por ejemplo, en las nubes en la esquina superior izquierda para ver la diferencia.

Tenga en cuenta que las imágenes JPEG que se cargan desde los recursos del proyecto y se dibujan de manera similar se muestran bien, es decir, no tienen pixelación.

¿Alguien puede darme una pista de por qué está sucediendo esto?

Para elaborar un poco, la matriz de bytes se obtiene de Flickr de la siguiente manera; esto se basa en el código de la aplicación Secuencia de fotos de Romain Guy:

InputStream in = new BufferedInputStream(url.openStream(), IO_BUFFER_SIZE); 
final ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); 
out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE); 
copy(in, out); 
out.flush(); 
final byte[] data = dataStream.toByteArray(); 

PD: También he publicado una variante de esta cuestión en el grupo de Google android.developer.


Muchas gracias por su sugerencia - ¡Ahora estoy realmente perplejo! Hice lo que sugirió y descubrí que la imagen resultante directamente de la matriz de bytes descargada está efectivamente pixelada. Sin embargo, esto se descarga desde exactamente la misma URL que, cuando se accede desde mi computadora, NO está pixelada. Aquí está la URL correspondiente Flickr:

http://farm3.static.flickr.com/2678/4315351421_54e8cdb8e5.jpg

Aún más extraño, cuando corro la misma aplicación en el simulador y no en mi teléfono (un HTC Hero), no hay ninguna pixelación.

¿Cómo es esto posible?

A continuación se muestra el código que utilizo para cargar un mapa de bits de una dirección URL - que se basa en la aplicación Secuencia de fotos de Romain individuo, e incorpora la sugerencia de Will para escribir la matriz de bytes sin procesar en el archivo:

Bitmap loadPhotoBitmap(URL url) { 
    Bitmap bitmap = null; 
     InputStream in = null; 
     BufferedOutputStream out = null; 

     try { 

      FileOutputStream fos = new FileOutputStream("/sdcard/photo-tmp.jpg"); 
      BufferedOutputStream bfs = new BufferedOutputStream(fos); 

      in = new BufferedInputStream(url.openStream(), 
        IO_BUFFER_SIZE); 

      final ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); 
      out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE); 
      copy(in, out);      
      out.flush(); 
      final byte[] data = dataStream.toByteArray(); 

      bfs.write(data, 0, data.length); 
      bfs.flush(); 

      BitmapFactory.Options opt = new BitmapFactory.Options(); 
      bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opt); 

     } catch (IOException e) { 
      android.util.Log.e(LOG_TAG, "Could not load photo: " + this, e); 
     } finally { 
      closeStream(in); 
      closeStream(out) 
      closeStream(bfs); 
     } 

     return bitmap; 
    } 

private static void copy(InputStream in, OutputStream out) throws IOException { 
    byte[] b = new byte[IO_BUFFER_SIZE]; 
    int read; 
    while ((read = in.read(b)) != -1) { 
     out.write(b, 0, read); 
    } 
} 

private static void closeStream(Closeable stream) { 
    if (stream != null) { 
     try { 
      stream.close(); 
     } catch (IOException e) { 
      android.util.Log.e(LOG_TAG, "Could not close stream", e); 
     } 
    } 
} 

¿Me estoy volviendo loco aquí? Mejor, Michael.

+0

Me tomé la libertad de subrayar las imágenes, ya que por lo general la pregunta es más clara y fácil de leer. – unwind

+1

¿Alguna vez encontró una solución para esto? Probé las sugerencias, pero no tuve suerte. Es súper molesto – blork

+0

como nota al pie, no olvide que JPEG no tiene pérdida en el entorno de Android. aunque es compatible, se desaconseja a favor de PNG. – user836725

Respuesta

3

Escriba los bytes brutos obtenidos de la URL en /sdcard/tmp.jpg y visualícelos en su PC.

Las imágenes JPEG se comprimen en mosaicos de 8x8 (o 16x16). La "pixelación" tal como la describes está en realidad en estas fichas, lo que sugiere que la imagen "mala" es una JPEG comprimida más agresivamente que la otra.

Así que me gustaría anticipar que el problema real es que la imagen que se está descargando es una versión de muy baja calidad, p. uno destinado a thumbnailing/preview use-cases.

+0

También sospeché esto, pero el tamaño del archivo real de la imagen "mala" es aproximadamente 18% * más grande * que el "bueno". Rareza. – unwind

+0

Eso no prueba nada :) – Will

4

Bien, entonces finalmente lo entiendo: parece que mi red móvil hace compresión de imagen para ahorrar ancho de banda.

Por lo tanto, una imagen descargada de mi teléfono es de calidad inferior a la misma imagen descargada de mi computadora.

Eso es un fastidio para mi aplicación, pero supongo que no hay nada que pueda hacer al respecto. Suspiro.

¡Gracias de nuevo por su aporte!

Mejor, Michael.

+0

también podría ser provocado por los encabezados http - facebook en sí podría proporcionar imágenes de baja calidad para teléfonos móviles. Edite los encabezados antes de enviarlos, básicamente, elimínelos. – Will

+1

Puede intentar configurar los encabezados http para Aceptar-Codificación gzip. No estoy seguro, pero es posible que supere la compresión de la imagen de red. Consulte http://stackoverflow.com/questions/1573391/android-http-communication-should-use-accept-encoding-gzip –

+0

¿Ha intentado confirmar esto descargando la imagen en el navegador? Tengo el mismo problema, pero si abro la imagen en el navegador web obtengo una imagen no pixelada. Entonces debe haber una forma de obtener la imagen correcta. – Janusz

1

Algunas versiones de Android tienen un error en la clase de mapa de bits y convierten el mapa de bits a RGB_565 en algunas operaciones. Esto se manifestaría en artefactos similares a los de tu foto. Esto también explicaría las bandas del cielo azul. Además, tenga en cuenta que Android intenta "optimizar" la imagen convirtiéndola a rgb_565 al cargar e incluso compilar en archivos de recursos. Eche un vistazo a: http://android.nakatome.net/2010/04/bitmap-basics.html

Cuestiones relacionadas