I am trying to capture photos in my app using standard camera app intent (I am NOT interested in using JetpackX or other library to have a viewfinder in my app).
When I had the code in my Fragment
like so:
// This is in response to user clicking a button
fun startPhotoTaking() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
resultLauncher.launch(takePictureIntent)
}
private var resultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val photo = result.data?.extras?.get("data") as? Bitmap
photo?.let {
// ... do whatever
}
}
}
Then the photo
Bitmap
came back tiny as apparently Android caps intents at 1 Mb , but the orientation was correct.
Since I actually need the original large image, I have modified the code like so:
// This is in response to user clicking a button
fun startPhotoTaking() {
lastUri = getTmpFileUri()
if (lastUri != null) {
resultLauncher.launch(lastUri)
}
}
private fun getTmpFileUri(): Uri {
requireContext().cacheDir.listFiles()?.forEach { it.delete() }
val tmpFile = File
.createTempFile("tmp_image_file", ".jpg", requireContext().cacheDir)
.apply {
createNewFile()
}
return FileProvider.getUriForFile(
MyApplication.instance.applicationContext,
"${BuildConfig.APPLICATION_ID}.provider",
tmpFile
)
}
var lastUri: Uri? = null
private var resultLauncher =
registerForActivityResult(ActivityResultContracts.TakePicture()) { result ->
if (result) {
val photoUri = lastUri
if (photoUri != null) {
val stream = MyApplication.instance.applicationContext.contentResolver
.openInputStream(photoUri)
val photo = BitmapFactory.decodeStream(stream)
stream?.close()
// ... do whatever
// If i try ExifInterface(photoUri.path!!)
}
}
}
Now I do receive the actual large photo, but it is always landscape :(
I tried creating an instance of ExifInterface(photoUri.path)
but that throws an exception for me (which I don't quite understand as I am only writing/reading to my own app's cache directory?):
java.io.FileNotFoundException: /cache/tmp_image_file333131952730914647.jpg: open failed: EACCES (Permission denied)
How can I get my photo to retain orientation when saved to file and/or get access to read EXIF parameters so I can rotate it myself?
Update
As a workaround, this did the trick but it's just... ungodly. So am very keen to find better solutions.
val stream = MyApplication.instance.applicationContext.contentResolver
.openInputStream(photoUri)
if (stream != null) {
val tempFile = File.createTempFile("tmp", ".jpg", requireContext().cacheDir)
.apply { createNewFile() }
val fos = FileOutputStream(tempFile)
val buf = ByteArray(8192)
var length: Int
while (stream.read(buf).also { length = it } > 0) {
fos.write(buf, 0, length)
}
fos.close()
val exif = ExifInterface(tempFile.path)
val orientation =
exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1)
val matrix = Matrix()
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
matrix.postRotate(90f)
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
matrix.postRotate(180f)
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
matrix.postRotate(270f)
var photo = BitmapFactory.decodeFile(tempFile.path)
photo = Bitmap.createBitmap(
photo,
0,
0,
photo.width,
photo.height,
matrix,
true
)
}
CodePudding user response:
ExifInterface(photoUri.path)
That isnot an existing path as you have seen.
Better use:
ExifInterface( tmpFile.getAbsolutePath())
CodePudding user response:
You can rotate image to the particular angle like this,
// To rotate image
private fun rotateImage(source: Bitmap, angle: Float): Bitmap? {
val matrix = Matrix()
matrix.postRotate(angle)
return Bitmap.createBitmap(
source, 0, 0, source.width, source.height,
matrix, true
)
}
In your case set angle to 90f to get image in portrait orientation.