Cannot save pictures taken using CameraX

443 views
Skip to first unread message

sanjuro ogawa

unread,
Sep 4, 2023, 4:42:21 AM9/4/23
to Android CameraX Discussion Group
I am using the following:

* Android Studio Giraffe 2022.3.1 Patch 1
* CameraX 1.2.3
* Language: Java
* API 30 (R; Android 11) - physical device - fails
* API 30 (R; Android 11) - emulator        - fails
* API 29 (Q; Android 10) - emulator        - fails
* API 24 (Nougat; Android 7) - emulator    - succeeds
(but images are rotated -90 deg)

When I use CameraX to record a video to the "Movies" directory, everything works fine.

In the exact same program, when I use CameraX to take a picture with the goal of saving the picture to the "Pictures" directory, it fails with the exception output shown below.

Even if I set the program up to save the picture to the "Movies" directory, the same type of error occurs.

Oh, also, the "*.tmp" file does not exist in the directory.

exception = {ImageCaptureException@17788} "androidx.camera.core.ImageCaptureException: Failed to write temp file"
 mImageCaptureError = 1
 backtrace = {Object[11]@17791}
 cause = {FileNotFoundException@17792} "java.io.FileNotFoundException: /storage/emulated/0/Pictures/CameraX59730b5a-e132-4c5a-9df3-e40af76643ac.tmp: open failed: EPERM (Operation not permitted)"
 detailMessage = "Failed to write temp file"
 stackTrace = {StackTraceElement[10]@17797}
 suppressedExceptions = {Collections$EmptyList@17795}  size = 0
 shadow$_klass_ = {Class@17307} "class androidx.camera.core.ImageCaptureException"
 shadow$_monitor_ = 0
 
The API I am using for taking pictures is as follows:

androidx.camera.core.ImageCapture
public void takePicture

Just for completeness, the API I am using for recording video is as follows:

androidx.camera.core.VideoCapture
public void startRecording

Am I missing some permission?
Here are the permissions that I have defined in AndroidManifest.xml:
 
     <uses-feature
        android:name="android.hardware.camera"
        android:required="false" />
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>

    <!-- The following are not supported in Android 13+...  hover below for details. -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
   
And here is the snippet of code that requests the permissions:

       final String[] permissions = {
                Manifest.permission.CAMERA,
                Manifest.permission.RECORD_AUDIO,
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE};

        requestPermissions(permissions, THIS_APP_PERMISSION_REQUEST_CODE);

Any ideas what I couldbe missing here?
Any help is greatly appreciated.
Thank you for your time.

sanjuro ogawa

unread,
Sep 4, 2023, 7:38:11 PM9/4/23
to Android CameraX Discussion Group, sanjuro ogawa

I will also add that I just tested that I could write a file to the target file system using an instance of java.io.FileWriter.
That this works is an indication that my permissions are configured correctly, I believe.

Thanks in advance for any help.

Leo Huang

unread,
Sep 4, 2023, 9:28:38 PM9/4/23
to Android CameraX Discussion Group, ogawa....@gmail.com
This may be related to limitations of Android scoped storage from Android 10 (API level 29). See https://developer.android.com/training/data-storage#scoped-storage

You can use MediaStore type output option instead.

sample:
                        ContentValues contentValues = new ContentValues();
                        contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "file_name.jpg");
                        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");

                        ImageCapture.OutputFileOptions outputFileOptions =
                                new ImageCapture.OutputFileOptions.Builder(
                                        getContentResolver(),
                                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
                                        .build();

ogawa....@gmail.com 在 2023年9月5日 星期二清晨7:38:11 [UTC+8] 的信中寫道:

Leo Huang

unread,
Sep 4, 2023, 10:21:39 PM9/4/23
to Android CameraX Discussion Group, Leo Huang, ogawa....@gmail.com
If this is not the cause, could you also try newer CameraX version, ex: 1.3.0-rc01

Leo Huang 在 2023年9月5日 星期二上午9:28:38 [UTC+8] 的信中寫道:

NGENGE SENIOR

unread,
Sep 4, 2023, 10:34:14 PM9/4/23
to Leo Huang, Android CameraX Discussion Group, ogawa....@gmail.com
I think Leo is right. I faced the same problem with CameraX 1.2.2. Use the MediaStore instead for Android Q and above. I even faced the sane issue with video recording. Trying to use FileOutputOptions for Android Q+ fails but when I used MediaStoreOutputOptions, it worked fine.

--
You received this message because you are subscribed to the Google Groups "Android CameraX Discussion Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to camerax-develop...@android.com.
To view this discussion on the web visit https://groups.google.com/a/android.com/d/msgid/camerax-developers/1e85fdb0-761e-4375-850a-3b19cd35f7d1n%40android.com.

Scott Nien

unread,
Sep 5, 2023, 1:44:37 AM9/5/23
to NGENGE SENIOR, Leo Huang, Android CameraX Discussion Group, ogawa....@gmail.com
While media store output option works,  If you prefer using file path,  here is more information and the solutions:
1) In API 29,   the new scoped storage doesn't allow apps to write using file path to the external public folder unless you turn on requestLegacyExternalStorage flag in the manifest <Application> 
2) In API 30+,  this limitation seems to be removed.   but CameraX previously has a issue that it tries to create ".tmp" files on the public external folder which is not allowed.  CameraX 1.3.0 rc01 has fixed the issue( fix is here). 

In short, do the following if you prefer using file path. 
1) Set requestLegacyExternalStorage to true in manifest <Application> (this works for API 29 and is ignored in API 30+)
2) Use CameraX 1.3.0 rc01 or above


sanjuro ogawa

unread,
Sep 5, 2023, 2:18:23 AM9/5/23
to Android CameraX Discussion Group, scot...@google.com, leoh...@google.com, Android CameraX Discussion Group, sanjuro ogawa, senior...@gmail.com
Hello, everyone!
Thank you for all of your input.

It seems that I may need to write a bit of a wrapper around the whole "media saving" logic for pictures and movies.

Something such that if I could detect the current android version at runtime, branch to the appropriate code block.

So far, the requestLegacyExternalStorage setting to true under API 29 works.
As expected, API 30 did not work.
I tried to use leoh's solution and it worked, except that it ignored the full path that I had specifed, converted all of the "/" to "_", then saved the jpeg file in "Pictures" directly instead of saving it under "Pictures/MyPics" as I'd hoped. 
So a filename would come out looking like this: "_storage_emulated_0_Pictures_MyPics_1693892355124.jpg".
Quite close.  Perhaps it is because of the parameter MediaStore.MediaColumns.DISPLAY_NAME?  Apart from that it saved a file every time.

I did try CameraX 1.3.0 rc01 and found that I needed to change  the import for androidx.camera.core.VideoCapture to androidx.camera.video.VideoCapture as well as install API 34.

Again, I imagine that I would need to have to use some if-logic to make it so that things work reliably from API 24 (Nougat; Android 7.0) to present.

Thanks for all of the input. 😀
If it seems like I might have gotten sometthing wrong here, or if there are other ideas, please chime in and let me know.

Leo Huang

unread,
Sep 5, 2023, 3:13:32 AM9/5/23
to Android CameraX Discussion Group, ogawa....@gmail.com, Scott Nien, Leo Huang, Android CameraX Discussion Group, senior...@gmail.com
To save image to the relative path, you can add one more content value as below

contentValues.put(MediaStore.Images.Media.RELATIVE_PATH,
                  Environment.DIRECTORY_PICTURES + File.separator + "MyPics");
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, "1693892355124.jpg");

ogawa....@gmail.com 在 2023年9月5日 星期二下午2:18:23 [UTC+8] 的信中寫道:

sanjuro ogawa

unread,
Sep 5, 2023, 4:04:34 AM9/5/23
to Android CameraX Discussion Group, leoh...@google.com, sanjuro ogawa, scot...@google.com, Android CameraX Discussion Group, senior...@gmail.com
Hello, leoh!

I just tried out your suggestion and it worked like a charm!

Thanks again!

Reply all
Reply to author
Forward
0 new messages