Skip to content

TiffConverter.convertJpgTiffFd fails to convert image with a CantOpenFileException from cache. #58

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
pasllani opened this issue Aug 22, 2023 · 5 comments

Comments

@pasllani
Copy link

I have a jetpack compose app with the following logic that triggers to allow user to select an image from the gallery and then copies it to cache:

val context = LocalContext.current
var progressString by remember { mutableStateOf<String?>(null) }
val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.GetContent()) {
    if (it != null) {
        context.contentResolver.openInputStream(it)?.use { input ->
            val file = File(context.cacheDir, "copiedimage.jpg")
            FileOutputStream(file).use { output ->
                val buffer = ByteArray(4 * 1024)
                var read: Int
                while (input.read(buffer).also { read = it } != -1) {
                    output.write(buffer, 0, read)
                }
                output.flush()
            }
            val fd = context.contentResolver.openFileDescriptor(file.toUri(), "r")
            if (fd != null) {
                TiffConverterObject.convertToTiffAndSaveInCache(fd, context.cacheDir) { progress ->
                    progressString = "${progress * 100}%"
                }
            }
        }
    }
}

Button(
    modifier = Modifier
        .width(250.dp)
        .padding(bottom = 8.dp),
    onClick = {
        launcher.launch("image/*")
    }
) {
    Text(text = "Choose image from gallery")
}

I see the copiedimage.jpeg in the cache directory and I've saved it to my desktop and opened it so I know that's being saved correctly:
cache

This is my TiffConverterObject class which uses this library to convert the image to tiff but it keeps crashing returning a CantOpenFileException:

object TiffConverterObject {
    fun convertToTiffAndSaveInCache(inputFD: ParcelFileDescriptor, outputFD: File, progress: (Double) -> Unit) {
        val options = ConverterOptions()
        options.throwExceptions = true
        options.availableMemory = (128 * 1024 * 1024).toLong()
        options.compressionScheme = CompressionScheme.LZW
        options.appendTiff = false

        val file = File.createTempFile("output-temp", ".tiff", outputFD)
        val inputFd = inputFD.fd
        inputFD.close()

        val fd = App.instance.contentResolver.openFileDescriptor(file.toUri(), "rwt")
        if (fd != null) {
            val outputFd = fd.fd
            fd.close()

            val saved = TiffConverter.convertJpgTiffFd(inputFd, outputFd, options) { processedPixels, totalPixels ->
                progress(processedPixels.toDouble() / totalPixels)
            }
            
            println("\n\t-----> Saved: $saved")
        }
    }
}

I've tried all combinations of r,rw,rwt modes on both files as well as .jpg, .jpeg, .tif, and .tiff extensions with no luck. Any help would be greatly appreciated.

@Beyka
Copy link
Owner

Beyka commented Aug 23, 2023

Do you have read storage permission?

@Beyka
Copy link
Owner

Beyka commented Aug 23, 2023

Also any logs with error?

@pasllani
Copy link
Author

Yes I have <uses-permission android::name="android.permission.READ_EXTERNAL_STORAGE" /> in the AndroidManifest file. I added it right above the application information.
I've also tried <uses-permission android::name="android.permission.MANAGE_EXTERNAL_STORAGE" /> and <uses-permission android::name="android.permission.WRITE_EXTERNAL_STORAGE" /> but none of those helped either.

Here are the error logs I'm getting.

FATAL EXCEPTION: main
Process: com.example.pngtotiffconverter, PID: 24601
    java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1606289597, result=-1, data=Intent { dat=content://media/... flg=0x41 clip={image/* video/* {U(content)}} }} to activity {com.example.pngtotiffconverter/com.example.pngtotiffconverter.MainActivity}: org.beyka.tiffbitmapfactory.exceptions.CantOpenFileException: Can't open file with file descriptor 103
    at android.app.ActivityThread.deliverResults(ActivityThread.java:5526)
    at android.app.ActivityThread.handleSendResult(ActivityThread.java:5565)
    at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:67)
    at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8176)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Caused by: org.beyka.tiffbitmapfactory.exceptions.CantOpenFileException: Can't open file with file descriptor 103
    at org.beyka.tiffbitmapfactory.TiffConverter.convertJpgTiffFd(Native Method)
    at com.example.pngtotiffconverter.TiffConverterObject.convertToTiffAndSaveInCache(TiffConverter.kt:37)
    at com.example.pngtotiffconverter.MainActivityKt$Greeting$galleryLauncher$1.invoke(MainActivity.kt:84)
    at com.example.pngtotiffconverter.MainActivityKt$Greeting$galleryLauncher$1.invoke(MainActivity.kt:70)
    at androidx.activity.compose.ActivityResultRegistryKt$rememberLauncherForActivityResult$1.invoke$lambda-0(ActivityResultRegistry.kt:106)
    at androidx.activity.compose.ActivityResultRegistryKt$rememberLauncherForActivityResult$1.$r8$lambda$dCDOHypJPJiF_gC4kcw2C1QNWFU(Unknown Source:0)
    at androidx.activity.compose.ActivityResultRegistryKt$rememberLauncherForActivityResult$1$$ExternalSyntheticLambda0.onActivityResult(Unknown Source:2)
    at androidx.activity.result.ActivityResultRegistry.doDispatch(ActivityResultRegistry.java:418)
    at androidx.activity.result.ActivityResultRegistry.dispatchResult(ActivityResultRegistry.java:375)
    at androidx.activity.ComponentActivity.onActivityResult(ComponentActivity.java:777)
    at android.app.Activity.dispatchActivityResult(Activity.java:8943)
    at android.app.ActivityThread.deliverResults(ActivityThread.java:5519)
    at android.app.ActivityThread.handleSendResult(ActivityThread.java:5565) 
    at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:67) 
    at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loopOnce(Looper.java:205) 
    at android.os.Looper.loop(Looper.java:294) 
    at android.app.ActivityThread.main(ActivityThread.java:8176) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971) 

@pasllani
Copy link
Author

These are the crash logs I get when I remove the close() functions for the inputFD and outputFD respectively. I think these are more accurate than the ones I've posted above. Both methods crash within TiffBitmapFactory.

fdsan: failed to exchange ownership of file descriptor: fd 101 is owned by ParcelFileDescriptor 0xce5ad5, was expected to be unowned
Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 29897 (totiffconverter), pid 29897 (totiffconverter)
Cmdline: com.example.pngtotiffconverter
pid: 29897, tid: 29897, name: totiffconverter  >>> com.example.pngtotiffconverter <<<
      #02 pc 00000000000200b4  /data/app/~~MVx-QyN8xxbS8x42DsS4LQ==/com.example.pngtotiffconverter-DsfEtC9kGM2_p0PKw01eSQ==/base.apk!libtiffconverter.so (offset 0xd5000) (JpgToTiffConverter::convert()+232) (BuildId: df448798ff7fc0449147e9e7908310cbf5fdb9fe)
      #03 pc 000000000001bd64  /data/app/~~MVx-QyN8xxbS8x42DsS4LQ==/com.example.pngtotiffconverter-DsfEtC9kGM2_p0PKw01eSQ==/base.apk!libtiffconverter.so (offset 0xd5000) (Java_org_beyka_tiffbitmapfactory_TiffConverter_convertJpgTiffFd+100) (BuildId: df448798ff7fc0449147e9e7908310cbf5fdb9fe)
      #09 pc 0000000000005784  /data/data/com.example.pngtotiffconverter/code_cache/.overlay/base.apk/classes3.dex (com.example.pngtotiffconverter.TiffConverterObject.convertToTiffAndSaveInCache+0)
      #14 pc 00000000000048f8  /data/data/com.example.pngtotiffconverter/code_cache/.overlay/base.apk/classes3.dex (com.example.pngtotiffconverter.MainActivityKt$Greeting$galleryLauncher$1.invoke+0)
      #19 pc 00000000000048b0  /data/data/com.example.pngtotiffconverter/code_cache/.overlay/base.apk/classes3.dex (com.example.pngtotiffconverter.MainActivityKt$Greeting$galleryLauncher$1.invoke+0)
      #24 pc 000000000017e3dc  /data/data/com.example.pngtotiffconverter/code_cache/.overlay/base.apk/classes.dex (androidx.activity.compose.ActivityResultRegistryKt$rememberLauncherForActivityResult$1.invoke$lambda-0+0)
      #29 pc 000000000017e394  /data/data/com.example.pngtotiffconverter/code_cache/.overlay/base.apk/classes.dex (androidx.activity.compose.ActivityResultRegistryKt$rememberLauncherForActivityResult$1.$r8$lambda$dCDOHypJPJiF_gC4kcw2C1QNWFU+0)
     #34 pc 000000000017e2bc  /data/data/com.example.pngtotiffconverter/code_cache/.overlay/base.apk/classes.dex (androidx.activity.compose.ActivityResultRegistryKt$rememberLauncherForActivityResult$1$$ExternalSyntheticLambda0.onActivityResult+0)
      #39 pc 00000000001801b4  /data/data/com.example.pngtotiffconverter/code_cache/.overlay/base.apk/classes.dex (androidx.activity.result.ActivityResultRegistry.doDispatch+0)
      #44 pc 000000000017ffd0  /data/data/com.example.pngtotiffconverter/code_cache/.overlay/base.apk/classes.dex (androidx.activity.result.ActivityResultRegistry.dispatchResult+0)
      #49 pc 000000000017ccd0  /data/data/com.example.pngtotiffconverter/code_cache/.overlay/base.apk/classes.dex (androidx.activity.ComponentActivity.onActivityResult+0)

@sonique6784
Copy link

if you get want to use File descriptor from ParcelFileDescriptor, you first need to detach the file descriptor:

int fd = parcheFileDescriptor.detachFd(); // return the fileDescriptor int that can be used in native code like saveBitmap()

// use *fd* to call saveBitmap()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants