takePicture требует исполнителя на CameraX (1.0.0-alpha06) - PullRequest
4 голосов
/ 14 октября 2019

После обновления с

androidx.camera:camera-core:1.0.0-alpha03

до

androidx.camera:camera-core:1.0.0-alpha06

подписи методов setTargetAspectRatio (в ImageCaptureConfig.Builder) и takePicture (в ImageCapture) были изменены.

Официальная документация и информация в Интернете не показывают, как использовать новые методы (как указать исполнителя).

Код, который сломался после обновления:

...
val captureConfig = ImageCaptureConfig.Builder()
    .setTargetAspectRatioCustom(Rational(1, 1)) //this method changed
    .setFlashMode(flashMode)
    .setLensFacing(lensFacing)
    .build()

val capture = ImageCapture(captureConfig)

binding.takeAPhoto.setOnClickListener {
    ...
    val imageFile = createTempFile(System.currentTimeMillis().toString(), ".jpg")
    capture.takePicture(imageFile, object : ImageCapture.OnImageSavedListener { //this method also changed

        override fun onImageSaved(file: File) {
            ...
        }

        override fun onError(useCaseError: ImageCapture.UseCaseError, message: String, cause: Throwable?) {
            ...
        })
    }
}

Кто-нибудь имеет (или знает)где найти) пример использования новых методов? Заранее спасибо

Ответы [ 5 ]

5 голосов
/ 25 октября 2019

Официальные Google Codelabs, которые, очевидно, были недавно обновлены, используют: Executors.newSingleThreadExecutor()

Ссылка: https://codelabs.developers.google.com/codelabs/camerax-getting-started/#4

Редактировать: После ответа @ kos такжеимеет смысл для меня, я добавил эти две официальные ссылки на документы для Android:

https://developer.android.com/reference/java/util/concurrent/Executors.html#newSingleThreadExecutor()

https://developer.android.com/reference/java/util/concurrent/Executors.html#newCachedThreadPool()

Таким образом, каждый читатель этой темы может составитьего / ее собственный разум по отношению к исполнителям.

1 голос
/ 15 октября 2019

Вы можете сделать это так.

imageCapture.takePicture(file, { it.run() }, object : ImageCapture.OnImageSavedListener {
    override fun onImageSaved(file: File) {}
    override fun onError(useCaseError: ImageCapture.ImageCaptureError, message: String, cause: Throwable?) {}
})
1 голос
/ 14 октября 2019

Я столкнулся с тем же, что и вы. Я решил это со своей стороны.

class MainActivity : AppCompatActivity(), Executor {
    private var right: Int = 0
    private var bottom: Int = 0
    private var left: Int = 0
    private var top: Int = 0
    private lateinit var preview: Preview
    private val REQUEST_CODE_PERMISSIONS = 10
    private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
    private lateinit var imageCapture: ImageCapture
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        if (allPermissionsGranted()) {
            viewFinder.post { startCamera() }
        } else {
            ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
        }

        viewFinder.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
            updateTransform()
        }

        buttonPlus.setOnClickListener {
            if (right < 100) {
                right += 100
                bottom += 100
                left += 100
                top += 100
                val my = Rect(left, top, right, bottom)
                preview.zoom(my)
            }
        }

        buttonMinus.setOnClickListener {
            if (right > 0) {
                right -= 100
                bottom -= 100
                left -= 100
                top -= 100
                val my = Rect(left, top, right, bottom)
                preview.zoom(my)
            }
        }
    }

    @SuppressLint("RestrictedApi")
    private fun startCamera() {
        val metrics = DisplayMetrics().also { viewFinder.display.getRealMetrics(it) }
        val screenAspectRatio = Rational(metrics.widthPixels, metrics.heightPixels)
        val previewConfig = PreviewConfig.Builder().apply {
            setTargetAspectRatioCustom(screenAspectRatio)
            setTargetRotation(viewFinder.display.rotation)
        }.build()
        preview = Preview(previewConfig)
        preview.setOnPreviewOutputUpdateListener {
            val parent = viewFinder.parent as ViewGroup
            parent.removeView(viewFinder)
            parent.addView(viewFinder, 0)
            viewFinder.surfaceTexture = it.surfaceTexture
            updateTransform()
        }
        CameraX.bindToLifecycle(this, preview)

        captureImage()
    }

    @SuppressLint("RestrictedApi")
    private fun captureImage() {
        val imageCaptureConfig = ImageCaptureConfig.Builder()
                .apply {
                    setTargetAspectRatioCustom(Rational(1, 1))
                    setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
                }.build()
        imageCapture = ImageCapture(imageCaptureConfig)
        CameraX.bindToLifecycle(this, imageCapture)
        capture_button.setOnClickListener {
            val file = File(this.externalMediaDirs.first(), "${System.currentTimeMillis()}.jpg")
            imageCapture.takePicture(file, this, object : ImageCapture.OnImageSavedListener {
                override fun onImageSaved(file: File) {
                    val msg = "Photo capture succeeded: ${file.absolutePath}"
                    Log.d("CameraXApp", msg)
                }

                override fun onError(imageCaptureError: ImageCapture.ImageCaptureError, message: String, cause: Throwable?) {
                    val msg = "Photo capture failed: $message"
                    Log.e("CameraXApp", msg)
                    cause?.printStackTrace()
                }
            })
        }
    }

    override fun execute(command: Runnable) {
        command.run()
    }

    private fun updateTransform() {
        val matrix = Matrix()
        val centerX = viewFinder.width / 2f
        val centerY = viewFinder.height / 2f
        val rotationDegrees = when (viewFinder.display.rotation) {
            Surface.ROTATION_0 -> 0
            Surface.ROTATION_90 -> 90
            Surface.ROTATION_180 -> 180
            Surface.ROTATION_270 -> 270
            else -> return
        }
        matrix.postRotate(-rotationDegrees.toFloat(), centerX, centerY)
        viewFinder.setTransform(matrix)
    }

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

    private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
        ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
    }


    override fun onDestroy() {
        super.onDestroy()
        imageCapture.let {
            CameraX.unbind(imageCapture)
        }
    }
}

И вывод (Как я печатаю журнал в методе onImageSaved)

Photo capture succeeded: /storage/emulated/0/Android/media/com.akshay.cameraxzoominoutdemo/1571052301192.jpg

Это работает нормально для меня, попробуйте это.

0 голосов
/ 29 октября 2019

Вот журнал изменений для изменений в alpha06: https://developer.android.com/jetpack/androidx/releases/camera

  • setTargetAspectRatio() метод теперь принимает AspectRatio перечисление со значением 4_3 или 16_9.
  • takePicture() метод принимает (file, metadata, executor, imageSavedListener) // может использовать executor в соответствии с вашими потребностями / потребностями. Например, val executor = Executors.newSingleThreadExecutor()
  • вместо useCase.onPreviewOutputUpdateListener = используйте useCase.setOnPreviewOutputUpdateListener()

К вашему сведению: CameraX будет в бета-версии в декабре 2019

0 голосов
/ 20 октября 2019

CameraX имеет встроенные исполнители, и снимок может быть реализован следующим образом:

imgCaptureButton.setOnClickListener(new View.OnClickListener() {
    @Override
    @SuppressLint("RestrictedApi")
    public void onClick(View v) {
        imgCap.takePicture(CameraXExecutors.mainThreadExecutor(),new ImageCapture.OnImageCapturedListener() {
            @Override
            public void onCaptureSuccess(ImageProxy image, int rotationDegrees) {
                super.onCaptureSuccess(image, rotationDegrees);

                // Play with the Image here.
            }
        });
    }
});

Он не использует файл для сохранения изображения, вместо этого сохраняет изображение как буфер в памяти.

...