diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ea73a9d..ecbd2569 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## [x.x.x] - unreleased +- CropImageView: Added support for handling all EXIF orientation values. [#408](https://github.com/CanHub/Android-Image-Cropper/issues/408) - CropImageView: Use customOutputUri instance property as a fallback in startCropWorkerTask. [#401](https://github.com/CanHub/Android-Image-Cropper/issues/401) - CropImageOptions: Option to change progress bar color. [#390](https://github.com/CanHub/Android-Image-Cropper/issues/390) - Sample: Showcase 2:1 aspect ratio. [#386](https://github.com/CanHub/Android-Image-Cropper/issues/386) diff --git a/cropper/src/main/java/com/canhub/cropper/BitmapLoadingWorkerJob.kt b/cropper/src/main/java/com/canhub/cropper/BitmapLoadingWorkerJob.kt index 7930cfc8..116552ac 100644 --- a/cropper/src/main/java/com/canhub/cropper/BitmapLoadingWorkerJob.kt +++ b/cropper/src/main/java/com/canhub/cropper/BitmapLoadingWorkerJob.kt @@ -40,14 +40,16 @@ class BitmapLoadingWorkerJob internal constructor( val decodeResult = BitmapUtils.decodeSampledBitmap(context, uri, width, height) if (isActive) { - val rotateResult = - BitmapUtils.rotateBitmapByExif(decodeResult.bitmap, context, uri) + val orientateResult = + BitmapUtils.orientateBitmapByExif(decodeResult.bitmap, context, uri) onPostExecute( Result( uri = uri, - bitmap = rotateResult.bitmap, + bitmap = orientateResult.bitmap, loadSampleSize = decodeResult.sampleSize, - degreesRotated = rotateResult.degrees + degreesRotated = orientateResult.degrees, + flipHorizontally = orientateResult.flipHorizontally, + flipVertically = orientateResult.flipVertically ) ) } @@ -102,6 +104,12 @@ class BitmapLoadingWorkerJob internal constructor( /** The degrees the image was rotated */ val degreesRotated: Int + /** If the image was flipped horizontally */ + var flipHorizontally: Boolean = false + + /** If the image was flipped vertically */ + var flipVertically: Boolean = false + /** The error that occurred during async bitmap loading. */ val error: Exception? @@ -116,11 +124,20 @@ class BitmapLoadingWorkerJob internal constructor( fun getUriFilePath(context: Context, uniqueName: Boolean = false): String = getFilePathFromUri(context, uriContent, uniqueName) - internal constructor(uri: Uri, bitmap: Bitmap?, loadSampleSize: Int, degreesRotated: Int) { + internal constructor( + uri: Uri, + bitmap: Bitmap?, + loadSampleSize: Int, + degreesRotated: Int, + flipHorizontally: Boolean, + flipVertically: Boolean + ) { uriContent = uri this.bitmap = bitmap this.loadSampleSize = loadSampleSize this.degreesRotated = degreesRotated + this.flipHorizontally = flipHorizontally + this.flipVertically = flipVertically error = null } diff --git a/cropper/src/main/java/com/canhub/cropper/BitmapUtils.kt b/cropper/src/main/java/com/canhub/cropper/BitmapUtils.kt index bf9f0ee6..707c3db8 100644 --- a/cropper/src/main/java/com/canhub/cropper/BitmapUtils.kt +++ b/cropper/src/main/java/com/canhub/cropper/BitmapUtils.kt @@ -74,7 +74,7 @@ internal object BitmapUtils { * If no rotation is required the image will not be rotated.

* New bitmap is created and the old one is recycled. */ - fun rotateBitmapByExif(bitmap: Bitmap?, context: Context, uri: Uri?): RotateBitmapResult { + fun orientateBitmapByExif(bitmap: Bitmap?, context: Context, uri: Uri?): RotateBitmapResult { var ei: ExifInterface? = null try { val `is` = context.contentResolver.openInputStream(uri!!) @@ -84,7 +84,7 @@ internal object BitmapUtils { } } catch (ignored: Exception) { } - return if (ei != null) rotateBitmapByExif(bitmap, ei) else RotateBitmapResult(bitmap, 0) + return if (ei != null) orientateBitmapByExif(bitmap, ei) else RotateBitmapResult(bitmap, 0) } /** @@ -92,19 +92,21 @@ internal object BitmapUtils { * If no rotation is required the image will not be rotated.

* New bitmap is created and the old one is recycled. */ - fun rotateBitmapByExif(bitmap: Bitmap?, exif: ExifInterface): RotateBitmapResult { - val degrees: Int = when ( - exif.getAttributeInt( - ExifInterface.TAG_ORIENTATION, - ExifInterface.ORIENTATION_NORMAL - ) - ) { - ExifInterface.ORIENTATION_ROTATE_90 -> 90 + fun orientateBitmapByExif(bitmap: Bitmap?, exif: ExifInterface): RotateBitmapResult { + val orientationAttributeInt = + exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL) + val degrees: Int = when (orientationAttributeInt) { + ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_TRANSVERSE, + ExifInterface.ORIENTATION_TRANSPOSE -> 90 ExifInterface.ORIENTATION_ROTATE_180 -> 180 ExifInterface.ORIENTATION_ROTATE_270 -> 270 else -> 0 } - return RotateBitmapResult(bitmap, degrees) + val flipHorizontally = orientationAttributeInt == ExifInterface.ORIENTATION_FLIP_HORIZONTAL || + orientationAttributeInt == ExifInterface.ORIENTATION_TRANSPOSE + val flipVertically = orientationAttributeInt == ExifInterface.ORIENTATION_FLIP_VERTICAL || + orientationAttributeInt == ExifInterface.ORIENTATION_TRANSVERSE + return RotateBitmapResult(bitmap, degrees, flipHorizontally, flipVertically) } /** @@ -970,6 +972,14 @@ internal object BitmapUtils { /** * The degrees the image was rotated */ - val degrees: Int + val degrees: Int, + /** + * If the image was flipped horizontally + */ + val flipHorizontally: Boolean = false, + /** + * If the image was flipped vertically + */ + val flipVertically: Boolean = false ) } diff --git a/cropper/src/main/java/com/canhub/cropper/CropImageView.kt b/cropper/src/main/java/com/canhub/cropper/CropImageView.kt index 4f889513..f8d9ba46 100644 --- a/cropper/src/main/java/com/canhub/cropper/CropImageView.kt +++ b/cropper/src/main/java/com/canhub/cropper/CropImageView.kt @@ -711,9 +711,11 @@ class CropImageView @JvmOverloads constructor(context: Context, attrs: Attribute val setBitmap: Bitmap? var degreesRotated = 0 if (bitmap != null && exif != null) { - val result = BitmapUtils.rotateBitmapByExif(bitmap, exif) + val result = BitmapUtils.orientateBitmapByExif(bitmap, exif) setBitmap = result.bitmap degreesRotated = result.degrees + mFlipHorizontally = result.flipHorizontally + mFlipVertically = result.flipVertically mInitialDegreesRotated = result.degrees } else setBitmap = bitmap @@ -866,6 +868,8 @@ class CropImageView @JvmOverloads constructor(context: Context, attrs: Attribute setProgressBarVisibility() if (result.error == null) { mInitialDegreesRotated = result.degreesRotated + mFlipHorizontally = result.flipHorizontally + mFlipVertically = result.flipVertically setBitmap( result.bitmap, 0,