Home > Software engineering >  Android CameraX image capture onImageSaved never runs
Android CameraX image capture onImageSaved never runs

Time:12-02

I'm following along with some camerax tutorials, and I'm trying to get the image capture & saving working, however the 'onImageSaved' function is never called, and even though I can get a Uri for the image location, it points to nothing. I've spent hours trying to debug this and can't figure out what's gone wrong. I've tried checking file access permissions, that's not the problem.

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(externalMediaDirs[0],"JPEG_${System.currentTimeMillis()}.jpg")
    val directory: File = applicationContext.getDir("imageDir", Context.MODE_PRIVATE)
    val photoFile = File(directory, "JPEG_${System.currentTimeMillis()}.jpg")

    // Create output options object which contains file   metadata
    val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
    
    // Convert filepath to Uri
    val imageUri = Uri.fromFile(photoFile)

    // Set up image capture listener, which is triggered after photo has been taken
    imageCapture.takePicture(
        outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
            override fun onError(exc: ImageCaptureException) {
                Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
            }

            override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                // TODO This never runs
                val msg = "Photo capture succeeded: $imageUri"
                Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
                Log.d(TAG, msg)
            }
        })

    // Send our image Uri back to the demo app & finish this activity
    val intent = Intent()
    intent.putExtra("ImageUri", imageUri)
    runOnUiThread {
        setResult(2, intent)
        finish()
    }
}

CodePudding user response:

First capture image

 imageCapture.takePicture(ContextCompat.getMainExecutor(requireContext()),object :
        ImageCapture.OnImageCapturedCallback() {
        override fun onCaptureSuccess(image: ImageProxy) {
            super.onCaptureSuccess(image)
            val bitmap =imageProxyToBitmap(image)
            val file  = bitmap?.let {
                AppUtils.saveImage(requireContext(),
                    it,SimpleDateFormat(CameraFragment.FILENAME_FORMAT, 
                 Locale.US).format(System.currentTimeMillis())   ".png")
            }
            val savedUri = Uri.fromFile(file)

            if (savedUri != null) {
              // here your save image uri path 
            }

        }

        override fun onError(exception: ImageCaptureException) {
            super.onError(exception)

        }

    })

Create a function for imageProxyToBitmap

 private fun imageProxyToBitmap(image: ImageProxy): Bitmap {
    val planeProxy = image.planes[0]
    val buffer: ByteBuffer = planeProxy.buffer
    val bytes = ByteArray(buffer.remaining())
    buffer.get(bytes)
    return BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
}

Than create saveImage class in util or any where you want

  @Throws(IOException::class)
 fun saveImage(context: Context,bitmap: Bitmap,  name: String): File? {
    val saved: Boolean
    var image : File?=null
    val fos: OutputStream? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        val resolver: ContentResolver = context.contentResolver
        val contentValues = ContentValues()
        contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, name)
        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
        contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/")
        val imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
        image =File(imageUri?.let { FileUriUtils.getRealPath(context, uri = it) })
        imageUri?.let { resolver.openOutputStream(it) }
    } else {
        val imagesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString()   File.separator
        val file = File(imagesDir)
        if (!file.exists()) {
            file.mkdir()
        }

        image = File(imagesDir, "$name.png")
        FileOutputStream(image)
    }
    saved = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
    fos?.flush()
    fos?.close()

    return image
}
  • Related