@@ -9,6 +9,7 @@ import android.graphics.Paint
99import android.media.ExifInterface
1010import android.net.Uri
1111import android.util.Base64
12+ import android.util.Log
1213import com.facebook.react.bridge.ReactApplicationContext
1314import com.reactnativecompressor.Utils.MediaCache
1415import com.reactnativecompressor.Utils.Utils.exifAttributes
@@ -21,6 +22,8 @@ import java.io.IOException
2122import java.net.MalformedURLException
2223
2324object ImageCompressor {
25+ private const val TAG = " ImageCompressor"
26+
2427 fun getRNFileUrl (filePath : String? ): String? {
2528 var filePath = filePath
2629 val returnAbleFile = File (filePath)
@@ -56,25 +59,38 @@ object ImageCompressor {
5659 return BitmapFactory .decodeFile(filePath)
5760 }
5861
59- fun copyExifInfo (imagePath : String , outputUri : String ){
60- try {
61- // for copy exif info
62- val sourceExif = ExifInterface (imagePath)
63- val compressedExif = ExifInterface (outputUri)
64- for (tag in exifAttributes) {
65- val compressedValue = compressedExif.getAttribute(tag)
66- if (compressedValue== null )
67- {
68- val sourceValue = sourceExif.getAttribute(tag)
69- if (sourceValue != null ) {
70- compressedExif.setAttribute(tag, sourceValue)
62+ /* *
63+ * Strip "file://" / "content://" scheme so legacy ExifInterface can open
64+ * the underlying JPEG. ExifInterface(String) only accepts raw filesystem
65+ * paths — passing a URI string makes it fail silently inside the
66+ * try/catch and drops every EXIF tag, including GPS.
67+ */
68+ private fun normalizeToFilePath (input : String ): String {
69+ if (input.startsWith(" file://" ) || input.startsWith(" content://" )) {
70+ return Uri .parse(input).path ? : input
71+ }
72+ return input
73+ }
74+
75+ fun copyExifInfo (imagePath : String , outputUri : String ) {
76+ try {
77+ val sourcePath = normalizeToFilePath(imagePath)
78+ val outPath = normalizeToFilePath(outputUri)
79+ val sourceExif = ExifInterface (sourcePath)
80+ val compressedExif = ExifInterface (outPath)
81+ var copied = 0
82+ for (tag in exifAttributes) {
83+ val sourceValue = sourceExif.getAttribute(tag) ? : continue
84+ if (compressedExif.getAttribute(tag) == null ) {
85+ compressedExif.setAttribute(tag, sourceValue)
86+ copied++
87+ }
7188 }
72- }
89+ compressedExif.saveAttributes()
90+ Log .i(TAG , " copyExifInfo copied $copied tags from $sourcePath -> $outPath " )
91+ } catch (e: Exception ) {
92+ Log .w(TAG , " copyExifInfo failed for $imagePath " , e)
7393 }
74- compressedExif.saveAttributes()
75- } catch (e: Exception ) {
76- e.printStackTrace()
77- }
7894 }
7995
8096 fun encodeImage (imageDataByteArrayOutputStream : ByteArrayOutputStream , isBase64 : Boolean , outputExtension : String? ,imagePath : String? , reactContext : ReactApplicationContext ? ): String? {
@@ -84,10 +100,14 @@ object ImageCompressor {
84100 } else {
85101 val outputUri = generateCacheFilePath(outputExtension!! , reactContext!! )
86102 try {
87- val fos = FileOutputStream (outputUri)
88- imageDataByteArrayOutputStream.writeTo(fos)
103+ // Close the stream before ExifInterface re-opens the file so
104+ // the JPEG bytes are fully flushed; otherwise saveAttributes()
105+ // may truncate the in-flight write.
106+ FileOutputStream (outputUri).use { fos ->
107+ imageDataByteArrayOutputStream.writeTo(fos)
108+ }
89109
90- copyExifInfo(imagePath!! , outputUri)
110+ copyExifInfo(imagePath!! , outputUri)
91111
92112 return getRNFileUrl(outputUri)
93113 } catch (e: Exception ) {
@@ -262,7 +282,7 @@ object ImageCompressor {
262282 if (bitmap == null || imagePath == null ) return bitmap
263283
264284 return try {
265- val exif = ExifInterface (imagePath)
285+ val exif = ExifInterface (normalizeToFilePath( imagePath) )
266286 val orientation = exif.getAttributeInt(ExifInterface .TAG_ORIENTATION , ExifInterface .ORIENTATION_NORMAL )
267287 val matrix = Matrix ()
268288
0 commit comments