Jetpack Compose - 在图像选择器后调整图像大小(ContentResolver 异常?)
Jetpack Compose - Resizing Image after Image PIcker (ContentResolver Exception?)
我只是在用户从我的应用程序启动图像选择器并在本地设备上选择一个图像文件后尝试调整图像大小(处理来自 Dropbox 的远程图像或其他东西将是另一场战斗)而这以前为我工作过,现在我得到这个例外:
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1105296364, result=-1, data=Intent { dat=content://com.android.externalstorage.documents/document/primary:Download/20170307_223207_cropped.jpg flg=0x1 }} to activity {my.app/MainActivity}: java.io.FileNotFoundException: No content provider: /document/primary:Download/20170307_223207_cropped.jpg
这发生在选择器中选择图像之后,因为我是 运行 我的“处理”代码,用于定位图像、调整图像大小并将其复制到应用程序文件夹中的子文件夹。
正如我所说,这有效,但我不确定现在出了什么问题。我已经通过 USB 调试在模拟器和我的 Galaxy S10 上试过了,结果是一样的。该图像在模拟器和我自己的设备上的本地存储“下载”文件夹中。
URI 看起来很奇怪(我的意思是图片只是在本地存储的“下载”文件夹中)但我不是 URI 专家所以我认为它没问题,因为这就是图像选择器 returns。
这是抛出异常的直接代码(具体来说,ImageDecoder.decodeBitmap
调用):
private fun copyFileToAppDataFolder(
context: Context,
imageTempPath: String
): String {
// ensure we are sent at least a non-empty path
if (imageTempPath.isEmpty()) {
return ""
}
val appDataFolder = "${context.dataDir.absolutePath}/images/firearms"
var filename = imageTempPath.substringAfterLast("/", "")
if (filename.isNullOrBlank()) {
filename = imageTempPath.substringAfterLast("%2F", "")
}
// couldn't parse filename from Uri; exit
if (filename.isNullOrBlank()) {
return ""
}
// get a bitmap of the selected image so it can be saved in an outputstream
var selectedImage: Bitmap? = null
selectedImage = if (Build.VERSION.SDK_INT <= 28) {
MediaStore.Images.Media.getBitmap(context.contentResolver, Uri.parse(imageTempPath))
} else {
ImageDecoder.decodeBitmap(ImageDecoder.createSource(context.contentResolver, Uri.parse(imageTempPath)))
}
if (selectedImage == null) {
return ""
}
val destinationImagePath: String = "$appDataFolder/$filename"
val destinationStream = FileOutputStream(destinationImagePath)
selectedImage.compress(Bitmap.CompressFormat.JPEG, 100, destinationStream)
destinationStream.close()
return destinationImagePath
}
上面的函数是从我的 ViewModel 调用的(那个 processFirearmImage
函数只是调用上面的函数),我在其中发送来自图像选择器的结果 URI 以及应用程序上下文:
// this event is fired when the Image Picker returns
is AddEditFirearmEvent.AssignedPicture -> {
val resizedImagePath = ShotTrackerUtility.processFirearmImage(
event.applicationContext, // this is from LocalContext.current in Composable
event.value // result uri from image picker
)
_firearmImageUrl.value = resizedImagePath
}
我不知道,哈哈。我不敢相信这是一件如此困难的事情,但关于这方面的信息似乎很少(尤其是对于 Compose,但即便如此)但我真的不考虑启动图像选择器并将生成的图像调整为那么奇怪。聪明人的任何帮助都会很棒。
有时从编程问题中走出来然后再回来似乎是最好的选择,哈哈。
我今晚回来,几分钟后发现我向 ImageDecoder.createSource
方法发送了不正确的 Uri,这导致了异常。基本上是这样的:
val imageTempPath = theUriReturnedFromImagePicker.path ?: ""
ImageDecoder.decodeBitmap(ImageDecoder.createSource(context.contentResolver, Uri.parse(imageTempPath)))
应该是:
val imageUrl = theUriReturnedFromImagePicker
ImageDecoder.decodeBitmap(ImageDecoder.createSource(context.contentResolver, imageUri))
正如我在 OP 中提到的,这最初是有效的,但我必须稍微更改代码(我发送给各种 methods/classes 的参数主要是)。我还使用 Uri.path
部分来获取所选图像的文件名,所以我忽略了 and/or 对我发送给 ImageDecoder.createSource
的内容感到困惑。
呵呵。也许其他人会像我一样做一些愚蠢的事情,这会有所帮助。
我只是在用户从我的应用程序启动图像选择器并在本地设备上选择一个图像文件后尝试调整图像大小(处理来自 Dropbox 的远程图像或其他东西将是另一场战斗)而这以前为我工作过,现在我得到这个例外:
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1105296364, result=-1, data=Intent { dat=content://com.android.externalstorage.documents/document/primary:Download/20170307_223207_cropped.jpg flg=0x1 }} to activity {my.app/MainActivity}: java.io.FileNotFoundException: No content provider: /document/primary:Download/20170307_223207_cropped.jpg
这发生在选择器中选择图像之后,因为我是 运行 我的“处理”代码,用于定位图像、调整图像大小并将其复制到应用程序文件夹中的子文件夹。
正如我所说,这有效,但我不确定现在出了什么问题。我已经通过 USB 调试在模拟器和我的 Galaxy S10 上试过了,结果是一样的。该图像在模拟器和我自己的设备上的本地存储“下载”文件夹中。
URI 看起来很奇怪(我的意思是图片只是在本地存储的“下载”文件夹中)但我不是 URI 专家所以我认为它没问题,因为这就是图像选择器 returns。
这是抛出异常的直接代码(具体来说,ImageDecoder.decodeBitmap
调用):
private fun copyFileToAppDataFolder(
context: Context,
imageTempPath: String
): String {
// ensure we are sent at least a non-empty path
if (imageTempPath.isEmpty()) {
return ""
}
val appDataFolder = "${context.dataDir.absolutePath}/images/firearms"
var filename = imageTempPath.substringAfterLast("/", "")
if (filename.isNullOrBlank()) {
filename = imageTempPath.substringAfterLast("%2F", "")
}
// couldn't parse filename from Uri; exit
if (filename.isNullOrBlank()) {
return ""
}
// get a bitmap of the selected image so it can be saved in an outputstream
var selectedImage: Bitmap? = null
selectedImage = if (Build.VERSION.SDK_INT <= 28) {
MediaStore.Images.Media.getBitmap(context.contentResolver, Uri.parse(imageTempPath))
} else {
ImageDecoder.decodeBitmap(ImageDecoder.createSource(context.contentResolver, Uri.parse(imageTempPath)))
}
if (selectedImage == null) {
return ""
}
val destinationImagePath: String = "$appDataFolder/$filename"
val destinationStream = FileOutputStream(destinationImagePath)
selectedImage.compress(Bitmap.CompressFormat.JPEG, 100, destinationStream)
destinationStream.close()
return destinationImagePath
}
上面的函数是从我的 ViewModel 调用的(那个 processFirearmImage
函数只是调用上面的函数),我在其中发送来自图像选择器的结果 URI 以及应用程序上下文:
// this event is fired when the Image Picker returns
is AddEditFirearmEvent.AssignedPicture -> {
val resizedImagePath = ShotTrackerUtility.processFirearmImage(
event.applicationContext, // this is from LocalContext.current in Composable
event.value // result uri from image picker
)
_firearmImageUrl.value = resizedImagePath
}
我不知道,哈哈。我不敢相信这是一件如此困难的事情,但关于这方面的信息似乎很少(尤其是对于 Compose,但即便如此)但我真的不考虑启动图像选择器并将生成的图像调整为那么奇怪。聪明人的任何帮助都会很棒。
有时从编程问题中走出来然后再回来似乎是最好的选择,哈哈。
我今晚回来,几分钟后发现我向 ImageDecoder.createSource
方法发送了不正确的 Uri,这导致了异常。基本上是这样的:
val imageTempPath = theUriReturnedFromImagePicker.path ?: ""
ImageDecoder.decodeBitmap(ImageDecoder.createSource(context.contentResolver, Uri.parse(imageTempPath)))
应该是:
val imageUrl = theUriReturnedFromImagePicker
ImageDecoder.decodeBitmap(ImageDecoder.createSource(context.contentResolver, imageUri))
正如我在 OP 中提到的,这最初是有效的,但我必须稍微更改代码(我发送给各种 methods/classes 的参数主要是)。我还使用 Uri.path
部分来获取所选图像的文件名,所以我忽略了 and/or 对我发送给 ImageDecoder.createSource
的内容感到困惑。
呵呵。也许其他人会像我一样做一些愚蠢的事情,这会有所帮助。