From 90b028fe1af3c257e4ceb68c8c86955069dea0f9 Mon Sep 17 00:00:00 2001 From: dayeggpi Date: Sun, 24 May 2026 11:24:32 +0200 Subject: [PATCH 1/2] Add files via upload --- .../org/fossify/camera/helpers/ImageSaver.kt | 76 ++++++++++++++++--- 1 file changed, 64 insertions(+), 12 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/camera/helpers/ImageSaver.kt b/app/src/main/kotlin/org/fossify/camera/helpers/ImageSaver.kt index 35d7f6a7..2a3d90d7 100644 --- a/app/src/main/kotlin/org/fossify/camera/helpers/ImageSaver.kt +++ b/app/src/main/kotlin/org/fossify/camera/helpers/ImageSaver.kt @@ -3,6 +3,10 @@ package org.fossify.camera.helpers import android.annotation.SuppressLint import android.content.ContentResolver import android.content.ContentValues +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.ImageFormat +import android.graphics.Matrix import android.net.Uri import android.provider.MediaStore import androidx.camera.core.ImageCapture @@ -98,34 +102,35 @@ class ImageSaver private constructor( } try { - val output = FileOutputStream(tempFile) - val byteArray: ByteArray = imageToJpegByteArray(image, jpegQuality) - output.write(byteArray) + FileOutputStream(tempFile).use { output -> + val byteArray: ByteArray = imageToJpegByteArray(image, jpegQuality) + output.write(byteArray) + } if (saveExifAttributes) { val exifInterface = ExifInterface(tempFile) - val imageByteArray = jpegImageToJpegByteArray(image) - val inputStream: InputStream = ByteArrayInputStream(imageByteArray) - ExifInterface(inputStream).copyTo(exifInterface) - - // Overwrite the original orientation if the quirk exists. + if (image.format == ImageFormat.JPEG) { + val imageByteArray = jpegImageToJpegByteArray(image) + val inputStream: InputStream = ByteArrayInputStream(imageByteArray) + ExifInterface(inputStream).copyTo(exifInterface) + } if (!ExifRotationAvailability().shouldUseExifOrientation(image)) { exifInterface.rotate(image.imageInfo.rotationDegrees) } - if (metadata.isReversedHorizontal) { exifInterface.flipHorizontally() } - if (metadata.isReversedVertical) { exifInterface.flipVertically() } - if (metadata.location != null) { exifInterface.setGpsInfo(metadata.location) } - exifInterface.saveAttributes() + } else { + // Physically rotate pixels so orientation is correct with no EXIF stored. + // Bitmap.compress produces JPEG with no EXIF, satisfying the no-metadata setting. + rotatePixelsAndStrip(tempFile) } } catch (e: IOException) { saveError = SaveError.FILE_IO_FAILED @@ -164,6 +169,53 @@ class ImageSaver private constructor( return tempFile } + @SuppressLint("RestrictedApi") + private fun rotatePixelsAndStrip(file: File) { + // Determine the correct orientation using an in-memory ExifInterface as a calculator. + val rotateDegrees: Int + val isFlipped: Boolean + + if (image.format == ImageFormat.JPEG) { + val srcExif = ExifInterface(ByteArrayInputStream(jpegImageToJpegByteArray(image))) + if (!ExifRotationAvailability().shouldUseExifOrientation(image)) { + srcExif.rotate(image.imageInfo.rotationDegrees) + } + if (metadata.isReversedHorizontal) srcExif.flipHorizontally() + if (metadata.isReversedVertical) srcExif.flipVertically() + rotateDegrees = srcExif.rotationDegrees + isFlipped = srcExif.isFlipped + } else { + // YUV: no EXIF in source bytes; rotation is entirely in rotationDegrees. + var deg = image.imageInfo.rotationDegrees + var flip = metadata.isReversedHorizontal + if (metadata.isReversedVertical) { + flip = !flip + deg = (deg + 180) % 360 + } + rotateDegrees = deg + isFlipped = flip + } + + val matrix = Matrix() + if (isFlipped) matrix.postScale(-1f, 1f) + if (rotateDegrees != 0) matrix.postRotate(rotateDegrees.toFloat()) + + val decoded = BitmapFactory.decodeFile(file.absolutePath) ?: return + val finalBitmap = if (!matrix.isIdentity) { + Bitmap.createBitmap(decoded, 0, 0, decoded.width, decoded.height, matrix, true) + .also { decoded.recycle() } + } else { + decoded + } + try { + FileOutputStream(file).use { out -> + finalBitmap.compress(Bitmap.CompressFormat.JPEG, jpegQuality, out) + } + } finally { + finalBitmap.recycle() + } + } + /** * Copy the temp file to user specified destination. * From 54b11217a9edcd1ffc7c7a51ec896ee9a512193d Mon Sep 17 00:00:00 2001 From: dayeggpi Date: Sun, 24 May 2026 11:35:39 +0200 Subject: [PATCH 2/2] Add files via upload --- app/src/main/kotlin/org/fossify/camera/helpers/ImageSaver.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/org/fossify/camera/helpers/ImageSaver.kt b/app/src/main/kotlin/org/fossify/camera/helpers/ImageSaver.kt index 2a3d90d7..0bbd5e9e 100644 --- a/app/src/main/kotlin/org/fossify/camera/helpers/ImageSaver.kt +++ b/app/src/main/kotlin/org/fossify/camera/helpers/ImageSaver.kt @@ -46,6 +46,8 @@ class ImageSaver private constructor( private const val COPY_BUFFER_SIZE = 1024 private const val PENDING = 1 private const val NOT_PENDING = 0 + private const val ROTATION_180 = 180 + private const val DEGREES_IN_CIRCLE = 360 fun saveImage( contentResolver: ContentResolver, @@ -190,7 +192,7 @@ class ImageSaver private constructor( var flip = metadata.isReversedHorizontal if (metadata.isReversedVertical) { flip = !flip - deg = (deg + 180) % 360 + deg = (deg + ROTATION_180) % DEGREES_IN_CIRCLE } rotateDegrees = deg isFlipped = flip