Android: BitmapFactory.decodeByteArray дает пиксельное растровое изображение - PullRequest
12 голосов
/ 02 февраля 2010

Я работаю над приложением для 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); 

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

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

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

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

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

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

Для уточнения, байтовый массив получен из Flickr следующим образом; это основано на коде из приложения Photostream от 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();

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


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

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

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

Как, черт возьми, это возможно?

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

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

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

Ответы [ 3 ]

4 голосов
/ 02 февраля 2010

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

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

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

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

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

3 голосов
/ 02 февраля 2010

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

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

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

1 голос
/ 30 января 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...