capacitor: bug: Camera cannot select picture from Redmi Gallery app

Bug Report

Capacitor Version

npx cap doctor output: Installed Dependencies: @capacitor/ios not installed @capacitor/core 1.2.1 @capacitor/cli 1.2.1 @capacitor/android 1.2.1

Affected Platform(s)

  • Android
  • iOS
  • Electron
  • Web

Current Behavior

Using the Camera plugin on Android Redmi phones, when a picture is selected in the Gallery app, this error is thrown: Unable to process image. It doesn’t manifest itself with other apps (e.g. File Manager) and also there was no problem with the Cordova plugin which we used before upgrading to Capacitor.

Expected Behavior

Users are able to use the default Gallery app to select their pictures on Redmi phones.

Sample Code or Sample Application Repo

This is the config we use: const options: CameraOptions = { quality: 30, resultType: CameraResultType.Uri, allowEditing: false, source: CameraSource.Photos, };

Reproduction Steps

Configure the Camera plugin to return a Uri and use the option to select a picture from gallery instead of taking a new photo.

Other Technical Details

  • Phone: Redmi 6A/Redmi Note 7
  • Android version: 8.1/9
  • MIUI version: 10.3.6/10.3.6

Other Information

I suspect the bug concerns other MIUI devices, such as Xiaomi phones. I managed to track down the problem to saveTemporaryImage method in Camera.java. contentUri.getlastPathSegment tries to select the filename and a copy of the file is created in the cacheDir.

However, contentUri from the Gallery app has this format: content://com.miui.gallery.open/raw/%2Fstorage%2Femulated%2F0%2FDCIM%2FCamera%2FIMG_20191013_191506.jpg

while the other apps return unescaped slashes in the path, e.g. content://com.mi.android.globalFileexplorer.myprovider/external_files/DCIM/Camera/IMG_20191013_191506.jpg

I created an easy solution for our app (using a random filename) but this is probably a symptom of a more serious issue and I don’t know what the proper fix would be. Is it enough to just unescape the path?

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 5
  • Comments: 30 (4 by maintainers)

Commits related to this issue

Most upvoted comments

As no one from the Capacitor team has replied, I’ll at least give you a workaround.

  1. Created a file called named patch-camera.js in the project root folder with this content:
const fs = require("fs");
const f =
  "node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/Camera.java";

fs.readFile(f, "utf8", function(err, data) {
  if (err) {
    return console.log(err);
  }
  var result = data.replace(
    "String filename = contentUri.getLastPathSegment()",
    'String filename = "file"'
  );

  fs.writeFile(f, result, "utf8", function(err) {
    if (err) return console.log(err);
  });
});

As you can see, this fix is very fragile as it relies on the specific node_modules path and Java source code. This ensures that a timestamp is used for the file name instead of the broken name from the Gallery app.

  1. Add the postinstall script to your package.json to patch the Capacitor source code.
 "scripts": {
    "build": "ng build --prod && npx cap sync",
    "postinstall": "node patch-camera.js"

This automatically runs the fix after npm install and works perfectly with @capacitor/android": “^1.2.1”. We haven’t updated to 1.3 yet.

On Samsung 21 I get the error: (via logcat in android studio)

2021-08-09 19:50:40.705 32410-32410/com.ionicframework.chalk208279 E/Capacitor/Console: File: http://192.168.0.12:8100/vendor.js - Line 46093 - Msg: ERROR Error: Uncaught (in promise): Error: Unable to process image
    Error: Unable to process image
        at Object.cap.fromNative (http://192.168.0.12:8100/:429:32)
        at <anonymous>:1:18

This happens when (as a user) I attempt to add an image from the stock gallery.

WORKS with camera

I encountered this issue on an old Samsung Galaxy J3, the problem persisted even after an upgrade to capacitor@3. I downgraded the capacitor back to v2, as I have a problem debug the native code of the plugins in v3, and found out the exception is thrown in code that corrects the orientation of the image.

Solution

By disabling rotation with correctOrientation: false I resolved my issue.

Further investigation

I got a

java.io.FileNotFoundException: /-1/1/content:/media/external/images/media/376/ORIGINAL/NONE/image/jpeg/1205681957 (No such file or directory)

from the prepareBitmap function

by digging deeper, it turned out, that the failing code was imageUri.getPath(), a quick search revealed a StackOverflow thread where this comment notes

The Uri that you are attempting to open is content://document/image:26171. You need to access it with a ContentProvider.

I’m a newbie in Android development, but it seems that the Samsung Gallery does not provide a regular file URI, thus the Camera plugin must use ContentProvider to handle the URI.

Additional informations

I checked the capacitor v3 Camera plugin source code and it seems to me that it is exposed to the same issue by using Uri.getPath(), but I did not test it, as I have a problem debug the native code of capacitor v3. Also, during the debug of capacitor v2, I realized, that I completely miss the Gradle variable

androidxExifInterfaceVersion = '1.2.0'

which might be necessary for the Camera plugin to work correctly, but on Capacitor v2, the Camera plugin worked even without this variable.

We’ve also had a few users also state that image uploading is not working across the Samsung device list only; Pixels seem to be unaffected by this. Not to repeat what @czabaj has said, but I’m also thinking it’s to do with Samsung’s photo gallery returning incorrectly, although the specific error i get is /external/images/media/389: open failed: ENOENT (No such file or directory). As stated, correctOrientation: false does solve the issue but leaves the returned image rotated 90 degrees anticlockwise. This has occurred after our apps migration to capacitor 3 and was not a problem on v2.

As a temporary work around, you can turn the lines here in the plugin (android/capacitor-camera/src/main/java/com.capacitorjs.plugins.camera/ImageUtils) to the following:

 if (orientation != 0) {
      Matrix matrix = new Matrix();
      matrix.postRotate(orientation);
      return transform(bitmap, matrix);
  } else {

and rebuilding should allow it to work for now.

 if (orientation != 0) {
      Matrix matrix = new Matrix();
      matrix.postRotate(orientation);
      return transform(bitmap, matrix);
  } else {

This fix works for me with a Xiaomi. Does anyone knows if the Capacitor team is on it ?

Hello, I am facing this same problem with xiaomi. Our business really needs the camera and our customers are complaining. I think I will try this workaround, but is there any prediction of a definitive solution?