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

bug: Camera cannot select picture from Redmi Gallery app #2060

Closed
1 of 4 tasks
jirifranc opened this issue Oct 16, 2019 · 30 comments
Closed
1 of 4 tasks

bug: Camera cannot select picture from Redmi Gallery app #2060

jirifranc opened this issue Oct 16, 2019 · 30 comments

Comments

@jirifranc
Copy link

jirifranc commented Oct 16, 2019

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?

@wanaideed
Copy link

I got the same problem with you.

@alifrontend499
Copy link

The same problem I'm facing

@jirifranc
Copy link
Author

jirifranc commented Nov 6, 2019

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.

@jcesarmobile
Copy link
Member

do you know if it's possible to install the miui gallery in a not xiaomi device?
I've tried in different apps and they work fine.

@jcesarmobile jcesarmobile added the needs reply needs reply from the user label Jan 16, 2020
@jirifranc
Copy link
Author

I haven't tried to install the APK manually but the app doesn't seem to be available at the Play Store. The problem is this Gallery is the default one for Xiaomi/Redmi users and while the hack is simple, it's not a long-term solution as we have to check the source code with each release to make sure it doesn't break.

We ran into this issue immediately after migrating from Cordova but hoped it would be fixed quickly.

@lucasrleandro
Copy link

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?

@tato469
Copy link

tato469 commented Mar 3, 2020

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.

This worked for me, hope we could get "not patched" solution soon :)

@nikosdouvlis
Copy link
Contributor

I can confirm the same issue. Picking an image via the default Xiaomi gallery app results in a "Unable to process image" error. Other gallery apps seem to work, but its a blocker for us since most people with xiaomi devices use the default gallery app.

The patched version and the old cordova plugin work for now

@HamoudaAmine
Copy link

same issue on Xiaomi gallery

@shahidmau
Copy link

I acknowledge the exactly same issue on my Xiaomi phone while selecting photo from the gallery. Here is my adb log.

07-23 17:08:25.212 29040 29040 D Capacitor: Sending plugin error: {"save":false,"callbackId":"49711431","pluginId":"Camera","methodName":"getPhoto","success":false,"error":{"message":"Unable to process image"}}
07-23 17:08:25.215 29040 29040 D Capacitor: App restarted
07-23 17:08:25.216 29040 29040 D Capacitor: App started
07-23 17:08:25.218 29040 29040 D Capacitor/App: Firing change: true

@shahidmau
Copy link

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.

This fix is working for me, thanks.

@ferdiaddawy
Copy link

I also have the same problem, when I upload a file from the gallery (the default xiaomi application) it doesn't work, but when I use the default Google Photos app it works

Note: the device that I use redmi note 8

@manel00
Copy link

manel00 commented Aug 20, 2020

capacitorcam
It fixes also this? cannot run cam on my phone when deploying a capacitor ionic app :S

@aren1989
Copy link
Contributor

aren1989 commented Sep 3, 2020

same issue on Xiaomi gallery

@DoveAz
Copy link

DoveAz commented Sep 10, 2020

same issue

@lucasrleandro
Copy link

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.

Works!!! Thanks @jirifranc 😄

eidng8 added a commit to eidng8/capacitor-plugins that referenced this issue Mar 1, 2021
The problem seems to be the encoded URI. The aforementioned line `String filename = contentUri.getLastPathSegment()` is really the real point of failure.

On a redmi phone (maybe some others too?), the `contentUri` points to something like `content://com.miui.gallery.open/raw/%2Fstorage%2Femulated%2F0%2FDCIM%2FCamera%2FIMG_20210301_082750.jpg`. So you see the encoded part. `getLastPathSegment()` extract the whole `%2Fstorage%2Femulated%2F0%2FDCIM%2FCamera%2FIMG_20210301_082750.jpg` part, then decodes and returns it. Eventually, the follow outFile got a path like `...package..name.../cache/storage/emulated/0/DCIM/Camera/IMG_20210301_082750.jpg`, and you see where it crashes.

I'm not sure if I'm doing it the tidy way, it's the most straightforward way I can think of.
@MilotH2
Copy link

MilotH2 commented Mar 3, 2021

The patch no longer works for me... "@capacitor/android": "^2.4.6",

@koczka
Copy link

koczka commented Apr 15, 2021

The patch no longer works for me... "@capacitor/android": "^2.4.6",

Same here

@jirifranc
Copy link
Author

jirifranc commented Apr 19, 2021

I've updated Capacitor (core, android, and cli) in our app to 2.4.7 and the patch is still working. Please open the file node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/Camera.java and check the line starting with String filename = (there is only one).

You can also replace the line according to @eidng8's fix above which hopefully gets merged into Capacitor 3.

@balazsotakomaiya
Copy link

There are certainly a lot of markets where Xiaomi and Redmi phones are commonplace – so much so in my case, that about 40% of my Android users use one.

I'm really surprised, especially with a PR outstanding, that the Capacitor team isn't merging it, nor commenting on the issue.

@jcesarmobile
Copy link
Member

should be fixed on latest version @capacitor/camera plugin (requires capacitor 3)

if you still face the issue, create a new issue on https://github.com/ionic-team/capacitor-plugins/issues and provide a sample app where it can be reproduced

@czabaj
Copy link

czabaj commented Jul 14, 2021

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.

@AdlerJS
Copy link

AdlerJS commented Jul 19, 2021

@czabaj I also confirmed the same issue on a newer galaxy S10. correctOrientation: false did resolve the issue for me but images are now uploaded the wrong orientation for portrait photos when sending to the server.

@mattmilan-dev
Copy link

mattmilan-dev commented Jul 30, 2021

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.

@jonmbennett
Copy link

jonmbennett commented Jul 31, 2021

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.

Thanks Matt for your temporary fix. Yesterday I had this issue affect my personal Pixel 3 XL too, though now I am having trouble reproducing it. At the least I can confirm it does seem to happen consistently on Samsung phones.

There is a pull request with a fix too: ionic-team/capacitor-plugins@1bde69c

@stevebrowndotco
Copy link

stevebrowndotco commented Aug 9, 2021

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

@Euxiniar
Copy link

 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 ?

@mendo96
Copy link

mendo96 commented Aug 13, 2021

 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 ?

thank you buddy, that did the job !

@AlexJurik
Copy link

AlexJurik commented Nov 23, 2021

After Capacitor upgrade to v2.5.0 mix of workarounds mentioned above helped us with issue on Xiaomi devices.
patch-camera.js file.

const f =
  "node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/Camera.java";
const f2 =
  "node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/camera/ImageUtils.java";

// Workaround for Capacitor camera issue https://github.com/ionic-team/capacitor/issues/2060
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);
  });
});

// Inspired by https://github.com/ionic-team/capacitor/issues/2060#issuecomment-890225244
fs.readFile(f2, "utf8", function (err, data) {
  if (err) {
    return console.log(err);
  }
  var result = data.replace(
    "if (orientation != 0) {\n" +
      "        Matrix matrix = new Matrix();\n" +
      "        matrix.postRotate(orientation);\n" +
      "        exif.resetOrientation();\n" +
      "        return transform(bitmap, matrix);\n" +
      "      } else {",
    " if (orientation != 0) {\n" +
      "      Matrix matrix = new Matrix();\n" +
      "      matrix.postRotate(orientation);\n" +
      "      return transform(bitmap, matrix);\n" +
      "  } else {",
  );

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

@ionitron-bot
Copy link

ionitron-bot bot commented Nov 10, 2022

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Capacitor, please create a new issue and ensure the template is fully filled out.

@ionitron-bot ionitron-bot bot locked and limited conversation to collaborators Nov 10, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests