@@ -16,6 +16,7 @@ import com.facebook.react.modules.core.PermissionAwareActivity
1616import com.facebook.react.modules.core.PermissionListener
1717import com.facebook.react.util.RNLog
1818import com.lodev09.exify.ExifyUtils.formatTags
19+ import java.io.File
1920import java.io.IOException
2021
2122private const val ERROR_TAG = " E_EXIFY_ERROR"
@@ -72,35 +73,66 @@ class ExifyModule(
7273 promise : Promise ,
7374 ) {
7475 try {
75- val inputStream =
76- if (scheme == " http" || scheme == " https" ) {
77- java.net.URL (uri).openStream()
78- } else if (scheme == " content" && Build .VERSION .SDK_INT >= Build .VERSION_CODES .Q ) {
79- try {
80- context.contentResolver.openInputStream(MediaStore .setRequireOriginal(photoUri))
81- } catch (e: SecurityException ) {
82- context.contentResolver.openInputStream(photoUri)
83- }
76+ val exif =
77+ if (scheme == " file" ) {
78+ ExifInterface (photoUri.path!! )
8479 } else {
85- context.contentResolver.openInputStream(photoUri)
80+ val inputStream =
81+ if (scheme == " content" && Build .VERSION .SDK_INT >= Build .VERSION_CODES .Q ) {
82+ try {
83+ context.contentResolver.openInputStream(MediaStore .setRequireOriginal(photoUri))
84+ } catch (_: SecurityException ) {
85+ context.contentResolver.openInputStream(photoUri)
86+ }
87+ } else if (scheme == " http" || scheme == " https" ) {
88+ java.net.URL (uri).openStream()
89+ } else {
90+ context.contentResolver.openInputStream(photoUri)
91+ }
92+
93+ if (inputStream == null ) {
94+ RNLog .w(context, " Exify: Could not open URI: $uri " )
95+ promise.reject(ERROR_TAG , " Could not open URI: $uri " )
96+ return
97+ }
98+
99+ inputStream.use { ExifInterface (it) }
86100 }
87101
88- if (inputStream == null ) {
89- RNLog .w(context, " Exify: Could not open URI: $uri " )
90- promise.reject(ERROR_TAG , " Could not open URI: $uri " )
91- return
92- }
102+ val tags = formatTags(exif)
93103
94- inputStream.use {
95- val tags = formatTags(ExifInterface (it))
96- promise.resolve(tags)
104+ // ExifInterface ignores IFD0 tags placed in ExifIFD (non-standard but common
105+ // with some image editors). Fall back to raw EXIF parsing for missing tags.
106+ val missingTags =
107+ IFD0_STRING_TAGS .filter { ! tags.hasKey(it) }.toSet()
108+ if (missingTags.isNotEmpty()) {
109+ val fallback =
110+ try {
111+ openInputStream(uri, photoUri, scheme)?.use { readFallbackTags(it, missingTags) }
112+ } catch (_: Exception ) {
113+ null
114+ }
115+ fallback?.forEach { (tag, value) -> tags.putString(tag, value) }
97116 }
117+
118+ promise.resolve(tags)
98119 } catch (e: Exception ) {
99120 RNLog .w(context, " Exify: ${e.message} " )
100121 promise.reject(ERROR_TAG , e.message, e)
101122 }
102123 }
103124
125+ private fun openInputStream (
126+ uri : String ,
127+ photoUri : Uri ,
128+ scheme : String ,
129+ ): java.io.InputStream ? =
130+ when (scheme) {
131+ " file" -> File (photoUri.path!! ).inputStream()
132+ " content" -> context.contentResolver.openInputStream(photoUri)
133+ else -> java.net.URL (uri).openStream()
134+ }
135+
104136 @Throws(IOException ::class )
105137 override fun write (
106138 uri : String ,
0 commit comments