cordova-plugin-camera icon indicating copy to clipboard operation
cordova-plugin-camera copied to clipboard

camera.getPicture() with FILE_URI destination returns invalid/unexpected image URI

Open wencywww opened this issue 3 years ago • 13 comments

Bug Report

Problem

What is expected to happen?

camera.getPicture() to return a valid file_URI in the form of content://media/external/images/media/2 when Camera.DestinationType = FILE_URI

What does actually happen?

the returned value is something like: file///data/user/0/com.tld.appname/cache/1642011143203.jpg and this seems to be an unreacheable url for the webview (can not render the picture). Moreover, searching through the filesystem i can't see such a file. There is no problems when the Camera.DestinationType = DATA_URL, however it is undesired due to possible memory problems

Information

Command or Code

navigator.camera.getPicture(onSuccess, onFail, { quality: 50, destinationType: Camera.DestinationType.FILE_URI });

Environment, Platform, Device

Developing on Windows 10, the result is with Android 7.0 phone

Version information

[email protected] [email protected] [email protected] Android SDK Platform 11.0 / API Level 30 Gradle 7.3.3

Checklist

  • I searched for existing GitHub issues

  • I updated all Cordova tooling to most recent version

  • [ ] I included all the necessary information above

wencywww avatar Jan 12 '22 18:01 wencywww

I have the same issue. Did you found some solution?

cmarian5 avatar Feb 13 '22 20:02 cmarian5

I don't think so :( Asked within StackOverflow here https://stackoverflow.com/questions/70693557/camera-getpicture-returns-an-unexpected-file-uri-on-android but with little success. One suggested using this: <preference name="AndroidInsecureFileModeEnabled" value="true" /> but the resulting url is still like file//

I have the same issue. Did you found some solution?

wencywww avatar Feb 14 '22 08:02 wencywww

Same issue

kirkHawksworth avatar Feb 18 '22 15:02 kirkHawksworth

For me <preference name="AndroidInsecureFileModeEnabled" value="true" /> worked fine. Meaning I could obtain a valid url of the image to add it in a html img tag.

cmarian5 avatar Feb 18 '22 15:02 cmarian5

@cmarian5 do you still receive the image url like: file:///data/user/0/package.name/cache/1645202153127.jpg

I have that preference enabled in my config.xml, added & removed Android etc. and still get the same issue

kirkHawksworth avatar Feb 18 '22 16:02 kirkHawksworth

With that preference in config.xml I get it like this <img onclick="image(this)" class="poze1" src="file:///data/user/0/com.example.hello/cache/1645205836634.jpg">

In this case the image is displayed correctly. Also in your case should work.

cmarian5 avatar Feb 18 '22 17:02 cmarian5

This issue is related to the scoped storage of Android 11.

(A) use DATA_URL && low targetHeight & targetWidth values (<3000)

The latest entry-level smartphones have large pixels, so an "out of memory" error occurs during conversion to base64.

navigator.camera.getPicture(onSuccess, onFail, { quality: 100, destinationType: Camera.DestinationType.DATA_URL, targetHeight:1000, targetWidth:1000});

(B) Save the image to photoalbum --> read the image

navigator.camera.getPicture(onSuccess, onFail, { quality: 100, destinationType: Camera.DestinationType.FILE_URI, saveToPhotoAlbum : true, correctOrientation:false });

Although "cordova-pluggin-camera" can not access the 'cache' folder, but it can write it on photoalbum folder.

cf) src/android/CameraLauncher.java

line 226 : getCacheDir() --> FAIL

private String getTempDirectoryPath() {
    File cache = cordova.getActivity().**getCacheDir()**;
    // Create the cache directory if it doesn't exist
    cache.mkdirs();
    return cache.getAbsolutePath();
}

line 532 : galleryUri.toString() --> SUCCESS

    else if (destType == FILE_URI) {
        // If all this is true we shouldn't compress the image.
        if (this.targetHeight == -1 && this.targetWidth == -1 && this.mQuality == 100 &&
                !this.correctOrientation) {

            // If we saved the uncompressed photo to the album, we can just
            // return the URI we already created
            if (this.saveToPhotoAlbum) {
                this.callbackContext.success(**galleryUri.toString()**);

This FILE URI can be read by the following code.

function onSuccess(imageURI) { function gotFile(fileEntry) { fileEntry.file(function(file) {

    var reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onloadend = function(e) {
        var content = this.result;
        console.log(typeof content);  // --> **BASE64 IMAGE**
        };
        reader.readAsText(file);
    });}

window.resolveLocalFileSystemURL(imageURI, gotFile, function () { console.log("resolveLocalFileSystemURL Error"); }); }

whria78 avatar Mar 27 '22 10:03 whria78

if (this.targetHeight == -1 && this.targetWidth == -1 && destType == FILE_URI && !this.correctOrientation && getMimetypeForEncodingType().equalsIgnoreCase(mimeTypeOfGalleryFile)) { this.callbackContext.success(finalLocation); }

&& getMimetypeForEncodingType().equalsIgnoreCase(mimeTypeOfGalleryFile)) 把这个判断去掉 强制走if条件

Barry1990 avatar Jun 23 '22 06:06 Barry1990

Cordova Android 10.0.0 Released! - Apache Cordova In "cordova-android 10.0.0", WebViewAssetLoader has been added and file:// access is no longer possible.

As described in the Release document, to keep the previous behavior, add the following to config.xml

<preference name="AndroidInsecureFileModeEnabled" value="true" />

URLs must be converted using cordova-plugin-file in order to be accessed correctly by WebViewAssetLoader.

window.resolveLocalFileSystemURL(imageUri, (fileEntry) => {
  const fileEntryURL = fileEntry.toURL();
  appState.imageUri = fileEntryURL;
  document.getElementById("get-picture-result").src = fileEntryURL;
},
(err) => {
  console.error(err);
});

I think you should modify README.md.

anaura avatar Oct 03 '22 17:10 anaura

so I have to call window.resolveLocalFileSystemURL(imageUri, (fileEntry) => { const fileEntryURL = fileEntry.toURL(); appState.imageUri = fileEntryURL; document.getElementById("get-picture-result").src = fileEntryURL; }, (err) => { console.error(err); }); every time I have to display a file uri?

dreamslabmg avatar Jul 10 '23 21:07 dreamslabmg

same issue here. Need a content URI to get the proper filename. Is there a way

  1. to get a content uri instead of file uri from the camera plugin
  2. if not, is there a way to convert a file uri into a content uri?

drogerie21 avatar Jan 23 '24 14:01 drogerie21

I'm facing same issue with Android 13 and [email protected] using camera.getPicture with DestinationType.FILE_URI

  1. workaround that seem to work for me is to move on using instead a DestinationType.DATA_URL:
function onPhotoURISuccess(imgUri) {
    console.log(imgUri); // on Android 13 it's a uri without file:// and resolveLocalFileSystemURL will fail.

    // in case of resolveLocalFileSystemURL fail I'll try to manage imgUri as imgData and store Base64 encoded data to a new File.
    window.resolveLocalFileSystemURL(imgUri, function success(fileEntry) {
        console.log(JSON.stringify(fileEntry));
        console.log("got file: " + fileEntry.fullPath);
        return fileEntry;
    }, function (error) {
        console.log(error.code); // on Android 13 it's Error Code 5
        var tmp = createNewFileEntry(imgUri);
        return tmp;
    });
}
  1. root cause

debugging the cordova-plugin-camera at CameraLauncher.java the processResultFromGallery will return finalLocation the "imgUri" that look like /storage/emulated/0/Pictures/IMG_20240123_164955.jpg (it's an example of a selection from an emulator gallery) that it's later not resolvable from resolveLocalFileSystemURL

see also #866

mattocchi avatar Jan 23 '24 23:01 mattocchi

same issue

hirushacooray avatar Feb 29 '24 08:02 hirushacooray