mirror of
https://github.com/SimpleMobileTools/Simple-Camera.git
synced 2025-06-27 09:02:59 +02:00
fix the rotation of images captured with Camera2 api
This commit is contained in:
@ -1,33 +0,0 @@
|
|||||||
package com.simplemobiletools.camera.extensions
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.hardware.Camera
|
|
||||||
import android.view.Surface
|
|
||||||
|
|
||||||
fun Activity.getPreviewRotation(cameraId: Int): Int {
|
|
||||||
val info = getCameraInfo(cameraId)
|
|
||||||
val degrees = getDeviceRotationDegrees()
|
|
||||||
|
|
||||||
var result: Int
|
|
||||||
if (info.facing == getMyCamera().getFrontCameraId()) {
|
|
||||||
result = (info.orientation + degrees) % 360
|
|
||||||
result = 360 - result
|
|
||||||
} else {
|
|
||||||
result = info.orientation - degrees + 360
|
|
||||||
}
|
|
||||||
|
|
||||||
return result % 360
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Activity.getDeviceRotationDegrees() = when (windowManager.defaultDisplay.rotation) {
|
|
||||||
Surface.ROTATION_90 -> 90
|
|
||||||
Surface.ROTATION_180 -> 180
|
|
||||||
Surface.ROTATION_270 -> 270
|
|
||||||
else -> 0
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getCameraInfo(cameraId: Int): Camera.CameraInfo {
|
|
||||||
val info = android.hardware.Camera.CameraInfo()
|
|
||||||
Camera.getCameraInfo(cameraId, info)
|
|
||||||
return info
|
|
||||||
}
|
|
@ -4,8 +4,6 @@ import android.content.Context
|
|||||||
import android.graphics.Point
|
import android.graphics.Point
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import com.simplemobiletools.camera.helpers.Config
|
import com.simplemobiletools.camera.helpers.Config
|
||||||
import com.simplemobiletools.camera.helpers.ORIENT_LANDSCAPE_LEFT
|
|
||||||
import com.simplemobiletools.camera.helpers.ORIENT_LANDSCAPE_RIGHT
|
|
||||||
import com.simplemobiletools.camera.implementations.MyCameraOneImpl
|
import com.simplemobiletools.camera.implementations.MyCameraOneImpl
|
||||||
import com.simplemobiletools.camera.implementations.MyCameraTwoImpl
|
import com.simplemobiletools.camera.implementations.MyCameraTwoImpl
|
||||||
import com.simplemobiletools.commons.helpers.isLollipopPlus
|
import com.simplemobiletools.commons.helpers.isLollipopPlus
|
||||||
@ -51,10 +49,3 @@ val Context.realScreenSize: Point
|
|||||||
val Context.navBarHeight: Int get() = realScreenSize.y - usableScreenSize.y
|
val Context.navBarHeight: Int get() = realScreenSize.y - usableScreenSize.y
|
||||||
|
|
||||||
fun Context.getMyCamera() = if (isLollipopPlus()) MyCameraTwoImpl(applicationContext) else MyCameraOneImpl(applicationContext)
|
fun Context.getMyCamera() = if (isLollipopPlus()) MyCameraTwoImpl(applicationContext) else MyCameraOneImpl(applicationContext)
|
||||||
|
|
||||||
fun Context.compensateDeviceRotation(orientation: Int, currCameraId: Int) = when {
|
|
||||||
orientation == ORIENT_LANDSCAPE_LEFT -> 270
|
|
||||||
orientation == ORIENT_LANDSCAPE_RIGHT -> 90
|
|
||||||
currCameraId == getMyCamera().getFrontCameraId() -> 180
|
|
||||||
else -> 0
|
|
||||||
}
|
|
||||||
|
@ -35,3 +35,10 @@ const val STATE_PICTURE_TAKEN = 2
|
|||||||
const val STATE_WAITING_LOCK = 3
|
const val STATE_WAITING_LOCK = 3
|
||||||
const val STATE_WAITING_PRECAPTURE = 4
|
const val STATE_WAITING_PRECAPTURE = 4
|
||||||
const val STATE_WAITING_NON_PRECAPTURE = 5
|
const val STATE_WAITING_NON_PRECAPTURE = 5
|
||||||
|
|
||||||
|
fun compensateDeviceRotation(orientation: Int, isUsingFrontCamera: Boolean) = when {
|
||||||
|
orientation == ORIENT_LANDSCAPE_LEFT -> 270
|
||||||
|
orientation == ORIENT_LANDSCAPE_RIGHT -> 90
|
||||||
|
isUsingFrontCamera -> 180
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
@ -9,10 +9,8 @@ import android.os.AsyncTask
|
|||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import com.simplemobiletools.camera.R
|
import com.simplemobiletools.camera.R
|
||||||
import com.simplemobiletools.camera.activities.MainActivity
|
import com.simplemobiletools.camera.activities.MainActivity
|
||||||
import com.simplemobiletools.camera.extensions.compensateDeviceRotation
|
|
||||||
import com.simplemobiletools.camera.extensions.config
|
import com.simplemobiletools.camera.extensions.config
|
||||||
import com.simplemobiletools.camera.extensions.getOutputMediaFile
|
import com.simplemobiletools.camera.extensions.getOutputMediaFile
|
||||||
import com.simplemobiletools.camera.extensions.getPreviewRotation
|
|
||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.commons.helpers.isNougatPlus
|
import com.simplemobiletools.commons.helpers.isNougatPlus
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -20,14 +18,15 @@ import java.io.FileNotFoundException
|
|||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
class PhotoProcessor(val activity: MainActivity, val uri: Uri?, val currCameraId: Int, val deviceOrientation: Int, val flipHorizontally: Boolean) : AsyncTask<ByteArray, Void, String>() {
|
class PhotoProcessor(val activity: MainActivity, val saveUri: Uri?, val currCameraId: Int, val deviceOrientation: Int, val previewRotation: Int, val isUsingFrontCamera: Boolean) :
|
||||||
|
AsyncTask<ByteArray, Void, String>() {
|
||||||
|
|
||||||
override fun doInBackground(vararg params: ByteArray): String {
|
override fun doInBackground(vararg params: ByteArray): String {
|
||||||
var fos: OutputStream? = null
|
var fos: OutputStream? = null
|
||||||
val path: String
|
val path: String
|
||||||
try {
|
try {
|
||||||
path = if (uri != null) {
|
path = if (saveUri != null) {
|
||||||
uri.path
|
saveUri.path
|
||||||
} else {
|
} else {
|
||||||
activity.getOutputMediaFile(true)
|
activity.getOutputMediaFile(true)
|
||||||
}
|
}
|
||||||
@ -61,27 +60,25 @@ class PhotoProcessor(val activity: MainActivity, val uri: Uri?, val currCameraId
|
|||||||
|
|
||||||
fos = activity.contentResolver.openOutputStream(document.uri)
|
fos = activity.contentResolver.openOutputStream(document.uri)
|
||||||
} else {
|
} else {
|
||||||
fos = if (uri == null) {
|
fos = if (saveUri == null) {
|
||||||
FileOutputStream(photoFile)
|
FileOutputStream(photoFile)
|
||||||
} else {
|
} else {
|
||||||
activity.contentResolver.openOutputStream(uri)
|
activity.contentResolver.openOutputStream(saveUri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var image = BitmapFactory.decodeByteArray(data, 0, data.size)
|
|
||||||
val exif = ExifInterface(photoFile.toString())
|
val exif = ExifInterface(photoFile.toString())
|
||||||
|
|
||||||
val deviceRot = activity.compensateDeviceRotation(deviceOrientation, currCameraId)
|
|
||||||
val previewRot = activity.getPreviewRotation(currCameraId)
|
|
||||||
val orient = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)
|
val orient = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)
|
||||||
val imageRot = orient.degreesFromOrientation()
|
val imageRot = orient.degreesFromOrientation()
|
||||||
|
|
||||||
val totalRotation = (imageRot + deviceRot + previewRot) % 360
|
val deviceRot = compensateDeviceRotation(deviceOrientation, isUsingFrontCamera)
|
||||||
|
var image = BitmapFactory.decodeByteArray(data, 0, data.size)
|
||||||
|
val totalRotation = (imageRot + deviceRot + previewRotation) % 360
|
||||||
if (activity.isPathOnSD(path) && !isNougatPlus()) {
|
if (activity.isPathOnSD(path) && !isNougatPlus()) {
|
||||||
image = rotate(image, totalRotation)
|
image = rotate(image, totalRotation)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flipHorizontally) {
|
if (isUsingFrontCamera && activity.config.flipPhotos) {
|
||||||
val matrix = Matrix()
|
val matrix = Matrix()
|
||||||
if (path.startsWith(activity.internalStoragePath)) {
|
if (path.startsWith(activity.internalStoragePath)) {
|
||||||
matrix.preScale(1f, -1f)
|
matrix.preScale(1f, -1f)
|
||||||
|
@ -15,10 +15,7 @@ import android.net.Uri
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.view.ScaleGestureDetector
|
import android.view.*
|
||||||
import android.view.SurfaceHolder
|
|
||||||
import android.view.SurfaceView
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import com.simplemobiletools.camera.R
|
import com.simplemobiletools.camera.R
|
||||||
import com.simplemobiletools.camera.activities.MainActivity
|
import com.simplemobiletools.camera.activities.MainActivity
|
||||||
import com.simplemobiletools.camera.dialogs.ChangeResolutionDialog
|
import com.simplemobiletools.camera.dialogs.ChangeResolutionDialog
|
||||||
@ -181,7 +178,7 @@ class PreviewCameraOne : ViewGroup, SurfaceHolder.Callback, MyPreview {
|
|||||||
mParameters!!.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
|
mParameters!!.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
|
||||||
}
|
}
|
||||||
|
|
||||||
mCamera!!.setDisplayOrientation(mActivity!!.getPreviewRotation(mCurrCameraId))
|
mCamera!!.setDisplayOrientation(getPreviewRotation(mCurrCameraId))
|
||||||
mParameters!!.zoom = 0
|
mParameters!!.zoom = 0
|
||||||
updateCameraParameters()
|
updateCameraParameters()
|
||||||
|
|
||||||
@ -385,10 +382,12 @@ class PreviewCameraOne : ViewGroup, SurfaceHolder.Callback, MyPreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun storePhoto(data: ByteArray) {
|
private fun storePhoto(data: ByteArray) {
|
||||||
val flipHorizontally = mActivity!!.config.flipPhotos && mCurrCameraId == mActivity!!.getMyCamera().getFrontCameraId()
|
val previewRotation = getPreviewRotation(mCurrCameraId)
|
||||||
PhotoProcessor(mActivity!!, mTargetUri, mCurrCameraId, mRotationAtCapture, flipHorizontally).execute(data)
|
PhotoProcessor(mActivity!!, mTargetUri, mCurrCameraId, mRotationAtCapture, previewRotation, getIsUsingFrontCamera()).execute(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getIsUsingFrontCamera() = mCurrCameraId == mActivity!!.getMyCamera().getFrontCameraId()
|
||||||
|
|
||||||
private fun handlePreview() {
|
private fun handlePreview() {
|
||||||
if (mConfig.isShowPreviewEnabled) {
|
if (mConfig.isShowPreviewEnabled) {
|
||||||
if (!mConfig.wasPhotoPreviewHintShown) {
|
if (!mConfig.wasPhotoPreviewHintShown) {
|
||||||
@ -802,8 +801,8 @@ class PreviewCameraOne : ViewGroup, SurfaceHolder.Callback, MyPreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getVideoRotation(): Int {
|
private fun getVideoRotation(): Int {
|
||||||
val deviceRot = mActivity!!.compensateDeviceRotation(mActivity!!.mLastHandledOrientation, mCurrCameraId)
|
val deviceRot = compensateDeviceRotation(mActivity!!.mLastHandledOrientation, getIsUsingFrontCamera())
|
||||||
val previewRot = mActivity!!.getPreviewRotation(mCurrCameraId)
|
val previewRot = getPreviewRotation(mCurrCameraId)
|
||||||
return (deviceRot + previewRot) % 360
|
return (deviceRot + previewRot) % 360
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -887,6 +886,32 @@ class PreviewCameraOne : ViewGroup, SurfaceHolder.Callback, MyPreview {
|
|||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getPreviewRotation(cameraId: Int): Int {
|
||||||
|
val info = getCameraInfo(cameraId)
|
||||||
|
val degrees = when (mActivity!!.windowManager.defaultDisplay.rotation) {
|
||||||
|
Surface.ROTATION_90 -> 90
|
||||||
|
Surface.ROTATION_180 -> 180
|
||||||
|
Surface.ROTATION_270 -> 270
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var result: Int
|
||||||
|
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
||||||
|
result = (info.orientation + degrees) % 360
|
||||||
|
result = 360 - result
|
||||||
|
} else {
|
||||||
|
result = info.orientation - degrees + 360
|
||||||
|
}
|
||||||
|
|
||||||
|
return result % 360
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCameraInfo(cameraId: Int): Camera.CameraInfo {
|
||||||
|
val info = android.hardware.Camera.CameraInfo()
|
||||||
|
Camera.getCameraInfo(cameraId, info)
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
interface PreviewListener {
|
interface PreviewListener {
|
||||||
fun setFlashAvailable(available: Boolean)
|
fun setFlashAvailable(available: Boolean)
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ import android.view.Surface
|
|||||||
import android.view.TextureView
|
import android.view.TextureView
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import com.simplemobiletools.camera.activities.MainActivity
|
import com.simplemobiletools.camera.activities.MainActivity
|
||||||
import com.simplemobiletools.camera.extensions.config
|
|
||||||
import com.simplemobiletools.camera.helpers.*
|
import com.simplemobiletools.camera.helpers.*
|
||||||
import com.simplemobiletools.camera.interfaces.MyPreview
|
import com.simplemobiletools.camera.interfaces.MyPreview
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -133,10 +132,10 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
|
|||||||
val buffer = reader.acquireNextImage().planes[0].buffer
|
val buffer = reader.acquireNextImage().planes[0].buffer
|
||||||
val bytes = ByteArray(buffer.remaining())
|
val bytes = ByteArray(buffer.remaining())
|
||||||
buffer.get(bytes)
|
buffer.get(bytes)
|
||||||
PhotoProcessor(mActivity, mTargetUri, 0, mRotationAtCapture, mActivity.config.flipPhotos && getIsFrontCamera()).execute(bytes)
|
PhotoProcessor(mActivity, mTargetUri, 0, mRotationAtCapture, mSensorOrientation, getIsUsingFrontCamera()).execute(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getIsFrontCamera(): Boolean {
|
private fun getIsUsingFrontCamera(): Boolean {
|
||||||
val manager = mActivity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
val manager = mActivity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
||||||
val characteristics = manager.getCameraCharacteristics(mCameraId)
|
val characteristics = manager.getCameraCharacteristics(mCameraId)
|
||||||
val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
|
val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
|
||||||
@ -343,6 +342,11 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
|
|||||||
unlockFocus()
|
unlockFocus()
|
||||||
mActivity.toggleBottomButtons(false)
|
mActivity.toggleBottomButtons(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCaptureFailed(session: CameraCaptureSession?, request: CaptureRequest?, failure: CaptureFailure?) {
|
||||||
|
super.onCaptureFailed(session, request, failure)
|
||||||
|
mActivity.toggleBottomButtons(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mCaptureSession!!.apply {
|
mCaptureSession!!.apply {
|
||||||
|
Reference in New Issue
Block a user