Centralize JPEG compression to a single function
This commit is contained in:
@@ -108,17 +108,7 @@ fun decodeJpeg(jpegBytes: ByteArray): Mat? {
|
||||
}
|
||||
|
||||
fun encodeJpeg(mat: Mat, jpegQuality: Int): ByteArray? {
|
||||
val params = MatOfInt(Imgcodecs.IMWRITE_JPEG_QUALITY, jpegQuality.coerceIn(0, 100))
|
||||
val encoded = MatOfByte()
|
||||
val ok = Imgcodecs.imencode(".jpg", mat, encoded, params)
|
||||
params.release()
|
||||
|
||||
if (!ok) {
|
||||
encoded.release()
|
||||
return null
|
||||
}
|
||||
|
||||
val result = encoded.toArray()
|
||||
encoded.release()
|
||||
return result
|
||||
return runCatching {
|
||||
org.fairscan.imageprocessing.encodeJpeg(mat, jpegQuality)
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
@@ -14,45 +14,55 @@
|
||||
*/
|
||||
package org.fairscan.app.platform
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import androidx.core.graphics.scale
|
||||
import org.fairscan.app.data.ImageTransformations
|
||||
import org.opencv.core.MatOfInt
|
||||
import org.fairscan.imageprocessing.encodeJpeg
|
||||
import org.opencv.core.Mat
|
||||
import org.opencv.core.Size
|
||||
import org.opencv.imgcodecs.Imgcodecs
|
||||
import org.opencv.imgproc.Imgproc
|
||||
import java.io.File
|
||||
import kotlin.math.min
|
||||
|
||||
class OpenCvTransformations : ImageTransformations {
|
||||
|
||||
override fun rotate(
|
||||
inputFile: File,
|
||||
outputFile: File,
|
||||
rotationDegrees: Int,
|
||||
jpegQuality: Int
|
||||
) {
|
||||
val src = Imgcodecs.imread(inputFile.absolutePath)
|
||||
require(!src.empty()) { "Could not load image from ${inputFile.absolutePath}" }
|
||||
|
||||
val dst = org.fairscan.imageprocessing.rotate(src, rotationDegrees)
|
||||
|
||||
val params = MatOfInt(Imgcodecs.IMWRITE_JPEG_QUALITY, jpegQuality)
|
||||
if (!Imgcodecs.imwrite(outputFile.absolutePath, dst, params)) {
|
||||
throw RuntimeException("Could not write image to ${outputFile.absolutePath}")
|
||||
transform(inputFile, outputFile, jpegQuality) {
|
||||
org.fairscan.imageprocessing.rotate(it, rotationDegrees)
|
||||
}
|
||||
|
||||
params.release()
|
||||
src.release()
|
||||
dst.release()
|
||||
}
|
||||
|
||||
override fun resize(inputFile: File, outputFile: File, maxSize: Int) {
|
||||
val bitmap = BitmapFactory.decodeFile(inputFile.absolutePath)
|
||||
val ratio = min(maxSize.toFloat() / bitmap.width, maxSize.toFloat() / bitmap.height)
|
||||
val newW = (bitmap.width * ratio).toInt()
|
||||
val newH = (bitmap.height * ratio).toInt()
|
||||
val scaled = bitmap.scale(newW, newH)
|
||||
outputFile.outputStream().use {
|
||||
scaled.compress(Bitmap.CompressFormat.JPEG, 85, it)
|
||||
transform(inputFile, outputFile, 85) { src ->
|
||||
val ratio = min(maxSize.toFloat() / src.width(), maxSize.toFloat() / src.height())
|
||||
val newW = (src.width() * ratio).toDouble()
|
||||
val newH = (src.height() * ratio).toDouble()
|
||||
val scaled = Mat()
|
||||
Imgproc.resize(src, scaled, Size(newW, newH))
|
||||
scaled
|
||||
}
|
||||
}
|
||||
|
||||
private fun transform(
|
||||
inputFile: File,
|
||||
outputFile: File,
|
||||
jpegQuality: Int,
|
||||
transform: (Mat) -> Mat,
|
||||
) {
|
||||
val input = Imgcodecs.imread(inputFile.absolutePath)
|
||||
var output: Mat? = null
|
||||
try {
|
||||
require(!input.empty()) { "Could not load image from ${inputFile.absolutePath}" }
|
||||
output = transform.invoke(input)
|
||||
val outputBytes = encodeJpeg(output, jpegQuality)
|
||||
outputFile.writeBytes(outputBytes)
|
||||
} finally {
|
||||
input.release()
|
||||
output?.release()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,12 @@
|
||||
package org.fairscan.imageprocessing
|
||||
|
||||
import org.opencv.core.Mat
|
||||
import org.opencv.core.MatOfByte
|
||||
import org.opencv.core.MatOfInt
|
||||
import org.opencv.core.Size
|
||||
import org.opencv.imgcodecs.Imgcodecs
|
||||
import org.opencv.imgproc.Imgproc
|
||||
import java.io.IOException
|
||||
import kotlin.math.sqrt
|
||||
|
||||
fun resizeForMaxPixels(img: Mat, maxPixels: Double): Mat {
|
||||
@@ -30,3 +34,19 @@ fun resizeForMaxPixels(img: Mat, maxPixels: Double): Mat {
|
||||
Imgproc.resize(img, resizedImg, size, 0.0, 0.0, Imgproc.INTER_AREA)
|
||||
return resizedImg
|
||||
}
|
||||
|
||||
fun encodeJpeg(mat: Mat, jpegQuality: Int): ByteArray {
|
||||
val params = MatOfInt(Imgcodecs.IMWRITE_JPEG_QUALITY, jpegQuality.coerceIn(0, 100))
|
||||
val encoded = MatOfByte()
|
||||
val ok = Imgcodecs.imencode(".jpg", mat, encoded, params)
|
||||
params.release()
|
||||
|
||||
if (!ok) {
|
||||
encoded.release()
|
||||
throw IOException("Failed to encode JPEG")
|
||||
}
|
||||
|
||||
val result = encoded.toArray()
|
||||
encoded.release()
|
||||
return result
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user