mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-04-21 11:26:15 +02:00
131 lines
4.0 KiB
Kotlin
131 lines
4.0 KiB
Kotlin
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package app.tauri.camera
|
|
|
|
import android.content.Context
|
|
import android.graphics.Bitmap
|
|
import android.graphics.Matrix
|
|
import android.net.Uri
|
|
import androidx.exifinterface.media.ExifInterface
|
|
import app.tauri.Logger
|
|
import java.io.IOException
|
|
import java.io.InputStream
|
|
import java.lang.Integer.min
|
|
import kotlin.math.roundToInt
|
|
|
|
object ImageUtils {
|
|
/**
|
|
* Resize an image to the given max width and max height. Constraint can be put
|
|
* on one dimension, or both. Resize will always preserve aspect ratio.
|
|
* @param bitmap
|
|
* @param desiredMaxWidth
|
|
* @param desiredMaxHeight
|
|
* @return a new, scaled Bitmap
|
|
*/
|
|
fun resize(bitmap: Bitmap, desiredMaxWidth: Int, desiredMaxHeight: Int): Bitmap {
|
|
return resizePreservingAspectRatio(bitmap, desiredMaxWidth, desiredMaxHeight)
|
|
}
|
|
|
|
/**
|
|
* Resize an image to the given max width and max height. Constraint can be put
|
|
* on one dimension, or both. Resize will always preserve aspect ratio.
|
|
* @param bitmap
|
|
* @param desiredMaxWidth
|
|
* @param desiredMaxHeight
|
|
* @return a new, scaled Bitmap
|
|
*/
|
|
private fun resizePreservingAspectRatio(
|
|
bitmap: Bitmap,
|
|
desiredMaxWidth: Int,
|
|
desiredMaxHeight: Int
|
|
): Bitmap {
|
|
val width = bitmap.width
|
|
val height = bitmap.height
|
|
|
|
// 0 is treated as 'no restriction'
|
|
val maxHeight = if (desiredMaxHeight == 0) height else desiredMaxHeight
|
|
val maxWidth = if (desiredMaxWidth == 0) width else desiredMaxWidth
|
|
|
|
// resize with preserved aspect ratio
|
|
var newWidth = min(width, maxWidth).toFloat()
|
|
var newHeight = height * newWidth / width
|
|
if (newHeight > maxHeight) {
|
|
newWidth = (width * maxHeight / height).toFloat()
|
|
newHeight = maxHeight.toFloat()
|
|
}
|
|
return Bitmap.createScaledBitmap(bitmap, newWidth.roundToInt(), newHeight.roundToInt(), false)
|
|
}
|
|
|
|
/**
|
|
* Transform an image with the given matrix
|
|
* @param bitmap
|
|
* @param matrix
|
|
* @return
|
|
*/
|
|
private fun transform(bitmap: Bitmap, matrix: Matrix): Bitmap {
|
|
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
|
|
}
|
|
|
|
/**
|
|
* Correct the orientation of an image by reading its exif information and rotating
|
|
* the appropriate amount for portrait mode
|
|
* @param bitmap
|
|
* @param imageUri
|
|
* @param exif
|
|
* @return
|
|
*/
|
|
@Throws(IOException::class)
|
|
fun correctOrientation(c: Context, bitmap: Bitmap, imageUri: Uri, exif: ExifWrapper): Bitmap {
|
|
val orientation = getOrientation(c, imageUri)
|
|
return if (orientation != 0) {
|
|
val matrix = Matrix()
|
|
matrix.postRotate(orientation.toFloat())
|
|
exif.resetOrientation()
|
|
transform(bitmap, matrix)
|
|
} else {
|
|
bitmap
|
|
}
|
|
}
|
|
|
|
@Throws(IOException::class)
|
|
private fun getOrientation(c: Context, imageUri: Uri): Int {
|
|
var result = 0
|
|
c.getContentResolver().openInputStream(imageUri).use { iStream ->
|
|
val exifInterface = ExifInterface(iStream!!)
|
|
val orientation: Int = exifInterface.getAttributeInt(
|
|
ExifInterface.TAG_ORIENTATION,
|
|
ExifInterface.ORIENTATION_NORMAL
|
|
)
|
|
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
|
|
result = 90
|
|
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
|
|
result = 180
|
|
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
|
|
result = 270
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
fun getExifData(c: Context, bitmap: Bitmap?, imageUri: Uri): ExifWrapper {
|
|
var stream: InputStream? = null
|
|
try {
|
|
stream = c.getContentResolver().openInputStream(imageUri)
|
|
val exifInterface = ExifInterface(stream!!)
|
|
return ExifWrapper(exifInterface)
|
|
} catch (ex: IOException) {
|
|
Logger.error("Error loading exif data from image", ex)
|
|
} finally {
|
|
if (stream != null) {
|
|
try {
|
|
stream.close()
|
|
} catch (ignored: IOException) {
|
|
}
|
|
}
|
|
}
|
|
return ExifWrapper(null)
|
|
}
|
|
}
|