Search code examples
androidkotlinandroid-cameraandroid-camera2

White image when clicking image using Camera2 API Kotlin


We are using Camera2 API for image capturing in our code and we are getting the white images in Samsung device whenever we are capturing images with the flash mode ON.

Below is the code snipset for capturing photo:

private val captureCallback = object : CameraCaptureSession.CaptureCallback() {
    override fun onCaptureCompleted(
        session: CameraCaptureSession,
        request: CaptureRequest,
        result: TotalCaptureResult
    ) {
        if (result != null) {
            process(result)
        }
    }

    private fun process(result: CaptureResult) {
        try {
            if (locked) return

            /* Wait for all states to be ready, if they are not ready repeat basic capture while camera is preparing for capture */
            if (result.isLocked() || captureTimes > MAX_CAPTURE_TIMES) {
                /* Take picture */
                locked = true
                capture()
            } else {
                /* Wait while camera is preparing */
                captureTimes++
                session?.capture(sessionBuilder?.build()!!, this, AsyncUtils.backgroundHandler)
            }
        } catch (t: Throwable) {
            pictureCallback?.onError(t)
        }
    }

    private fun capture() {
        cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE).apply {
            copyParamsFrom(sessionBuilder)
            /* Set picture quality */
            set(CaptureRequest.JPEG_QUALITY, config.pictureQuality.toByte())
            set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_START)
            /* Add surface target that will receive capture */
            addTarget(imageReader?.surface!!)
            session?.apply {
                /* Freeze preview session */
                abortCaptures()
                stopRepeating()
                /* Take dat picture */
                capture(build(), null, AsyncUtils.backgroundHandler)
            }
        }
    }
}

We are using Camera2 API for image capturing in our code and we are getting the white images in Samsung device whenever we are capturing images with the flash mode ON.

Below is the code snipset for capturing photo:

private val stateCallback = object : CameraCaptureSession.StateCallback() {
    override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {
        session = cameraCaptureSession
        try {
            sessionBuilder =
                cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW).apply {
                    applyConfig(config)
                    addTarget(surface!!)
                }
            startSession()
            initCallback?.onActive()
            initCallback = null
        } catch (t: Throwable) {
            initCallback?.onError(t)
            initCallback = null
        }
    }

    override fun onConfigureFailed(cameraCaptureSession: CameraCaptureSession) {
        initCallback?.onError(CameraConfigurationFailedException)
        initCallback = null
    }
}

fun createInitialPreviewSession(textureView: TextureView, callback: InitCallback) {
    this.initCallback = callback
    createSession(textureView)
}

override fun createSession(textureView: TextureView) {
    try {
        initTextureViewSurface(textureView)
        initImageReader()
        cameraDevice.createCaptureSession(
            listOf(surface, imageReader?.surface),
            stateCallback,
            AsyncUtils.backgroundHandler
        )
    } catch (t: Throwable) {
        initCallback?.onError(t)
        initCallback = null
    }
}

We are using Camera2 API for image capturing in our code and we are getting the white images in Samsung device whenever we are capturing images with the flash mode ON.

Below is the code snipset for capturing photo:

private fun initImageReader() {
    this.imageReader = ImageReader.newInstance(
        config.pictureSize.width,
        config.pictureSize.height,
        ImageFormat.JPEG,
        2
    )
    imageReader?.setOnImageAvailableListener({ reader ->
        async(
            task = {
                val image = reader.acquireLatestImage()
                val bitmap = image.toBitmap()
                image.close()
                if (bitmap != null) {
                    val orientationDifference =
                        CameraUtils.calculateDisplayOrientation(activity, config).toFloat()
                    pictureTransformation?.transform(bitmap, config, orientationDifference)
                        ?: bitmap
                } else {
                    null
                }
            },
            onResult = {
                locked = false
                unlockFocus(config.focusMode)
                if (it != null) {
                    pictureCallback?.onPictureTaken(it)
                } else {
                    pictureCallback?.onError(PictureConversionException)
                }
            }
        )
    }, AsyncUtils.backgroundHandler)
}

fun takePicture(callback: PictureCallback) {
    captureTimes = 0
    this.pictureCallback = callback
    sessionBuilder?.apply {
        /* Trigger AF and AE */
        if (config.focusMode in arrayOf(
                FocusMode.AUTO,
                FocusMode.CONTINUOUS_PICTURE,
                FocusMode.CONTINUOUS_VIDEO
            )
        ) {
            set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
            focusCenterIfUnfocused()
        }
        if (config.isHardwareAtLeastLimited()) {
            set(
                CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
                CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START
            )
        }
        session?.capture(build(), captureCallback, AsyncUtils.backgroundHandler)
        if (config.isHardwareAtLeastLimited()) {
            set(
                CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
                CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
            )
        }
    }
}

private fun focusCenterIfUnfocused() {
    if (isFocused()) return

    val activeRect =
        config.characteristics?.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE)
            ?: return
    val centerX = activeRect.width() / 2
    val centerY = activeRect.height() / 2
    val offsetX = (activeRect.width() * 0.1f).toInt()
    val offsetY = (activeRect.height() * 0.1f).toInt()
    val centerRegion = Rect(
        max(centerX - offsetX, 0),
        max(centerY - offsetY, 0),
        min(centerX + offsetX, activeRect.width()),
        min(centerY + offsetY, activeRect.height())
    )
    sessionBuilder?.set(
        CaptureRequest.CONTROL_AF_REGIONS,
        arrayOf(MeteringRectangle(centerRegion, MeteringRectangle.METERING_WEIGHT_MAX - 1))
    )
}

private fun isFocused(): Boolean {
    val regions = sessionBuilder?.get(CaptureRequest.CONTROL_AF_REGIONS)
    val focusedRegion = regions?.getOrNull(0)
    return focusedRegion?.meteringWeight == MeteringRectangle.METERING_WEIGHT_MAX - 1
}

override fun release() {
    super.release()
    surface = null
    pictureCallback = null
    initCallback = null
    try {
        imageReader?.close()
    } catch (t: Throwable) {
    } finally {
        imageReader = null
    }
}

Solution

  • You have three different code snippets that don't seem to go together at all.

    But take a look at https://github.com/googlearchive/android-Camera2Basic/blob/master/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java for a sample of flash capture.