I've succesfully capture image with CameraX into JPEG files. The problem is the file size is big. On an Android powered walki talkie (Android 11), the result is typically 4 to 6 MB, so I'd like to resize it.
Here's my code:
fun takePhoto() {
val FILENAME_FORMAT = "ddMMyyyy_HHmmss"
val capturedContentValues = ContentValues()
capturedContentValues.put(MediaStore.MediaColumns.DISPLAY_NAME,
"CARAKA_"+SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(System.currentTimeMillis()))
capturedContentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM+"/TESTAPP")
capturedContentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
val outputOptions= ImageCapture.OutputFileOptions.Builder(
context.contentResolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
capturedContentValues
).build()
imageCapture.takePicture(
outputOptions,
ContextCompat.getMainExecutor(context),
object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Toast.makeText(context,"Photo capture failed: ${exc.message}", Toast.LENGTH_SHORT).show()
}
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
val theFile = getFile(context, output.savedUri!!)
val capturedBitmap = BitmapFactory.decodeFile(theFile!!.absolutePath)
val resizedBitmap = getResizedBitmap(capturedBitmap, 1024)
val fout = FileOutputStream(theFile.absolutePath)
resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fout)
fout.flush()
fout.close()
}
})
}
fun getResizedBitmap(image: Bitmap, maxSize: Int): Bitmap {
var width = image.width
var height = image.height
val bitmapRatio = width.toFloat() / height.toFloat()
if (bitmapRatio > 1) {
width = maxSize
height = (width / bitmapRatio).toInt()
} else {
height = maxSize
width = (height * bitmapRatio).toInt()
}
return Bitmap.createScaledBitmap(image, width, height, true)
}
@Throws(IOException::class)
fun getFile(context: Context, uri: Uri): File? {
val destinationFilename =
File(context.filesDir.path + File.separatorChar + queryName(context, uri))
try {
context.contentResolver.openInputStream(uri).use { ins ->
createFileFromStream(
ins!!,
destinationFilename
)
}
} catch (ex: java.lang.Exception) {
Log.e("Save File", ex.message!!)
ex.printStackTrace()
}
return destinationFilename
}
fun createFileFromStream(ins: InputStream, destination: File?) {
try {
FileOutputStream(destination).use { os ->
val buffer = ByteArray(4096)
var length: Int
while (ins.read(buffer).also { length = it } > 0) {
os.write(buffer, 0, length)
}
os.flush()
}
} catch (ex: java.lang.Exception) {
Log.e("Save File", ex.message!!)
ex.printStackTrace()
}
}
private fun queryName(context: Context, uri: Uri): String {
val returnCursor: Cursor = context.contentResolver.query(uri, null, null, null, null)!!
val nameIndex: Int = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
returnCursor.moveToFirst()
val name: String = returnCursor.getString(nameIndex)
returnCursor.close()
return name
}
Those saved JPEGs size is still within 4 to 6 MB. Not reduced into hundreds KB. What's wrong here?
Instead of resizing it afterwards, another thing you can try is taking a smaller picture. You can set the target resolution to be lower: https://developer.android.com/reference/androidx/camera/core/ImageCapture.Builder#setTargetResolution(android.util.Size)