@@ -3,10 +3,7 @@ package com.margelo.nitro.multipleimagepicker
33import android.app.Activity
44import android.content.Context
55import android.content.Intent
6- import android.graphics.Bitmap
7- import android.graphics.BitmapFactory
86import android.graphics.Color
9- import android.graphics.Matrix
107import android.net.Uri
118import android.util.Log
129import androidx.exifinterface.media.ExifInterface
@@ -170,8 +167,8 @@ class MultipleImagePickerImp(reactContext: ReactApplicationContext?) :
170167 if (item != null ) {
171168 val media = getResult(item)
172169 // 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 )
175172 } else {
176173 media
177174 }
@@ -658,52 +655,111 @@ class MultipleImagePickerImp(reactContext: ReactApplicationContext?) :
658655 }
659656
660657private 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+
661687 try {
662- val ei = ExifInterface (filePath )
688+ val ei = ExifInterface (file.absolutePath )
663689 val orientation = ei.getAttributeInt(
664690 ExifInterface .TAG_ORIENTATION ,
665691 ExifInterface .ORIENTATION_UNDEFINED
666692 )
667693
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+ }
684711 }
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+ )
685721 } 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)
687727 }
688- // Return with orientation info even if bitmap processing fails
728+
729+ // Fallback: try to read orientation info even if bitmap processing fails
689730 return try {
690- val ei = ExifInterface (filePath )
731+ val ei = ExifInterface (file.absolutePath )
691732 val orientation = ei.getAttributeInt(
692733 ExifInterface .TAG_ORIENTATION ,
693734 ExifInterface .ORIENTATION_UNDEFINED
694735 )
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 )
699743 }
700744}
701745
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+ }
707763}
708764
709765 override fun getAppContext (): Context {
0 commit comments