@@ -3,10 +3,7 @@ package com.margelo.nitro.multipleimagepicker
3
3
import android.app.Activity
4
4
import android.content.Context
5
5
import android.content.Intent
6
- import android.graphics.Bitmap
7
- import android.graphics.BitmapFactory
8
6
import android.graphics.Color
9
- import android.graphics.Matrix
10
7
import android.net.Uri
11
8
import android.util.Log
12
9
import androidx.exifinterface.media.ExifInterface
@@ -170,8 +167,8 @@ class MultipleImagePickerImp(reactContext: ReactApplicationContext?) :
170
167
if (item != null ) {
171
168
val media = getResult(item)
172
169
// Adjust orientation using ExifInterface for Android (only for images)
173
- val adjustedMedia = if (media.type == ResultType .IMAGE ) {
174
- adjustOrientation(media, item.path )
170
+ val adjustedMedia = if (media.type == ResultType .IMAGE && ! item.realPath.isNullOrBlank() ) {
171
+ adjustOrientation(media, item.realPath )
175
172
} else {
176
173
media
177
174
}
@@ -658,52 +655,111 @@ class MultipleImagePickerImp(reactContext: ReactApplicationContext?) :
658
655
}
659
656
660
657
private fun adjustOrientation (pickerResult : PickerResult , filePath : String ): PickerResult {
658
+ // Validate file path
659
+ if (filePath.isBlank()) {
660
+ Log .w(TAG , " File path is blank, returning original result" )
661
+ return pickerResult
662
+ }
663
+
664
+ // Clean the file path - remove file:// prefix and handle content URIs
665
+ val cleanPath = when {
666
+ filePath.startsWith(" file://" ) -> filePath.removePrefix(" file://" )
667
+ filePath.startsWith(" content://" ) -> {
668
+ Log .w(TAG , " Content URI provided instead of file path: $filePath , returning original result" )
669
+ return pickerResult
670
+ }
671
+ else -> filePath
672
+ }
673
+
674
+ val file = File (cleanPath)
675
+ Log .d(TAG , " Checking orientation for file: ${file.absolutePath} " )
676
+
677
+ if (! file.exists()) {
678
+ Log .w(TAG , " File does not exist: ${file.absolutePath} (original path: $filePath )" )
679
+ return pickerResult
680
+ }
681
+
682
+ if (! file.canRead()) {
683
+ Log .w(TAG , " Cannot read file: ${file.absolutePath} " )
684
+ return pickerResult
685
+ }
686
+
661
687
try {
662
- val ei = ExifInterface (filePath )
688
+ val ei = ExifInterface (file.absolutePath )
663
689
val orientation = ei.getAttributeInt(
664
690
ExifInterface .TAG_ORIENTATION ,
665
691
ExifInterface .ORIENTATION_UNDEFINED
666
692
)
667
693
668
- val rotatedBitmap: Bitmap ? = when (orientation) {
669
- ExifInterface .ORIENTATION_ROTATE_90 -> rotateImage(filePath, 90f )
670
- ExifInterface .ORIENTATION_ROTATE_180 -> rotateImage(filePath, 180f )
671
- ExifInterface .ORIENTATION_ROTATE_270 -> rotateImage(filePath, 270f )
672
- else -> BitmapFactory .decodeFile(filePath)
673
- }
674
-
675
- rotatedBitmap?.let { bitmap ->
676
- val width = bitmap.width.toDouble()
677
- val height = bitmap.height.toDouble()
678
- // Update width, height, and orientation in pickerResult
679
- return pickerResult.copy(
680
- width = width,
681
- height = height,
682
- orientation = orientation.toDouble()
683
- )
694
+ Log .d(TAG , " EXIF orientation for $filePath : $orientation " )
695
+
696
+ // Calculate adjusted dimensions based on orientation
697
+ val (adjustedWidth, adjustedHeight) = when (orientation) {
698
+ ExifInterface .ORIENTATION_ROTATE_90 ,
699
+ ExifInterface .ORIENTATION_ROTATE_270 ,
700
+ ExifInterface .ORIENTATION_TRANSPOSE ,
701
+ ExifInterface .ORIENTATION_TRANSVERSE -> {
702
+ // Swap width and height for 90° and 270° rotations
703
+ Log .d(TAG , " Swapping dimensions for orientation: $orientation " )
704
+ Pair (pickerResult.height, pickerResult.width)
705
+ }
706
+ else -> {
707
+ // Keep original dimensions for 0°, 180°, and flips
708
+ Log .d(TAG , " Keeping original dimensions for orientation: $orientation " )
709
+ Pair (pickerResult.width, pickerResult.height)
710
+ }
684
711
}
712
+
713
+ Log .d(TAG , " Adjusted dimensions: ${adjustedWidth} x${adjustedHeight} (orientation: $orientation )" )
714
+
715
+ // Return result with adjusted dimensions and orientation angle
716
+ return pickerResult.copy(
717
+ width = adjustedWidth,
718
+ height = adjustedHeight,
719
+ orientation = exifOrientationToRotationDegrees(orientation)
720
+ )
685
721
} catch (e: IOException ) {
686
- Log .e(TAG , " Failed to adjust orientation" , e)
722
+ Log .e(TAG , " IOException while adjusting orientation for $filePath " , e)
723
+ } catch (e: OutOfMemoryError ) {
724
+ Log .e(TAG , " OutOfMemoryError while processing image $filePath " , e)
725
+ } catch (e: Exception ) {
726
+ Log .e(TAG , " Unexpected error while adjusting orientation for $filePath " , e)
687
727
}
688
- // Return with orientation info even if bitmap processing fails
728
+
729
+ // Fallback: try to read orientation info even if bitmap processing fails
689
730
return try {
690
- val ei = ExifInterface (filePath )
731
+ val ei = ExifInterface (file.absolutePath )
691
732
val orientation = ei.getAttributeInt(
692
733
ExifInterface .TAG_ORIENTATION ,
693
734
ExifInterface .ORIENTATION_UNDEFINED
694
735
)
695
- pickerResult.copy(orientation = orientation.toDouble())
696
- } catch (e: IOException ) {
697
- Log .e(TAG , " Failed to read orientation" , e)
698
- pickerResult
736
+ val rotation = exifOrientationToRotationDegrees(orientation)
737
+ Log .d(TAG , " Fallback: setting orientation to $rotation degrees (EXIF: $orientation ) for $filePath " )
738
+ pickerResult.copy(orientation = rotation)
739
+ } catch (e: Exception ) {
740
+ Log .e(TAG , " Failed to read orientation in fallback for $filePath " , e)
741
+ // Return original result with no rotation needed
742
+ pickerResult.copy(orientation = 0.0 )
699
743
}
700
744
}
701
745
702
- private fun rotateImage (filePath : String , degree : Float ): Bitmap ? {
703
- val bitmap = BitmapFactory .decodeFile(filePath)
704
- val matrix = Matrix ()
705
- matrix.postRotate(degree)
706
- return Bitmap .createBitmap(bitmap, 0 , 0 , bitmap.width, bitmap.height, matrix, true )
746
+ /* *
747
+ * Maps EXIF orientation values to rotation degrees for image display.
748
+ * Returns the rotation angle needed to display the image correctly.
749
+ */
750
+ private fun exifOrientationToRotationDegrees (exifOrientation : Int ): Double {
751
+ return when (exifOrientation) {
752
+ ExifInterface .ORIENTATION_ROTATE_90 -> 90.0
753
+ ExifInterface .ORIENTATION_ROTATE_180 -> 180.0
754
+ ExifInterface .ORIENTATION_ROTATE_270 -> - 90.0
755
+ ExifInterface .ORIENTATION_FLIP_HORIZONTAL -> 0.0 // Flip, not rotate
756
+ ExifInterface .ORIENTATION_FLIP_VERTICAL -> 0.0 // Flip, not rotate
757
+ ExifInterface .ORIENTATION_TRANSPOSE -> 90.0 // Flip + rotate 90
758
+ ExifInterface .ORIENTATION_TRANSVERSE -> - 90.0 // Flip + rotate -90
759
+ ExifInterface .ORIENTATION_NORMAL ,
760
+ ExifInterface .ORIENTATION_UNDEFINED -> 0.0
761
+ else -> 0.0 // No rotation needed
762
+ }
707
763
}
708
764
709
765
override fun getAppContext (): Context {
0 commit comments