Reputation: 13803
I am new in using camera X library. I am trying to follow the codelab from Google in here
I can show the preview and capture the image. but the problem is ......
when I capture the image in landscape, the image result will be still in portrait. I want to make it automatically rotate. if I take the image in landscape then the result should be in landscape, and if I take it in portrait then the result should be in portrait. like the camera in 'Camera' app
how to do that ?
I am using Redmi Note 7, Android 10.
the gradle I use:
implementation "androidx.camera:camera-camera2:1.0.0-beta11"
implementation "androidx.camera:camera-lifecycle:1.0.0-beta11"
implementation "androidx.camera:camera-view:1.0.0-alpha18"
here is my code to show the preview and to capture the image
class CameraFragment : Fragment() {
private var imageCapture: ImageCapture? = null
private lateinit var outputDirectory: File
private lateinit var cameraExecutor: ExecutorService
private var cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
companion object {
private const val TAG = "CameraFragment"
private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
private const val CAMERA_REQUEST_CODE_PERMISSIONS = 10
}
lateinit var mContext : Context
lateinit var mActivity : FragmentActivity
override fun onAttach(context: Context) {
super.onAttach(context)
mContext = context
activity?.let { mActivity = it }
}
private fun getOutputDirectory(): File {
val mediaDir = mActivity.externalMediaDirs.firstOrNull()?.let {
File(it, resources.getString(R.string.app_name)).apply { mkdirs() }
}
return if (mediaDir != null && mediaDir.exists())
mediaDir else mActivity.filesDir
}
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(mContext)
cameraProviderFuture.addListener(Runnable {
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview
val preview = Preview.Builder()
.build()
.also {
it.setSurfaceProvider(previewView.surfaceProvider)
}
imageCapture = ImageCapture.Builder().build()
try {
// Unbind use cases before rebinding
cameraProvider.unbindAll()
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture)
} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(mContext))
}
private fun takePhoto() {
// Get a stable reference of the modifiable image capture use case
val imageCapture = imageCapture ?: return
// Create time-stamped output file to hold the image
val photoFile = File(
outputDirectory,
SimpleDateFormat(FILENAME_FORMAT, Locale.US
).format(System.currentTimeMillis()) + ".jpg")
// Create output options object which contains file + metadata
val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
// Set up image capture listener, which is triggered after photo has
// been taken
imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(mContext), object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Log.d("agungxxx", "2: ${exc.localizedMessage}")
Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
}
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
cameraSharedViewModel.sendImageUriPathToPreviousDestination(photoFile)
findNavController().navigateUp()
}
})
}
}
Upvotes: 1
Views: 1390
Reputation: 4570
The rotation of the captured image depends on the target rotation of the ImageCapture
use case. By default, when it isn't set by the application, it is equal to Display.getRotation()
, where Display
is the default display at the time the ImageCapture
use case is created.
This means that you need to updated the ImageCapture
's target rotation every time the display's orientation changes, e.g. when the device is physically rotated from portrait to landscape.
I'm assuming your activity has a locked orientation (?). In this case, you can use an OrientationEventListener
to continuously get updates on the device's rotation, and then update the use case's target rotation accordingly.
val orientationEventListener = object : OrientationEventListener(this) {
override fun onOrientationChanged(orientation: Int) {
if (orientation == OrientationEventListener.UNKNOWN_ORIENTATION) {
return
}
val rotation = when (orientation) {
in 45 until 135 -> Surface.ROTATION_270
in 135 until 225 -> Surface.ROTATION_180
in 225 until 315 -> Surface.ROTATION_90
else -> Surface.ROTATION_0
}
imageCapture.targetRotation = rotation
}
}
You should start/stop the orientationEventListener
when the Activity's lifecycle is started/stopped, this also matches when the camera's started/stopped. You can see an example of this here.
You can also learn more about CameraX's use cases and rotation in the official documentation.
Upvotes: 2