如何显示使用Camerax API(Android)拍摄的图像

发布于 2025-02-13 06:57:49 字数 8144 浏览 0 评论 0原文

如何在Android中使用Camerax显示拍摄的图像。

我的情况:我有两个碎片。在其中一个片段中,我实现了摄影功能以拍摄照片并在本地保存照片。现在,我想将此图像传递给另一个片段,然后在图像视图中显示。

最好的方法应该是最好的方法(如果您可以提供有用的工作代码)

我认为

来解决此问题: 1st方法:发送从<<<<<<代码>覆盖onimagesaved (我们在imagecapture.outputfileresults中获得URI ID。但是,这几乎没有问题。使用Android Navigation将uri作为捆绑包或安全将其显示为null。这意味着在导航中没有URI转移。

第二方法:将uri转换为位图,然后将此位图发送到另一个片段。在那里解码位图将其放在imageView上。我不确定这种方法,如果您在告诉我之前已经使用过这种方法。

还有其他方法可以解决这个问题。我找不到有关此事的官方Android文档的任何文章。

摄像机片段(第一片):

class CameraFragment : Fragment() {

    private var _binding: FragmentCameraBinding? = null
    private val binding: FragmentCameraBinding get() = _binding!!

    private var imageCapture: ImageCapture? = null
    private lateinit var cameraExecutor: ExecutorService

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        _binding = FragmentCameraBinding.inflate(inflater, container, false)

        //Request Camera Permissions
        // Request camera permissions
        if (allPermissionsGranted()) {
            startCamera()
        } else {
            ActivityCompat.requestPermissions(
                requireActivity(), REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS
            )
        }
        cameraExecutor = Executors.newSingleThreadExecutor()

        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        //Setting up listeners for taking Photo
        binding.imageCaptureButton.setOnClickListener {
            takePhoto()
        }
    }

    private fun takePhoto() {
        // Get a stable reference of the modifiable image capture use case
        val imageCapture = imageCapture ?: return

        // Create time stamped name and MediaStore entry.
        val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
            .format(System.currentTimeMillis())
        val contentValues = ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME, name)
            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
                put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
            }
        }


        // Create output options object which contains file + metadata
        val outputOptions = ImageCapture.OutputFileOptions
            .Builder(
                requireContext().contentResolver,
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                contentValues
            )
            .build()

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

                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    val msg = "Photo capture succeeded: ${output.savedUri}"
                    Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
                    Timber.d(msg)


                    val uriFilePath = output.savedUri?.path
                    val path: String = uriFilePath.toString()

                    val bundle = Bundle()
                    bundle.putString("image", path)

                    Navigation.findNavController(requireView()).navigate(R.id
                        .cameraFragmentToCameraFinalFragment, bundle)
                }
            })
    }
 private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
        ContextCompat.checkSelfPermission(
            requireContext(), it
        ) == PackageManager.PERMISSION_GRANTED
    }


    private fun startCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())

        cameraProviderFuture.addListener({
            // Used to bind the lifecycle of cameras to the lifecycle owner
            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

            // Preview
            val preview = Preview.Builder()
                .build()
                .also { preview ->
                    preview.setSurfaceProvider(binding.viewFinder.surfaceProvider)
                }

            imageCapture = ImageCapture.Builder()
                .build()

            val imageAnalyzer = ImageAnalysis.Builder()
                .setTargetResolution(Size(1280, 720))
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .build()
                .also {
                    it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
                        Timber.d("Average luminosity: $luma")
                    })
                }

            // Select back camera as a default
            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

            try {
                // Unbind use cases before rebinding
                cameraProvider.unbindAll()

                // Bind use cases to camera
                cameraProvider.bindToLifecycle(
                    this, cameraSelector, preview, imageCapture, imageAnalyzer
                )

            } catch (exc: Exception) {
                Timber.e("Use case binding failed", exc)
            }

        }, ContextCompat.getMainExecutor(requireContext()))
    }

    override fun onRequestPermissionsResult(
        requestCode: Int, permissions: Array<String>, grantResults:
        IntArray
    ) {
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            if (allPermissionsGranted()) {
                startCamera()
            } else {
                Toast.makeText(
                    requireContext(), "Permissions not granted by the user.",
                    Toast.LENGTH_SHORT
                ).show()
            }
        }
    }


    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
        cameraExecutor.shutdown()
    }

    companion object {
        private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
        private const val REQUEST_CODE_PERMISSIONS = 10
        private val REQUIRED_PERMISSIONS = mutableListOf(
            Manifest.permission.CAMERA,
        ).apply {
            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
                add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
            }
        }.toTypedArray()
    }
}

photofinalfragment(第二片):

class PhotoFinalFragment : Fragment() {

    private var _binding: FragmentPhotoFinalBinding? = null
    private val binding: FragmentPhotoFinalBinding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        _binding = FragmentPhotoFinalBinding.inflate(inflater, container, false)

        val bundle: Bundle? = arguments?.getBundle("image")
        val uri: Uri = bundle?.get("image") as Uri

        binding.imageView.setImageURI(uri)

        binding.btnYes.setOnClickListener {
            Navigation.findNavController(requireView()).navigate(R.id.cameraFinalFragmentToStoryFragment)
        }

        binding.btnNo.setOnClickListener {
            Navigation.findNavController(requireView()).navigate(R.id.cameraFinalFragmentTocameraFragment)
        }
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

How to display the Image taken using CameraX in Android.

My case : I have two fragments. In one of the fragments I have implemented the CameraX functionality to take the photo and save it locally. And now I want to pass this image to an another fragment and display it there in an ImageView.

What should be the best approach for that ( and if you could provide a working code that would be helpful )

Approaches that I think of to solve this:

1st approach : Send the Uri Id that is extracted from overriding onImageSaved (we get the Uri id in ImageCapture.OutputFileResults). But there are few issues with this. Sending the Uri as bundle or safe args using Android Navigation show it as null. Which means there is no transfer of Uri across navigation.

2nd approach : Convert the uri into a bitmap and then send this bitmap to the other fragment. There decode the bitmap to put it on an ImageView. I am not sure of this approach, if you have worked with this before let me know.

Are there any other ways to tackle this issue. I can't find any article on the Official Android Docs for this thing.

Camera Fragment ( 1st Fragment ) :

class CameraFragment : Fragment() {

    private var _binding: FragmentCameraBinding? = null
    private val binding: FragmentCameraBinding get() = _binding!!

    private var imageCapture: ImageCapture? = null
    private lateinit var cameraExecutor: ExecutorService

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        _binding = FragmentCameraBinding.inflate(inflater, container, false)

        //Request Camera Permissions
        // Request camera permissions
        if (allPermissionsGranted()) {
            startCamera()
        } else {
            ActivityCompat.requestPermissions(
                requireActivity(), REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS
            )
        }
        cameraExecutor = Executors.newSingleThreadExecutor()

        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        //Setting up listeners for taking Photo
        binding.imageCaptureButton.setOnClickListener {
            takePhoto()
        }
    }

    private fun takePhoto() {
        // Get a stable reference of the modifiable image capture use case
        val imageCapture = imageCapture ?: return

        // Create time stamped name and MediaStore entry.
        val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
            .format(System.currentTimeMillis())
        val contentValues = ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME, name)
            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
                put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
            }
        }


        // Create output options object which contains file + metadata
        val outputOptions = ImageCapture.OutputFileOptions
            .Builder(
                requireContext().contentResolver,
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                contentValues
            )
            .build()

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

                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    val msg = "Photo capture succeeded: ${output.savedUri}"
                    Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
                    Timber.d(msg)


                    val uriFilePath = output.savedUri?.path
                    val path: String = uriFilePath.toString()

                    val bundle = Bundle()
                    bundle.putString("image", path)

                    Navigation.findNavController(requireView()).navigate(R.id
                        .cameraFragmentToCameraFinalFragment, bundle)
                }
            })
    }
 private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
        ContextCompat.checkSelfPermission(
            requireContext(), it
        ) == PackageManager.PERMISSION_GRANTED
    }


    private fun startCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())

        cameraProviderFuture.addListener({
            // Used to bind the lifecycle of cameras to the lifecycle owner
            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

            // Preview
            val preview = Preview.Builder()
                .build()
                .also { preview ->
                    preview.setSurfaceProvider(binding.viewFinder.surfaceProvider)
                }

            imageCapture = ImageCapture.Builder()
                .build()

            val imageAnalyzer = ImageAnalysis.Builder()
                .setTargetResolution(Size(1280, 720))
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .build()
                .also {
                    it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
                        Timber.d("Average luminosity: $luma")
                    })
                }

            // Select back camera as a default
            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

            try {
                // Unbind use cases before rebinding
                cameraProvider.unbindAll()

                // Bind use cases to camera
                cameraProvider.bindToLifecycle(
                    this, cameraSelector, preview, imageCapture, imageAnalyzer
                )

            } catch (exc: Exception) {
                Timber.e("Use case binding failed", exc)
            }

        }, ContextCompat.getMainExecutor(requireContext()))
    }

    override fun onRequestPermissionsResult(
        requestCode: Int, permissions: Array<String>, grantResults:
        IntArray
    ) {
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            if (allPermissionsGranted()) {
                startCamera()
            } else {
                Toast.makeText(
                    requireContext(), "Permissions not granted by the user.",
                    Toast.LENGTH_SHORT
                ).show()
            }
        }
    }


    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
        cameraExecutor.shutdown()
    }

    companion object {
        private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
        private const val REQUEST_CODE_PERMISSIONS = 10
        private val REQUIRED_PERMISSIONS = mutableListOf(
            Manifest.permission.CAMERA,
        ).apply {
            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
                add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
            }
        }.toTypedArray()
    }
}

PhotoFinalFragment (2nd Fragment) :

class PhotoFinalFragment : Fragment() {

    private var _binding: FragmentPhotoFinalBinding? = null
    private val binding: FragmentPhotoFinalBinding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        _binding = FragmentPhotoFinalBinding.inflate(inflater, container, false)

        val bundle: Bundle? = arguments?.getBundle("image")
        val uri: Uri = bundle?.get("image") as Uri

        binding.imageView.setImageURI(uri)

        binding.btnYes.setOnClickListener {
            Navigation.findNavController(requireView()).navigate(R.id.cameraFinalFragmentToStoryFragment)
        }

        binding.btnNo.setOnClickListener {
            Navigation.findNavController(requireView()).navigate(R.id.cameraFinalFragmentTocameraFragment)
        }
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

遇到 2025-02-20 06:57:49

使用ImageCapture.OnimageCaptrudCallback而不是ImaMeCapture.OnimagesAvedCallback

时,使用OnimageCaptredCallback(),您可以覆盖ofride oncapturesuccess,它提供可以将image -proxy转换为图像并设置为imageView的ImageProxy。

结帐

val buffer = imageProxy.planes[0].buffer
val bytes = ByteArray(buffer.capacity())
buffer[bytes]
val bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
imageProxy.close()

imageView.rotation = imageProxy.imageInfo.rotationDegrees.toFloat()
imageView.setImageBitmap(bitmapImage)

Use ImageCapture.OnImageCapturedCallback instead of ImageCapture.OnImageSavedCallback

When using OnImageCapturedCallback(), you get to override onCaptureSuccess which provides the ImageProxy which can be converted into an image and set to your ImageView.

Checkout OnImageCapturedCallback

val buffer = imageProxy.planes[0].buffer
val bytes = ByteArray(buffer.capacity())
buffer[bytes]
val bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
imageProxy.close()

imageView.rotation = imageProxy.imageInfo.rotationDegrees.toFloat()
imageView.setImageBitmap(bitmapImage)
你是我的挚爱i 2025-02-20 06:57:49
onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
    Uri selectedImageUri = outputFileResults.getSavedUri();
    Bitmap imageBitmap = BitmapUtils.loadFromUri(MainActivity.this, selectedImageUri);

    imgView.setImageBitmap(imageBitmap);
}

OnCapture成功有一个过度的方法,您可以将图像设置为从中保存。

onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
    Uri selectedImageUri = outputFileResults.getSavedUri();
    Bitmap imageBitmap = BitmapUtils.loadFromUri(MainActivity.this, selectedImageUri);

    imgView.setImageBitmap(imageBitmap);
}

oncapture success there is an overide method onimage saved from that you can set the image to.

纵山崖 2025-02-20 06:57:49

我使用相机从 MainActivity中的相机拍摄了照片。然后,在上,方法将图像URI传递到了下一个活动,然后

val i = Intent(this@MainActivity, ProcessImageActivity::class.java)
                i.putExtra("imagePath", selectedImageUri.toString())
                startActivity(i)

prcessimageactivity的on Create方法中获取URI并将其转换为位图,然后将其转换为bitmap,因为

 val imagePath = intent.getStringExtra("imagePath")
    val imageUri = Uri.parse(imagePath)
    takeImageBitmap = getBitmap(contentResolver, imageUri)!!

然后显示了bitmap as

    Column(modifier = Modifier
                .fillMaxWidth()
                .fillMaxHeight()
            ) {
                Image(
                    bitmap = takeImageBitmap.asImageBitmap(),
                    contentDescription = "Process this image",
                )
            }

getBitMmap < /em>功能代码如下

fun getBitmap(contentResolver: ContentResolver, fileUri: Uri?): Bitmap? {
    return try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            ImageDecoder.decodeBitmap(ImageDecoder.createSource(contentResolver, fileUri!!))
        } else {
            MediaStore.Images.Media.getBitmap(contentResolver, fileUri)
        }
    } catch (e: Exception){
        null
    }
}

I took picture from camera in MainActivity using cameraX. Then on onImageSaved method passed image Uri to next activity as

val i = Intent(this@MainActivity, ProcessImageActivity::class.java)
                i.putExtra("imagePath", selectedImageUri.toString())
                startActivity(i)

Then in onCreate method of PrcessImageActivity get the Uri and convert it to Bitmap as

 val imagePath = intent.getStringExtra("imagePath")
    val imageUri = Uri.parse(imagePath)
    takeImageBitmap = getBitmap(contentResolver, imageUri)!!

Then showed the bitmap as

    Column(modifier = Modifier
                .fillMaxWidth()
                .fillMaxHeight()
            ) {
                Image(
                    bitmap = takeImageBitmap.asImageBitmap(),
                    contentDescription = "Process this image",
                )
            }

getBitmap function code is following

fun getBitmap(contentResolver: ContentResolver, fileUri: Uri?): Bitmap? {
    return try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            ImageDecoder.decodeBitmap(ImageDecoder.createSource(contentResolver, fileUri!!))
        } else {
            MediaStore.Images.Media.getBitmap(contentResolver, fileUri)
        }
    } catch (e: Exception){
        null
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文