从二进制base64加载图像

时间:2016-01-13 13:13:32

标签: android android-volley universal-image-loader

编辑:这是Android版本中的一个错误< 4.3 Kitkat。它涉及Android中的libjpeg库,它不能处理缺少EOF / EOI位的JPEG,或者显然没有它不喜欢的元数据/ EXIF数据。 https://code.google.com/p/android/issues/detail?id=9064

原始问题:

在我的应用中加载图片时出现问题。

我的端点发送JSON,其中包含BASE64编码图像。根据REST调用,这些图像可以是PNGJPG。某些JPG文件遇到的问题是它们最后缺少EOF位。 PNG文件有效,有些JPG文件可以正常工作,但不幸的是,这些带有问题的JPG文件存在于Oracle DB中(存储为BLOB)。我无法控制数据库。

我一直在浏览谷歌的错误: https://code.google.com/p/android/issues/detail?id=9064 和这里: https://code.google.com/p/android/issues/detail?id=57502

还可以看到使用自定义ICC配置文件进行编码CYMK的问题。

以标准方式解码图像会返回false

byte[] imageAsBytes = Base64.decode(base64ImageString, Base64.DEFAULT);
return BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length);

根据上面的错误报告,Android中内置的JPG解析器应该受到指责。

我试图找出我的设备的解决方法,该方法停留在4.2.2上。我对此操作系统版本没有其他选择。

我认为尝试使用像Universal Image Loader这样的图像加载器库可能是一个好主意,但它要求我将图像存储在本地,或存储在URL上。当我从REST服务器获取BASE64中的数据时,我无法使用它。一个选项是支持decodeByteArray扩展BaseImageDecoder的自定义类,如底部开发人员所述:https://github.com/nostra13/Android-Universal-Image-Loader/issues/209

在这里,我被卡住了。我已经有了一个自定义图像解码器来尝试处理JPG文件中缺少EOF标记的问题,但我不知道如何编辑它以添加对decodeByteArray的支持。

这是我的CustomImageDecoder

public class CustomImageDecoder extends BaseImageDecoder {

    public CustomImageDecoder(boolean loggingEnabled) {
        super(loggingEnabled);
    }

    @Override
    protected InputStream getImageStream(ImageDecodingInfo decodingInfo) throws IOException {
        InputStream stream = decodingInfo.getDownloader()
                .getStream(decodingInfo.getImageUri(), decodingInfo.getExtraForDownloader());
        return stream == null ? null : new JpegClosedInputStream(stream);
    }

    private class JpegClosedInputStream extends InputStream {

        private static final int JPEG_EOI_1 = 0xFF;
        private static final int JPEG_EOI_2 = 0xD9;
        private final InputStream inputStream;
        private int bytesPastEnd;

        private JpegClosedInputStream(final InputStream iInputStream) {
            inputStream = iInputStream;
            bytesPastEnd = 0;
        }

        @Override
        public int read() throws IOException {
            int buffer = inputStream.read();
            if (buffer == -1) {
                if (bytesPastEnd > 0) {
                    buffer = JPEG_EOI_2;
                } else {
                    ++bytesPastEnd;
                    buffer = JPEG_EOI_1;
                }
            }

            return buffer;
        }
    }
}

顺便说一句,使用上面的自定义类,我试图像这样加载我的字节数组:

byte[] bytes = Base64.decode(formattedB64String, Base64.NO_WRAP);
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
String imageId = "stream://" + is.hashCode();
...
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(imageId, userImage, options);

我收到此错误: ImageLoader: Image can't be decoded [stream://1097215584_656x383]

Universal Image loader不允许stream://架构,因此我创建了一个允许它的自定义BaseImageDownloader类:

public class StreamImageDownloader extends BaseImageDownloader {

    private static final String SCHEME_STREAM = "stream";
    private static final String STREAM_URI_PREFIX = SCHEME_STREAM + "://";

    public StreamImageDownloader(Context context) {
        super(context);
    }

    @Override
    protected InputStream getStreamFromOtherSource(String imageUri, Object extra) throws IOException {
        if (imageUri.startsWith(STREAM_URI_PREFIX)) {
            return (InputStream) extra;
        } else {
            return super.getStreamFromOtherSource(imageUri, extra);
        }
    }
}

因此,如果有人可以帮助我创建一个更好的CustomImageDecoder来处理BASE64编码的字符串,或者byte[]包含一个图像,那么我可以使用decodeByteArray,我会不胜感激!

谢谢。

2 个答案:

答案 0 :(得分:1)

UnversalImageLoader使用以下方案解码文件

"h t t p ://site.com/image.png" // from Web
"file:///mnt/sdcard/image.png" // from SD card
"file:///mnt/sdcard/video.mp4" // from SD card (video thumbnail)
"content://media/external/images/media/13" // from content provider
"content://media/external/video/media/13" // from content provider (video thumbnail)
"assets://image.png" // from assets
"drawable://" + R.drawable.img // from drawables (non-9patch images)

您的方案是stream://

希望有所帮助。

答案 1 :(得分:0)

关闭这个: 这里的问题实际上是Android< 4.3中的一个错误,其中Android无法显示未正确关闭的图像(缺少结束字节)或包含某些元数据,这些元数据由于某种原因而无法实现。喜欢。但是,我不确定这是什么元数据。我的问题是JPEG没有正确终止。

无论如何,该错误已在Android 4.3中修复。