Assets的BitmapFactory.decodeStream在Android 7上返回null

时间:2016-09-04 10:42:00

标签: android bitmapfactory android-assets android-7.0-nougat

如何在Android 7中解码资产目录中的位图?

我的应用程序在适用于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);

}

因此(仅限Android 7)BitmapFactory.decodeStream为空。它适用于较旧的Android API。

在调试模式下,我看到以下消息:

  

09-04 10:10:50.384 6274-6610 / myapp D / skia:--- SkAndroidCodec :: NewFromStream返回null

有人可以告诉我原因以及如何更正编码吗?

编辑:同时我发现,使用inJustDecodeBounds = true删除第一个BitmapFactory.decodeStream会导致一个成功的BitmapFactory.decodeStream,然后使用inJustDecodeBounds = false。不知道原因,也不知道如何替换位图大小的测量。

3 个答案:

答案 0 :(得分:10)

我认为我们在同一条船上。我的团队像你一样坚持了这个问题。

这似乎是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。

答案 1 :(得分:1)

我怀疑android默认的安全配置不允许您使用协议“ http://”下载文件(未加密)。

尝试使用“ https://”协议查找图像或文件。查看是否导致文件加载。否则,请设置允许“ http”的网络安全配置。

答案 2 :(得分:0)

如果这对任何人都有帮助,我就会遇到类似问题更新以前用于调整图像大小的旧代码。 我的问题是我正在从图像文件中读取数据的堆栈。我使用了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;
}