BitmapFactory.decodeStream 来自 Assets returns null on Android 7
BitmapFactory.decodeStream from Assets returns null on Android 7
如何解码 Android 7 中 Asset 目录中的位图?
我的应用 运行 在 Marshmallow 之前的 Android 版本上运行良好。使用 Android 7 它无法从 Asset 目录加载图像。
我的代码:
private Bitmap getImage(String imagename) {
// Log.dd(logger, "AsyncImageLoader: " + ORDNER_IMAGES + imagename);
AssetManager asset = context.getAssets();
InputStream is = null;
try {
is = asset.open(ORDNER_IMAGES + imagename);
} catch (IOException e) {
// Log.de(logger, "image konnte nicht gelesen werden: " + ORDNER_IMAGES + imagename);
return null;
}
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, PW, PH);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
// Lesen des Bitmaps in der optimierten Groesse
return BitmapFactory.decodeStream(is, null, options);
}
结果(只有Android7)BitmapFactory.decodeStream
为空。它可以在较旧的 Android API 中正常工作。
在调试模式下,我看到以下消息:
09-04 10:10:50.384 6274-6610/myapp D/skia: --- SkAndroidCodec::NewFromStream returned null
谁能告诉我原因以及如何更正编码?
编辑:同时我发现,使用 inJustDecodeBounds=true 删除第一个 BitmapFactory.decodeStream 会导致随后使用 inJustDecodeBounds=false 成功 BitmapFactory.decodeStream。不知道原因,也不知道如何替代位图大小的测量。
如果这对任何人有帮助,我在更新以前用于调整图像大小的旧代码时遇到了类似的问题。 我的问题出在从图像文件读取数据的堆栈中。 我使用了 IOUtils.toByteArray(Reader)
,它已被弃用。我切换为直接从 URI 转换为字节数组,现在它运行良好。有关该新方法的示例,请参见下面 resizeImage()
的前两行(其余代码允许我调整图像大小。)
public static Bitmap resizeImage(Uri imageUri, int targetWidth, int targetHeight) {
// Convert the image to a byte array
java.net.URI tempUri = new URI(uri.toString());
byte[] imageData = IOUtils.toByteArray(tempUri);
// First decode with inJustDecodeBounds=true to check dimensions
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, targetWidth, targetHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap reducedBitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
Bitmap resizedBitmap = Bitmap.createScaledBitmap(reducedBitmap, targetWidth, targetHeight, false);
return resizedBitmap;
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a
// power of 2 and keeps both height and width larger
// than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
我想我们在同一条船上。我的团队和你一样在这个问题上停留了一段时间。
这似乎是 BitmapFactory.cpp 中的一个问题 (https://android.googlesource.com/platform/frameworks/base.git/+/master/core/jni/android/graphics/BitmapFactory.cpp) Android 7.0 中添加了一些代码并导致了问题的发生。
// Create the codec.
NinePatchPeeker peeker;
std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(streamDeleter.release(), &peeker));
if (!codec.get()) {
return nullObjectReturn("SkAndroidCodec::NewFromStream returned null");
}
我发现 BitmapFactory.decodeStream
方法在我们设置 inJustDecodeBounds=false
之后没有创建位图,但是当我尝试在没有绑定解码的情况下创建位图时。其作品!问题出在 BitmapOptions 上,当我们再次调用 BitmapFactory.decodeStream
时 InputStream 没有更新。
所以我在再次解码之前重置了 InputStream
private Bitmap getBitmapFromAssets(Context context, String fileName, int width, int height) {
AssetManager asset = context.getAssets();
InputStream is;
try {
is = asset.open(fileName);
} catch (IOException e) {
return null;
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
try {
is.reset();
} catch (IOException e) {
return null;
}
options.inSampleSize = calculateInSampleSize(options, width, height);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(is, null, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
看来我们每次重用 InputStream 之前都必须重置它。
我怀疑 android 默认安全配置不允许您使用协议 "http://"(未加密)下载文件。
尝试查找具有 "https://" 协议的图像或文件。查看这是否会导致您的文件加载。否则,设置允许 "http".
的网络安全配置
如何解码 Android 7 中 Asset 目录中的位图?
我的应用 运行 在 Marshmallow 之前的 Android 版本上运行良好。使用 Android 7 它无法从 Asset 目录加载图像。
我的代码:
private Bitmap getImage(String imagename) {
// Log.dd(logger, "AsyncImageLoader: " + ORDNER_IMAGES + imagename);
AssetManager asset = context.getAssets();
InputStream is = null;
try {
is = asset.open(ORDNER_IMAGES + imagename);
} catch (IOException e) {
// Log.de(logger, "image konnte nicht gelesen werden: " + ORDNER_IMAGES + imagename);
return null;
}
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, PW, PH);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
// Lesen des Bitmaps in der optimierten Groesse
return BitmapFactory.decodeStream(is, null, options);
}
结果(只有Android7)BitmapFactory.decodeStream
为空。它可以在较旧的 Android API 中正常工作。
在调试模式下,我看到以下消息:
09-04 10:10:50.384 6274-6610/myapp D/skia: --- SkAndroidCodec::NewFromStream returned null
谁能告诉我原因以及如何更正编码?
编辑:同时我发现,使用 inJustDecodeBounds=true 删除第一个 BitmapFactory.decodeStream 会导致随后使用 inJustDecodeBounds=false 成功 BitmapFactory.decodeStream。不知道原因,也不知道如何替代位图大小的测量。
如果这对任何人有帮助,我在更新以前用于调整图像大小的旧代码时遇到了类似的问题。 我的问题出在从图像文件读取数据的堆栈中。 我使用了 IOUtils.toByteArray(Reader)
,它已被弃用。我切换为直接从 URI 转换为字节数组,现在它运行良好。有关该新方法的示例,请参见下面 resizeImage()
的前两行(其余代码允许我调整图像大小。)
public static Bitmap resizeImage(Uri imageUri, int targetWidth, int targetHeight) {
// Convert the image to a byte array
java.net.URI tempUri = new URI(uri.toString());
byte[] imageData = IOUtils.toByteArray(tempUri);
// First decode with inJustDecodeBounds=true to check dimensions
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, targetWidth, targetHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap reducedBitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
Bitmap resizedBitmap = Bitmap.createScaledBitmap(reducedBitmap, targetWidth, targetHeight, false);
return resizedBitmap;
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a
// power of 2 and keeps both height and width larger
// than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
我想我们在同一条船上。我的团队和你一样在这个问题上停留了一段时间。
这似乎是 BitmapFactory.cpp 中的一个问题 (https://android.googlesource.com/platform/frameworks/base.git/+/master/core/jni/android/graphics/BitmapFactory.cpp) Android 7.0 中添加了一些代码并导致了问题的发生。
// Create the codec.
NinePatchPeeker peeker;
std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(streamDeleter.release(), &peeker));
if (!codec.get()) {
return nullObjectReturn("SkAndroidCodec::NewFromStream returned null");
}
我发现 BitmapFactory.decodeStream
方法在我们设置 inJustDecodeBounds=false
之后没有创建位图,但是当我尝试在没有绑定解码的情况下创建位图时。其作品!问题出在 BitmapOptions 上,当我们再次调用 BitmapFactory.decodeStream
时 InputStream 没有更新。
所以我在再次解码之前重置了 InputStream
private Bitmap getBitmapFromAssets(Context context, String fileName, int width, int height) {
AssetManager asset = context.getAssets();
InputStream is;
try {
is = asset.open(fileName);
} catch (IOException e) {
return null;
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
try {
is.reset();
} catch (IOException e) {
return null;
}
options.inSampleSize = calculateInSampleSize(options, width, height);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(is, null, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
看来我们每次重用 InputStream 之前都必须重置它。
我怀疑 android 默认安全配置不允许您使用协议 "http://"(未加密)下载文件。
尝试查找具有 "https://" 协议的图像或文件。查看这是否会导致您的文件加载。否则,设置允许 "http".
的网络安全配置