I am using Camera2 api to take images. I am using imageReader to capture image from a surfaceView and acquireLatestImage() to collect the image.
Images are getting captured but they are coming as null as shown by the Log.e message "Capture Completed" and "Failed to acquire captured image"
private fun onCaptureButtonClick(
captureType: String,
imageWidth: Int,
imageHeight: Int,
controlMode: Int,
cameraSettings: MutableMap<String, Any?>
) {
if (captureType == "Image") {
try {
//CaptureRequest.Builder to configure the capture request
val captureRequestBuilder =
cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
captureRequestBuilder?.addTarget(previewSurface!!)
captureRequestBuilder?.set(CaptureRequest.CONTROL_MODE, controlMode)
//ImageReader to capture the image
val imageReader = ImageReader.newInstance(imageWidth, imageHeight, ImageFormat.JPEG, 1)
Toast.makeText(applicationContext, "Imgereader Started", Toast.LENGTH_SHORT).show()
if (imageReader != null && cameraDevice != null) {
// Create a CameraCaptureSession.CaptureCallback to handle capture results
val captureCallback = object : CameraCaptureSession.CaptureCallback() {
override fun onCaptureCompleted(
session: CameraCaptureSession,
request: CaptureRequest,
result: TotalCaptureResult
) {
Log.d(TAG, "Capture completed")
super.onCaptureCompleted(session, request, result)
//image data from the ImageReader
val image = imageReader.acquireLatestImage()
if (image != null) {
//image data buffer
val buffer = image.planes[0].buffer
//buffer to a ByteArray
val imageData = ByteArray(buffer.remaining())
buffer.get(imageData)
// Save the image data to a JPEG file
val outputFile = File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"my_image.jpg"
)
try {
FileOutputStream(outputFile).use { output ->
output.write(imageData)
}
Log.d(
TAG,
"Image saved successfully: ${outputFile.absolutePath}"
)
// Update the gallery so that the image appears in the gallery app
MediaScannerConnection.scanFile(
applicationContext,
arrayOf(outputFile.absolutePath),
null,
null
)
} catch (e: IOException) {
e.printStackTrace()
} finally {
// Close the image after saving
image.close()
}
} else {
Log.e(TAG, "Failed to acquire captured image")
Toast.makeText(
applicationContext,
"Failed to acquire captured image",
Toast.LENGTH_SHORT
).show()
}
updateCameraPreview()
}
override fun onCaptureFailed(
session: CameraCaptureSession,
request: CaptureRequest,
failure: CaptureFailure
) {
super.onCaptureFailed(session, request, failure)
// Capture failed, implement your logic here
Log.d(TAG, "Capture failed")
}
}
//apture session with the configured capture request, imageReader surface, and capture callback
val surfaces = mutableListOf(previewSurface, imageReader.surface)
if (cameraCaptureSession == null) {
//new capture session if the current capture session is null
cameraDevice?.createCaptureSession(surfaces, object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
// Capture session configured successfully, get the CameraCaptureSession object
cameraCaptureSession = session
captureRequestBuilder?.build()?.let {
cameraCaptureSession?.capture(
it, captureCallback, null
)
}
}
override fun onConfigureFailed(session: CameraCaptureSession) {
// Failed to configure capture session
Log.e(TAG, "Failed to configure capture session")
}
},
null
)
} else {
// Use the existing capture session if it's already created
cameraCaptureSession?.capture(
captureRequestBuilder!!.build(),
captureCallback,
null
)
}
} else {
Log.e(TAG, "Failed to create ImageReader or CameraDevice is null")
}
} catch (e: CameraAccessException) {
e.printStackTrace()
}
} else {
}
}
I am calling the with a button click
btnCapture.setOnClickListener { onCaptureButtonClick(captureType, imageWidth, (aspectRatio*imageWidth),controlMode, cameraSettings) }
I already tried with different heights and width values. Got the accepted sizes using
try {
val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId)
val maxImageSize = cameraCharacteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP
)?.getOutputSizes(ImageFormat.JPEG)?.maxByOrNull { it.height * it.width }
val minImageSize = cameraCharacteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP
)?.getOutputSizes(ImageFormat.JPEG)?.minByOrNull { it.height * it.width }
if (maxImageSize != null) {
val maxWidth = maxImageSize.width
val maxHeight = maxImageSize.height
Log.d(TAG, "Max Image Size: $maxWidth x $maxHeight")
}
if (minImageSize != null) {
val minWidth = minImageSize.width
val minHeight = minImageSize.height
Log.d(TAG, "Min Image Size: $minWidth x $minHeight")
}
} catch (e: CameraAccessException) {
e.printStackTrace()
}
Any help is appreciated.