从二进制 base64 加载图像

Load image from binary base64

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

原始问题:

我在我的应用程序中加载图像时遇到问题。

我的端点发送 JSON,其中包含 BASE64 编码图像。根据 REST 调用,这些图像可以是 PNGJPG。一些 JPG 文件存在结尾缺少 EOF 位的问题。 PNG 文件有效,一些 JPG 文件有效,但不幸的是,Oracle 数据库中存在很多这些 JPG 文件存在问题(存储为 BLOB)。我无法控制数据库。

我一直在查看 Google 此处的错误: https://code.google.com/p/android/issues/detail?id=9064 和这里: https://code.google.com/p/android/issues/detail?id=57502

使用自定义 ICC 配置文件的编码 CYMK 也会出现此问题。

以标准方式解码图像 returns false:

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

根据上面的错误报告,Android 中内置的 JPG 解析器是罪魁祸首。

我正在尝试为我的设备找出解决方法,该设备卡在 4.2.2 上。在这个 OS 版本上我没有其他选择。

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

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

这是我的 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;
        }
    }
}

顺便说一下,使用上面的自定义 class,我正在尝试像这样加载我的字节数组:

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]

通用图像加载器不允许 stream:// 模式,因此我创建了一个允许它的自定义 BaseImageDownloader class:

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,我将不胜感激!

谢谢。

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://

希望对您有所帮助。

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

该错误已在 Android 4.3 中修复。