从二进制 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 调用,这些图像可以是 PNG
或 JPG
。一些 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 中修复。
编辑:这是 Android 版本 <4.3 Kitkat 中的错误。它与 Android 中的 libjpeg 库有关,它无法处理缺少 EOF/EOI 位的 JPEG,或者显然有它不喜欢的 metadata/EXIF 数据。 https://code.google.com/p/android/issues/detail?id=9064
原始问题:
我在我的应用程序中加载图像时遇到问题。
我的端点发送 JSON
,其中包含 BASE64
编码图像。根据 REST 调用,这些图像可以是 PNG
或 JPG
。一些 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 中修复。