OpenCV Utils.matToBitmap:如果使用 ImageDecoder.createSource 创建位图,则断言失败 AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0

sha*_*eep 1 android opencv kotlin

我有这个扩展函数是为了从 Uri 创建位图

fun Uri.getBitmap(resolver: ContentResolver): Bitmap {
  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
    @Suppress("DEPRECATION")
    return MediaStore.Images.Media.getBitmap(resolver, this)
  } else {
    val source = ImageDecoder.createSource(resolver, this)
    return ImageDecoder.decodeBitmap(source)
  }
}
Run Code Online (Sandbox Code Playgroud)

在 中Build.VERSION.SDK_INT >= Build.VERSION_CODES.P,所以当我使用时ImageDecoder.createSource我得到这个异常:

CvException [org.opencv.core.CvException: OpenCV(4.1.1) /build/master_pack-android/opencv/modules/java/generator/src/cpp/utils.cpp:38: error: (-215:Assertion failed) AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0
Run Code Online (Sandbox Code Playgroud)

在打开时Build.VERSION.SDK_INT < Build.VERSION_CODES.P,因此使用MediaStore.Images.Media.getBitmap,一切正常。

我缺少什么?

sha*_*eep 5

查看ImageDecoder官方文档,您可以阅读:

默认情况下,由 ImageDecoder 创建的位图(包括位于 Drawable 内部的位图)是不可变的(即 Bitmap#isMutable 返回 false),并且它通常具有 Config Bitmap.Config#HARDWARE。尽管可以使用 setMutableRequired(true) 更改这些属性

因此通过添加来更改扩展功能

setMutableRequired(true)

这样:

fun Uri.getBitmap(resolver: ContentResolver): Bitmap {
  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
    @Suppress("DEPRECATION")
    return MediaStore.Images.Media.getBitmap(resolver, this)
  } else {
    // https://developer.android.com/reference/android/graphics/ImageDecoder
    // CvException [org.opencv.core.CvException: OpenCV(4.1.1) /build/master_pack-android/opencv/modules/java/generator/src/cpp/utils.cpp:38: error: (-215:Assertion failed) AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0
    /*
      By default, a Bitmap created by ImageDecoder (including one that is inside a Drawable)
      will be immutable (i.e. Bitmap#isMutable returns false), and it will typically
      have Config Bitmap.Config#HARDWARE. Although these properties can be changed
      with setMutableRequired(true)
     */
    val source = ImageDecoder.createSource(resolver, this)
    return ImageDecoder.decodeBitmap(source) { decoder, _, _ ->
      decoder.isMutableRequired = true
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

问题就消失了!