Android: BitmapFactory.decodeByteArray дает пикселированное растровое изображение

Я работаю над Android-приложением, которое отображает фотографии, загружаемые с Flickr. Я получаю растровый объект из массива байтов, который, в свою очередь, считывается с соответствующего URL-адреса Flickr следующим образом:

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

Затем я рисую растровое изображение на холсте в методе onDraw объекта View:

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

Проблема в том, что результирующая картинка неровная, и я не могу понять, почему; Я попробовал несколько вариантов объектов opt и paint без везения. Разница между изображением, отображаемым в моем приложении, и изображением исходного URL-адреса, примерно подтверждается следующим:

Плохое изображение, см. Пиксель в верхнем левом углу http://homepages.inf.ed.ac.uk/s0677975/bad.jpg

Хорошая картина, это ожидаемый результат http://homepages.inf.ed.ac.uk/s0677975/good.jpg

Посмотрите, например, на облака в верхнем левом углу, чтобы увидеть разницу.

Обратите внимание, что изображения JPEG, которые загружаются из ресурсов проекта и рисуются аналогичным образом, отображаются очень хорошо, т.е. не имеют пикселизации.

Может ли кто-нибудь дать мне подсказку, почему это происходит?

Чтобы немного вычислить, массив байтов получается из Flickr следующим образом; Это основано на коде из приложения Photostream от Ромена Гая:

 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(); 

PS: Я также опубликовал вариант этого вопроса в группе Android android.developer.


Большое спасибо за ваше предложение – теперь я действительно озадачен! Я сделал так, как вы предложили, и обнаружил, что изображение, полученное непосредственно из загруженного массива байтов, действительно пикселируется. Тем не менее, это загружается с точно такого же URL-адреса, который при доступе на моем компьютере НЕ пикселирован. Вот соответствующий URL-адрес Flickr:

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

Даже незнакомец, когда я запускаю одно и то же приложение в симуляторе, а не на своем телефоне (HTC Hero), пикселизации нет.

Как это возможно?

Ниже приведен код, который я использую для загрузки растрового изображения из URL-адреса – он основан на приложении Photostream от Ромен Гая и включает предложение Уилла о написании массива необработанных байтов в файл:

 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); } } } 

Я схожу с ума? Лучше, Майкл.

Solutions Collecting From Web of "Android: BitmapFactory.decodeByteArray дает пикселированное растровое изображение"

Напишите необработанные байты, полученные из URL-адреса, в /sdcard/tmp.jpg и просмотрите на ПК.

Изображения JPEG сжимаются в 8х8 (или 16х16) плитах. «Пикселизация», как вы ее описываете, на самом деле находится в этих фрагментах, предполагая, что «плохое» изображение представляет собой JPEG, который более агрессивно сжат, чем другой.

Поэтому я ожидал, что фактическая проблема заключается в том, что загружаемое изображение является очень некачественной версией, например, для превью-превью-превью.

Итак, я, наконец, понял: похоже, моя мобильная сеть делает сжатие изображений для экономии полосы пропускания.

Следовательно, изображение, загруженное с моего телефона, имеет более низкое качество, чем изображение, загруженное с моего компьютера.

Это врет для моего приложения, но я не думаю, что я могу с этим поделать. Вздох.

Еще раз спасибо за ваш вклад!

Лучше, Майкл.

В некоторых версиях Android есть ошибка в классе Bitmap и преобразование Bitmap в RGB_565 при некоторых операциях. Это проявилось бы в артефактах, подобных тем, что были на вашей картине. Это также объясняет полосу голубого неба. Кроме того, имейте в виду, что андроид пытается «оптимизировать» изображение, преобразовывая их в rgb_565 при загрузке и даже компиляции в файлах ресурсов. Взгляните на: http://android.nakatome.net/2010/04/bitmap-basics.html