0

我正在使用CameraX https://developer.android.com/training/camerax拍摄一些图像。但是,我所有的图像都出现了错误的旋转。它们都被标记:ORIENTATION_ROTATE_90是的,我已检查以确保方向锁定未打开,并且清单中没有任何内容可以锁定屏幕方向,我也没有覆盖任何方向方法。

无论我如何通过模拟器或真实设备对其进行测试,方向似乎都被“锁定”了。唯一正确旋转的图片是设备处于纵向模式时。但是,它仍然被标记为ORIENTATION_ROTATE_90

谁能看到我可能做错了什么?

     private var imageCapture: ImageCapture? = null
    private lateinit var cameraExecutor: ExecutorService
  
  //.. other methods removed for brievity
  
   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Request camera permissions

        cameraExecutor = Executors.newSingleThreadExecutor()
    }
        override fun onResume() {
        super.onResume()

            startCamera()

    }
          
       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 {
                    it.setSurfaceProvider(binding.cameraPreview.surfaceProvider)
                }

            imageCapture = Builder().build()

            // Doesn't work
                // activity?.display.let { d ->
                // d.let {  imageCapture!!.targetRotation = d!!.rotation }
                //  }

            // 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)

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

        }, ContextCompat.getMainExecutor(requireContext()))
    }
   
    private fun captureImage() {


        // Get a stable reference of the modifiable image capture use case
        val imageCapture = imageCapture ?: return

        // this way the images will stay in order
        val id = System.currentTimeMillis().toString() 

        // Make directory if it doesn't exist, and build a file for the new image to go into
        val photoFile = File("${sharedViewModel.fileDirectory}/${id}").apply {
            @Suppress("RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
            parentFile.mkdirs()
        }

        // Create output options object which contains file + metadata
        val outputOptions = OutputFileOptions.Builder(photoFile).build()

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

                override fun onImageSaved(output: OutputFileResults) {
                    fixRotation(photoFile.path)
                }
            })


    }

    private fun fixRotation(imageUri: String) {

        val bitmap = File(imageUri)
        if (!bitmap.exists()) return

        Uri.parse(imageUri)?.let{
            CoroutineScope(Dispatchers.IO).launch { spinAndSave(it) }
        }

    }


    private suspend fun spinAndSave(imageURI: Uri) = withContext(Dispatchers.IO) {

        val options = BitmapFactory.Options()
        options.inPreferredConfig = Bitmap.Config.ARGB_8888

        imageURI.path?.let { path ->
            ExifInterface(path).getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED).let { orientation ->
                debugOrientation(orientation)
                val rotatedBitmap = rotateBitmap( BitmapFactory.decodeFile(path, options), orientation)!!
                FileOutputStream(imageURI.path).use { fos ->
                    rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos)
                    Log.i(TAG,"New Image Saved")
                }
            }
        }



    }

    private fun debugOrientation(orientation: Int) {

        val o = when (orientation) {
            ExifInterface.ORIENTATION_NORMAL -> "ORIENTATION_NORMAL"
            ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> "ORIENTATION_FLIP_HORIZONTAL"
            ExifInterface.ORIENTATION_ROTATE_180 -> "ORIENTATION_ROTATE_180"
            ExifInterface.ORIENTATION_FLIP_VERTICAL -> "ORIENTATION_FLIP_VERTICAL"
            ExifInterface.ORIENTATION_TRANSPOSE -> "ORIENTATION_TRANSPOSE"
            ExifInterface.ORIENTATION_ROTATE_90 -> "ORIENTATION_ROTATE_90"
            ExifInterface.ORIENTATION_TRANSVERSE -> "ORIENTATION_TRANSVERSE"
            ExifInterface.ORIENTATION_ROTATE_270 -> "ORIENTATION_ROTATE_270"
            else -> "UKNONWN ORIENTATION"
        }

        Log.w(TAG,"ORIEntation int: $orientation is: $o")
    }


    private fun rotateBitmap(bitmap: Bitmap, orientation: Int): Bitmap? {
        val matrix = Matrix()
        when (orientation) {
            ExifInterface.ORIENTATION_NORMAL -> return bitmap
            ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> matrix.setScale(-1f, 1f)
            ExifInterface.ORIENTATION_ROTATE_180 -> matrix.setRotate(180f)
            ExifInterface.ORIENTATION_FLIP_VERTICAL -> {
                matrix.setRotate(180f)
                matrix.postScale(-1f, 1f)
            }
            ExifInterface.ORIENTATION_TRANSPOSE -> {
                matrix.setRotate(90f)
                matrix.postScale(-1f, 1f)
            }
            ExifInterface.ORIENTATION_ROTATE_90 -> matrix.setRotate(90f)
            ExifInterface.ORIENTATION_TRANSVERSE -> {
                matrix.setRotate(-90f)
                matrix.postScale(-1f, 1f)
            }
            ExifInterface.ORIENTATION_ROTATE_270 -> matrix.setRotate(-90f)
            else -> return bitmap
        }
        return try {
            val bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
            bitmap.recycle()
            bmRotated
        } catch (e: OutOfMemoryError) {
            e.printStackTrace()
            null
        }
    }
4

1 回答 1

0

使用下面的代码来获取图像文件的 exif 和旋转。位图没有exif。

public static Bitmap rotateImage(String path) throws IOException {
    Bitmap bitmap = BitmapFactory.decodeFile(path);
    int rotate = 0;

    ExifInterface exif;
    exif = new ExifInterface(path);
    int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
            ExifInterface.ORIENTATION_NORMAL);
    switch (orientation) {
        case ExifInterface.ORIENTATION_ROTATE_270:
            rotate = 270;
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            rotate = 180;
            break;
        case ExifInterface.ORIENTATION_ROTATE_90:
            rotate = 90;
            break;
    }
    Matrix matrix = new Matrix();
    matrix.postRotate(rotate);
    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
            bitmap.getHeight(), matrix, true);
}
于 2021-10-21T10:02:34.047 回答