Skip to content
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

getting FileNotFoundException when passed content uri as destination #668

Open
ImRohithBajjuri opened this issue Jun 17, 2020 · 13 comments
Open

Comments

@ImRohithBajjuri
Copy link

ImRohithBajjuri commented Jun 17, 2020

java.io.FileNotFoundException: /external/images/media/66991: open failed: ENOENT (No such file or directory)
at libcore.io.IoBridge.open(IoBridge.java:496)
at java.io.FileOutputStream.(FileOutputStream.java:235)
at java.io.FileOutputStream.(FileOutputStream.java:186)
at com.yalantis.ucrop.task.BitmapLoadTask.copyFile(BitmapLoadTask.java:177)
at com.yalantis.ucrop.task.BitmapLoadTask.processInputUri(BitmapLoadTask.java:155)
at com.yalantis.ucrop.task.BitmapLoadTask.doInBackground(BitmapLoadTask.java:85)
at com.yalantis.ucrop.task.BitmapLoadTask.doInBackground(BitmapLoadTask.java:36)
at android.os.AsyncTask$3.call(AsyncTask.java:378)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
at libcore.io.Linux.open(Native Method)
at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:252)
at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7296)
at libcore.io.IoBridge.open(IoBridge.java:482)
at java.io.FileOutputStream.(FileOutputStream.java:235) 
at java.io.FileOutputStream.(FileOutputStream.java:186) 
at com.yalantis.ucrop.task.BitmapLoadTask.copyFile(BitmapLoadTask.java:177) 
at com.yalantis.ucrop.task.BitmapLoadTask.processInputUri(BitmapLoadTask.java:155) 
at com.yalantis.ucrop.task.BitmapLoadTask.doInBackground(BitmapLoadTask.java:85) 
at com.yalantis.ucrop.task.BitmapLoadTask.doInBackground(BitmapLoadTask.java:36) 
at android.os.AsyncTask$3.call(AsyncTask.java:378) 
at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
at java.lang.Thread.run(Thread.java:919) 

@priyanka-poplify
Copy link

@ImRohithBajjuri did you find any solution of this ? I am getting the same issue.

@ImRohithBajjuri
Copy link
Author

ImRohithBajjuri commented Aug 9, 2020 via email

@rcd27
Copy link

rcd27 commented Aug 15, 2020

The same problem to me, working on it. f I get something, I'll let you know.

@rcd27
Copy link

rcd27 commented Aug 15, 2020

Seems like the problem in destination URI. I've used the code from sample: SampleActivity:233 to create destinationUri :

val destinationUri = Uri.fromFile(File(getCacheDir(), "balbla.jpg")

UCrop.of(sourceUri, destinationUri)...

@ImRohithBajjuri
Copy link
Author

Seems like the problem in destination URI. I've used the code from sample: SampleActivity:233 to create destinationUri :

val destinationUri = Uri.fromFile(File(getCacheDir(), "balbla.jpg")

UCrop.of(sourceUri, destinationUri)...

@ImRohithBajjuri
Copy link
Author

passing content uri as destination gave the error, after converting it to file uri did work. But in the latest version passing the converted file uri is also giving the error. Is it because of the scoped storage thing?

@rcd27
Copy link

rcd27 commented Aug 15, 2020

Probably, not sure.

@fabio-blanco
Copy link

fabio-blanco commented Dec 30, 2020

@ImRohithBajjuri Yes, it is. I'm with the same problem here.

Steps to reproduce the error on Android 29+:

  1. Code an app that uses SAF picker to let the user choose destination for a file:
Intent createDocumentIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);

createDocumentIntent.addCategory(Intent.CATEGORY_OPENABLE);
createDocumentIntent.setType("image/jpeg");
createDocumentIntent.putExtra(Intent.EXTRA_TITLE, createCroppedPictureNameFrom(cameraFile.getName()));

startActivityForResult(createDocumentIntent, EXTERNAL_IMAGE_FILE_REQUEST_CODE);
  1. In the onActivityResult method, call uCrop:
        if(requestCode == EXTERNAL_IMAGE_FILE_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                if (data != null) {
                    //Saving in the chosen external directory
                    Uri destinationUri = data.getData();
                    Uri sourceUri = Uri.fromFile(cameraFile);

                    UCrop.of(sourceUri, destinationUri)
                         .withMaxResultSize(1024, 1024)
                         .start(this);
                }
            } else if (resultCode == RESULT_CANCELED) {
                //Explain to user that no file will be saved (maybe do this once and save state)
            }
        }
  1. Now just implement an if clause in the onActivityResult to receive the croped URI (that will be corrupted):
         else if(requestCode == UCrop.REQUEST_CROP) {
            if (resultCode == RESULT_OK) {
                final Uri resultUri = UCrop.getOutput(data);
                ImageUtils.loadImage(resultUri, mImageView, this);
            } else if (resultCode == UCrop.RESULT_ERROR) {
                final Throwable cropError = UCrop.getError(data);
                Log.d(LOG_TAG, "Cropping error", cropError);
            }
            if (cameraFile != null) {
                //Tmp file is no more required
                cameraFile.delete();
            }
        }
  1. Execute the app
  2. Note that, if you debug, the destinationUri from step 2 will now look like this:
    content://com.android.externalstorage.documents/document/19E8-1F1C%3Ateste%2FuCrop_img_uCrop_img_2020-12-29-11-55-033800606608213623243.jpg
  3. The uCrop widget will open with your image but when you click in the ok button the uCrop will crash and the resultUri from step 3 will be currupted. You will be able to find a Stacktrace like this on the Logcat console:
2020-12-30 00:13:24.345 18821-18821/br.com.fbsoftware.at.samples.ucroptest W/Glide: Load failed for file:///document/19E8-1F1C%3Ateste/uCrop_img_uCrop_img_2020-12-29-11-55-033800606608213623243.jpg with size [984x1488]
    class com.bumptech.glide.load.engine.GlideException: Failed to load resource
    There were 3 causes:
    java.io.FileNotFoundException(/document/19E8-1F1C:teste/uCrop_img_uCrop_img_2020-12-29-11-55-033800606608213623243.jpg: open failed: ENOENT (No such file or directory))
    java.io.FileNotFoundException(open failed: ENOENT (No such file or directory))
    java.io.FileNotFoundException(open failed: ENOENT (No such file or directory))
     call GlideException#logRootCauses(String) for more detail
      Cause (1 of 4): class com.bumptech.glide.load.engine.GlideException: Fetching data failed, class java.io.InputStream, LOCAL
    There was 1 cause:
    java.io.FileNotFoundException(/document/19E8-1F1C:teste/uCrop_img_uCrop_img_2020-12-29-11-55-033800606608213623243.jpg: open failed: ENOENT (No such file or directory))
     call GlideException#logRootCauses(String) for more detail
        Cause (1 of 1): class java.io.FileNotFoundException: /document/19E8-1F1C:teste/uCrop_img_uCrop_img_2020-12-29-11-55-033800606608213623243.jpg: open failed: ENOENT (No such file or directory)
      Cause (2 of 4): class com.bumptech.glide.load.engine.GlideException: Fetching data failed, class android.os.ParcelFileDescriptor, LOCAL
    There was 1 cause:
    java.io.FileNotFoundException(open failed: ENOENT (No such file or directory))
     call GlideException#logRootCauses(String) for more detail
        Cause (1 of 1): class java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)
      Cause (3 of 4): class com.bumptech.glide.load.engine.GlideException: Fetching data failed, class android.content.res.AssetFileDescriptor, LOCAL
    There was 1 cause:
    java.io.FileNotFoundException(open failed: ENOENT (No such file or directory))
     call GlideException#logRootCauses(String) for more detail
        Cause (1 of 1): class java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)
      Cause (4 of 4): class com.bumptech.glide.load.engine.GlideException: Failed LoadPath{HierarchicalUri->Object->Drawable}, LOCAL
        Cause (1 of 2): class com.bumptech.glide.load.engine.GlideException: Failed DecodePath{HierarchicalUri->Drawable->Drawable}
        Cause (2 of 2): class com.bumptech.glide.load.engine.GlideException: Failed DecodePath{HierarchicalUri->Bitmap->Drawable}
2020-12-30 00:13:24.352 18821-18821/br.com.fbsoftware.at.samples.ucroptest I/Glide: Root cause (1 of 3)
    java.io.FileNotFoundException: /document/19E8-1F1C:teste/uCrop_img_uCrop_img_2020-12-29-11-55-033800606608213623243.jpg: open failed: ENOENT (No such file or directory)

@fabio-blanco
Copy link

fabio-blanco commented Dec 30, 2020

Debugging uCrop code, I can see that the problem starts on the onPostExecute method of the BitmapLoadTask class:

    @Override
    protected void onPostExecute(@NonNull BitmapWorkerResult result) {
        if (result.mBitmapWorkerException == null) {
            mBitmapLoadCallback.onBitmapLoaded(result.mBitmapResult, result.mExifInfo, mInputUri.getPath(), (mOutputUri == null) ? null : mOutputUri.getPath());
        } else {
            mBitmapLoadCallback.onFailure(result.mBitmapWorkerException);
        }
    }

When doing this mOutputUri.getPath() the first part of the 'content://...' path gets lost. And then on the onPostExecute of the BitmapCropTask class the uCrop lib tries to build a new Uri from this corrupted path:

    @Override
    protected void onPostExecute(@Nullable Throwable t) {
        if (mCropCallback != null) {
            if (t == null) {
                Uri uri = Uri.fromFile(new File(mImageOutputPath));
                mCropCallback.onBitmapCropped(uri, cropOffsetX, cropOffsetY, mCroppedImageWidth, mCroppedImageHeight);
            } else {
                mCropCallback.onCropFailure(t);
            }
        }
    }

Inside the copyFile method of the BitmapLoadTask class we have the same problem:

outputStream = new FileOutputStream(new File(outputUri.getPath()));

So I think it is really a bug. When using SAF the uCrop should pass along the Uri and not try to rebuild one with the path string.

I've forked the repository and I will try to make some adjusts in order to try to correct this. I can share this work or discuss it better if some uCrop developer thinks it can be useful but as I'm new to this project source I may be missing something.

@fabio-blanco
Copy link

I have made the corrections and opened a pull request #732.
Now we will have to sit and wait for the Yalantis developers to see and review my pull request.
But if you are desperate for the solution, pulling your hair out of your own head, read the temporary solution below:

For the "I wanna be an alpha tester" kind of person or if you're desperate or just curious

If someone with the same error wants to try this in advance as an alpha tester and maybe help validate my work, you can do this by pointing your source code dependence to my pull request by changing this line of your build.gradle file:

implementation 'com.github.yalantis:ucrop:2.2.6-native'

to this:

implementation 'com.github.yalantis:ucrop:PR732-SNAPSHOT'

Success or failure reports will be appreciated. Thanks in advance! 😄 👍

@codespair
Copy link

codespair commented Feb 1, 2021

implementation 'com.github.yalantis:ucrop:PR732-SNAPSHOT'

This works perfectly indeed. It fixes the issue. I have the same issue with 'content:' files, this fixes it, should be merged.

I have created a simple example with the fix here -> https://github.com/codespair/CameraImageUCropTutorial

@VToegel
Copy link

VToegel commented Apr 1, 2021

I have made the corrections and opened a pull request #732.
Now we will have to sit and wait for the Yalantis developers to see and review my pull request.
But if you are desperate for the solution, pulling your hair out of your own head, read the temporary solution below:

For the "I wanna be an alpha tester" kind of person or if you're desperate or just curious

If someone with the same error wants to try this in advance as an alpha tester and maybe help validate my work, you can do this by pointing your source code dependence to my pull request by changing this line of your build.gradle file:

implementation 'com.github.yalantis:ucrop:2.2.6-native'

to this:

implementation 'com.github.yalantis:ucrop:PR732-SNAPSHOT'

Success or failure reports will be appreciated. Thanks in advance! 😄 👍

Hi Fabio,

your pull request works perfectly. Thank you

@egeysn
Copy link

egeysn commented Mar 14, 2022

I faced the same problem. The pictures I took with the camera were giving this error on Android 11 and above.
I change my root destination.
String root = Environment.getExternalStorageDirectory().toString(); to
String root = Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES).toString(); and my problem solved.
My full code:
``
public void onPictureTaken(@nonnull PictureResult result) {
super.onPictureTaken(result);
String root = Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES).toString();
File myDir = new File(root + "/" + getString(R.string.app_name) + "/posts");
if (!myDir.exists()) {
myDir.mkdirs();
}

            Random generator = new Random();
            int n = 10000;
            n = generator.nextInt(n);
            String fname = "Image-" + n + ".jpg";
            File file = new File(myDir, fname);
            int finalN = n;
            result.toFile(file, callback -> {
                String name = "Image-" + finalN + "-modified.jpg";
                File f = new File(myDir, name);
                UCrop.Options options = new UCrop.Options();
                options.setToolbarTitle(getString(R.string.crop_the_im));
                options.setRootViewBackgroundColor(ContextCompat.getColor(CameraActivity.this, R.color.white));
                options.setToolbarColor(ContextCompat.getColor(CameraActivity.this, R.color.white));
                options.setToolbarWidgetColor(ContextCompat.getColor(CameraActivity.this, R.color.white));
                options.setActiveControlsWidgetColor(ContextCompat.getColor(CameraActivity.this, R.color.green));
                options.setToolbarCancelDrawable(R.drawable.ic_close_red);
                options.setToolbarColor(ContextCompat.getColor(CameraActivity.this, R.color.white));
                options.setToolbarCropDrawable(R.drawable.ic_next);
                options.setStatusBarColor(ContextCompat.getColor(CameraActivity.this, R.color.black));
                options.setToolbarWidgetColor(ContextCompat.getColor(CameraActivity.this, R.color.black));
                UCrop.of(Uri.fromFile(file), Uri.fromFile(f))
                        .withAspectRatio(120, 120)
                        .withOptions(options)
                        .start(CameraActivity.this);
            });
        }

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

7 participants