Fix portrait image metadata when uploading without media optimization (#6362)
* fix(media): preserve image orientation metadata without optimization * style: linting
This commit is contained in:
parent
d38f483cd1
commit
523ede744a
2 changed files with 67 additions and 12 deletions
|
|
@ -195,18 +195,16 @@ class AndroidMediaPreProcessor(
|
|||
file = file,
|
||||
mimeType = mimeType,
|
||||
)
|
||||
val imageInfo = contentResolver.openInputStream(uri).use { input ->
|
||||
val bitmap = BitmapFactory.decodeStream(input, null, null)!!
|
||||
ImageInfo(
|
||||
width = bitmap.width.toLong(),
|
||||
height = bitmap.height.toLong(),
|
||||
mimetype = mimeType,
|
||||
size = file.length(),
|
||||
thumbnailInfo = thumbnailResult?.info,
|
||||
thumbnailSource = null,
|
||||
blurhash = thumbnailResult?.blurhash,
|
||||
)
|
||||
}
|
||||
val (width, height) = extractOrientedImageDimensions(file)
|
||||
val imageInfo = ImageInfo(
|
||||
width = width,
|
||||
height = height,
|
||||
mimetype = mimeType,
|
||||
size = file.length(),
|
||||
thumbnailInfo = thumbnailResult?.info,
|
||||
thumbnailSource = null,
|
||||
blurhash = thumbnailResult?.blurhash,
|
||||
)
|
||||
removeSensitiveImageMetadata(file)
|
||||
return MediaUploadInfo.Image(
|
||||
file = file,
|
||||
|
|
@ -354,6 +352,23 @@ class AndroidMediaPreProcessor(
|
|||
return contentResolver.openInputStream(uri)?.use { createTmpFileWithInput(it) }
|
||||
?: error("Could not copy the contents of $uri to a temporary file")
|
||||
}
|
||||
|
||||
private fun extractOrientedImageDimensions(file: File): Pair<Long, Long> {
|
||||
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||
BitmapFactory.decodeFile(file.path, options)
|
||||
|
||||
val rawWidth = options.outWidth.toLong()
|
||||
val rawHeight = options.outHeight.toLong()
|
||||
val orientation = tryOrNull {
|
||||
ExifInterface(file).getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)
|
||||
} ?: ExifInterface.ORIENTATION_UNDEFINED
|
||||
|
||||
return orientedImageDimensions(
|
||||
rawWidth = rawWidth,
|
||||
rawHeight = rawHeight,
|
||||
orientation = orientation,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ImageCompressionResult.toImageInfo(mimeType: String, thumbnailResult: ThumbnailResult?) = ImageInfo(
|
||||
|
|
@ -371,3 +386,18 @@ private fun MediaMetadataRetriever.extractDuration(): Duration {
|
|||
val durationInMs = extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong() ?: 0L
|
||||
return durationInMs.milliseconds
|
||||
}
|
||||
|
||||
internal fun orientedImageDimensions(rawWidth: Long, rawHeight: Long, orientation: Int): Pair<Long, Long> {
|
||||
return if (orientation.rotatesRightAngle()) {
|
||||
rawHeight to rawWidth
|
||||
} else {
|
||||
rawWidth to rawHeight
|
||||
}
|
||||
}
|
||||
|
||||
private fun Int.rotatesRightAngle(): Boolean {
|
||||
return this == ExifInterface.ORIENTATION_ROTATE_90 ||
|
||||
this == ExifInterface.ORIENTATION_ROTATE_270 ||
|
||||
this == ExifInterface.ORIENTATION_TRANSPOSE ||
|
||||
this == ExifInterface.ORIENTATION_TRANSVERSE
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import android.content.Context
|
|||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.net.toUri
|
||||
import androidx.exifinterface.media.ExifInterface
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.androidutils.file.TemporaryUriDeleter
|
||||
|
|
@ -42,6 +43,30 @@ import kotlin.time.Duration
|
|||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class AndroidMediaPreProcessorTest {
|
||||
@Test
|
||||
fun `orientedImageDimensions swaps width and height for 90 degree exif orientation`() {
|
||||
val (width, height) = orientedImageDimensions(
|
||||
rawWidth = 4032,
|
||||
rawHeight = 2268,
|
||||
orientation = ExifInterface.ORIENTATION_ROTATE_90,
|
||||
)
|
||||
|
||||
assertThat(width).isEqualTo(2268)
|
||||
assertThat(height).isEqualTo(4032)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `orientedImageDimensions keeps width and height for upright exif orientation`() {
|
||||
val (width, height) = orientedImageDimensions(
|
||||
rawWidth = 4032,
|
||||
rawHeight = 2268,
|
||||
orientation = ExifInterface.ORIENTATION_NORMAL,
|
||||
)
|
||||
|
||||
assertThat(width).isEqualTo(4032)
|
||||
assertThat(height).isEqualTo(2268)
|
||||
}
|
||||
|
||||
private suspend fun TestScope.process(
|
||||
asset: Asset,
|
||||
mediaOptimizationConfig: MediaOptimizationConfig,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue