When trying to save any JPEG picture using saveAttributes()
from androidx Exifinterface
, my program crashes with the error "write failed: EBADF (Bad file descriptor)"
I can replicate the error starting fresh from a new project. I'm using Android Studio: new project
->Empty Activity
. I'm using the emulator to test.
Below is the full code with the only changes I made to the fresh Empty Activity template.
Using androidx Exifinterface
, this code is correctly able to get Exif attributes. However, saveAttributes()
crashes every time:
saveAttributes()
crashes regardless if I firstsetAttribute()
or not.- Which picture used does not matter. It crashes for every picture I've tried.
- I'm using JPEG pictures. I have not tested with other mime types.
saveAttributes()
throws: "Failed to save new file. Original file is stored in..."
I want to set Exif attributes of the picture and save into the original image file. What is the correct way?
[This post should be tagged androidx-interface
. But that tag does not exist, and I don't have the reputation to add a tag. So I used tag android-interface
, which does exist].
build.gradle (:app)
implementation "androidx.exifinterface:exifinterface:1.3.2"
AndroidManifest.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
MainActivity.kt:
package com.example.test_exif_save
import android.content.ContentUris
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import androidx.core.app.ActivityCompat
import androidx.exifinterface.media.ExifInterface
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Simple method for PERMISSIONS just for quick testing
val permissions = arrayOf(
android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.Manifest.permission.ACCESS_MEDIA_LOCATION,
)
ActivityCompat.requestPermissions(this, permissions, 0)
val contentUri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
// id of arbitrary picture saved in Pictures/
// The picture chosen does not matter. The same crash occurs for every picture.
val picture_id: Long = 32
val uri = ContentUris.withAppendedId(contentUri, picture_id)
contentResolver.openInputStream(uri)?.use { stream ->
val exifData = ExifInterface(stream)
// Check that ExifInterface getAttribute works correctly
val attr_model = exifData.getAttribute(ExifInterface.TAG_MODEL)
val attr_datetime_original = exifData.getAttribute(ExifInterface.TAG_DATETIME_ORIGINAL)
val attr_image_width = exifData.getAttribute(ExifInterface.TAG_IMAGE_WIDTH)
Log.i("ExifData", "Model: $attr_model")
Log.i("ExifData", "Datetime original: $attr_datetime_original")
Log.i("ExifData", "Width: $attr_image_width")
// Try to save
// Causes fatal exception. Error: ErrnoException: write failed: EBADF (Bad file descriptor)
exifData.saveAttributes()
}
}
}
The stack trace:
com.example.test_exif_save E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.test_exif_save, PID: 12188
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.test_exif_save/com.example.test_exif_save.MainActivity}: java.io.IOException: Failed to save new file. Original file is stored in /data/user/0/com.example.test_exif_save/cache/temp1652156935871844716tmp
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.io.IOException: Failed to save new file. Original file is stored in /data/user/0/com.example.test_exif_save/cache/temp1652156935871844716tmp
at androidx.exifinterface.media.ExifInterface.saveAttributes(ExifInterface.java:4783)
at com.example.test_exif_save.MainActivity.onCreate(MainActivity.kt:44)
at android.app.Activity.performCreate(Activity.java:8000)
at android.app.Activity.performCreate(Activity.java:7984)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.io.IOException: write failed: EBADF (Bad file descriptor)
at libcore.io.IoBridge.write(IoBridge.java:540)
at java.io.FileOutputStream.write(FileOutputStream.java:398)
at androidx.exifinterface.media.ExifInterface.copy(ExifInterface.java:8087)
at androidx.exifinterface.media.ExifInterface.saveAttributes(ExifInterface.java:4779)
at com.example.test_exif_save.MainActivity.onCreate(MainActivity.kt:44)
at android.app.Activity.performCreate(Activity.java:8000)
at android.app.Activity.performCreate(Activity.java:7984)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: android.system.ErrnoException: write failed: EBADF (Bad file descriptor)
at libcore.io.Linux.writeBytes(Native Method)
at libcore.io.Linux.write(Linux.java:293)
at libcore.io.ForwardingOs.write(ForwardingOs.java:240)
at libcore.io.BlockGuardOs.write(BlockGuardOs.java:418)
at libcore.io.ForwardingOs.write(ForwardingOs.java:240)
at libcore.io.IoBridge.write(IoBridge.java:535)
at java.io.FileOutputStream.write(FileOutputStream.java:398)
at androidx.exifinterface.media.ExifInterface.copy(ExifInterface.java:8087)
at androidx.exifinterface.media.ExifInterface.saveAttributes(ExifInterface.java:4779)
at com.example.test_exif_save.MainActivity.onCreate(MainActivity.kt:44)
at android.app.Activity.performCreate(Activity.java:8000)
at android.app.Activity.performCreate(Activity.java:7984)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)