- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已经为 CameraX kotlin 更新了我的 gradle 插件,突然间我遇到了一个我不知道如何修复的错误。
这是我的相机 fragment
package com.khumomashapa.notes.fragments
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.res.Configuration
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.hardware.display.DisplayManager
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.DisplayMetrics
import android.util.Log
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.MimeTypeMap
import android.widget.ImageButton
import androidx.camera.core.AspectRatio
import androidx.camera.core.Camera
import androidx.camera.core.CameraInfoUnavailableException
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCapture.Metadata
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.ImageProxy
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.net.toFile
import androidx.core.view.setPadding
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.navigation.Navigation
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.khumomashapa.notes.R
import com.khumomashapa.notes.activities.CameraActivity
import com.khumomashapa.notes.activities.KEY_EVENT_ACTION
import com.khumomashapa.notes.activities.KEY_EVENT_EXTRA
import com.khumomashapa.notes.utils.ANIMATION_FAST_MILLIS
import com.khumomashapa.notes.utils.ANIMATION_SLOW_MILLIS
import com.khumomashapa.notes.utils.simulateClick
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
import java.nio.ByteBuffer
import java.text.SimpleDateFormat
import java.util.ArrayDeque
import java.util.Locale
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.collections.ArrayList
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
/** Helper type alias used for analysis use case callbacks */
typealias LumaListener = (luma: Double) -> Unit
/**
* Main fragment for this app. Implements all camera operations including:
* - Viewfinder
* - Photo taking
* - Image analysis
*/
class CameraFragment : Fragment() {
private lateinit var container: ConstraintLayout
private lateinit var viewFinder: PreviewView
private lateinit var outputDirectory: File
private lateinit var broadcastManager: LocalBroadcastManager
private var displayId: Int = -1
private var lensFacing: Int = CameraSelector.LENS_FACING_BACK
private var preview: Preview? = null
private var imageCapture: ImageCapture? = null
private var imageAnalyzer: ImageAnalysis? = null
private var camera: Camera? = null
private var cameraProvider: ProcessCameraProvider? = null
private val displayManager by lazy {
requireContext().getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
}
/** Blocking camera operations are performed using this executor */
private lateinit var cameraExecutor: ExecutorService
/** Volume down button receiver used to trigger shutter */
private val volumeDownReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.getIntExtra(KEY_EVENT_EXTRA, KeyEvent.KEYCODE_UNKNOWN)) {
// When the volume down button is pressed, simulate a shutter button click
KeyEvent.KEYCODE_VOLUME_DOWN -> {
val shutter = container
.findViewById<ImageButton>(R.id.camera_capture_button)
shutter.simulateClick()
}
}
}
}
/**
* We need a display listener for orientation changes that do not trigger a configuration
* change, for example if we choose to override config change in manifest or for 180-degree
* orientation changes.
*/
private val displayListener = object : DisplayManager.DisplayListener {
override fun onDisplayAdded(displayId: Int) = Unit
override fun onDisplayRemoved(displayId: Int) = Unit
override fun onDisplayChanged(displayId: Int) = view?.let { view ->
if (displayId == this@CameraFragment.displayId) {
Log.d(TAG, "Rotation changed: ${view.display.rotation}")
imageCapture?.targetRotation = view.display.rotation
imageAnalyzer?.targetRotation = view.display.rotation
}
} ?: Unit
}
override fun onResume() {
super.onResume()
// Make sure that all permissions are still present, since the
// user could have removed them while the app was in paused state.
if (!PermissionsFragment.hasPermissions(requireContext())) {
Navigation.findNavController(requireActivity(), R.id.fragment_container).navigate(
CameraFragmentDirections.actionCameraToPermissions()
)
}
}
override fun onDestroyView() {
super.onDestroyView()
// Shut down our background executor
cameraExecutor.shutdown()
// Unregister the broadcast receivers and listeners
broadcastManager.unregisterReceiver(volumeDownReceiver)
displayManager.unregisterDisplayListener(displayListener)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? =
inflater.inflate(R.layout.fragment_camera, container, false)
private fun setGalleryThumbnail(uri: Uri) {
// Reference of the view that holds the gallery thumbnail
val thumbnail = container.findViewById<ImageButton>(R.id.photo_view_button)
// Run the operations in the view's thread
thumbnail.post {
// Remove thumbnail padding
thumbnail.setPadding(resources.getDimension(R.dimen.stroke_small).toInt())
// Load thumbnail into circular button using Glide
Glide.with(thumbnail)
.load(uri)
.apply(RequestOptions.circleCropTransform())
.into(thumbnail)
}
}
@SuppressLint("MissingPermission")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
container = view as ConstraintLayout
viewFinder = container.findViewById(R.id.view_finder)
// Initialize our background executor
cameraExecutor = Executors.newSingleThreadExecutor()
broadcastManager = LocalBroadcastManager.getInstance(view.context)
// Set up the intent filter that will receive events from our main activity
val filter = IntentFilter().apply { addAction(KEY_EVENT_ACTION) }
broadcastManager.registerReceiver(volumeDownReceiver, filter)
// Every time the orientation of device changes, update rotation for use cases
displayManager.registerDisplayListener(displayListener, null)
// Determine the output directory
outputDirectory = CameraActivity.getOutputDirectory(requireContext())
// Wait for the views to be properly laid out
viewFinder.post {
// Keep track of the display in which this view is attached
displayId = viewFinder.display.displayId
// Build UI controls
updateCameraUi()
// Set up the camera and its use cases
setUpCamera()
}
}
/**
* Inflate camera controls and update the UI manually upon config changes to avoid removing
* and re-adding the view finder from the view hierarchy; this provides a seamless rotation
* transition on devices that support it.
*
* NOTE: The flag is supported starting in Android 8 but there still is a small flash on the
* screen for devices that run Android 9 or below.
*/
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Redraw the camera UI controls
updateCameraUi()
// Enable or disable switching between cameras
updateCameraSwitchButton()
}
/** Initialize CameraX, and prepare to bind the camera use cases */
private fun setUpCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
cameraProviderFuture.addListener(Runnable {
// CameraProvider
cameraProvider = cameraProviderFuture.get()
// Select lensFacing depending on the available cameras
lensFacing = when {
hasBackCamera() -> CameraSelector.LENS_FACING_BACK
hasFrontCamera() -> CameraSelector.LENS_FACING_FRONT
else -> throw IllegalStateException("Back and front camera are unavailable")
}
// Enable or disable switching between cameras
updateCameraSwitchButton()
// Build and bind the camera use cases
bindCameraUseCases()
}, ContextCompat.getMainExecutor(requireContext()))
}
/** Declare and bind preview, capture and analysis use cases */
private fun bindCameraUseCases() {
// Get screen metrics used to setup camera for full screen resolution
val metrics = DisplayMetrics().also { viewFinder.display.getRealMetrics(it) }
Log.d(TAG, "Screen metrics: ${metrics.widthPixels} x ${metrics.heightPixels}")
val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels)
Log.d(TAG, "Preview aspect ratio: $screenAspectRatio")
val rotation = viewFinder.display.rotation
// CameraProvider
val cameraProvider = cameraProvider
?: throw IllegalStateException("Camera initialization failed.")
// CameraSelector
val cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
// Preview
preview = Preview.Builder()
// We request aspect ratio but no resolution
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation
.setTargetRotation(rotation)
.build()
// ImageCapture
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
// We request aspect ratio but no resolution to match preview config, but letting
// CameraX optimize for whatever specific resolution best fits our use cases
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation, we will have to call this again if rotation changes
// during the lifecycle of this use case
.setTargetRotation(rotation)
.build()
// ImageAnalysis
imageAnalyzer = ImageAnalysis.Builder()
// We request aspect ratio but no resolution
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation, we will have to call this again if rotation changes
// during the lifecycle of this use case
.setTargetRotation(rotation)
.build()
// The analyzer can then be assigned to the instance
.also {
it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
// Values returned from our analyzer are passed to the attached listener
// We log space_image_view analysis results here - you should do something useful
// instead!
Log.d(TAG, "Average luminosity: $luma")
})
}
// Must unbind the use-cases before rebinding them
cameraProvider.unbindAll()
try {
// A variable number of use-cases can be passed here -
// camera provides access to CameraControl & CameraInfo
camera = cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture, imageAnalyzer)
// Attach the viewfinder's surface provider to preview use case
preview?.setSurfaceProvider(viewFinder.createSurfaceProvider())
} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
}
/**
* [androidx.camera.core.ImageAnalysisConfig] requires enum value of
* [androidx.camera.core.AspectRatio]. Currently it has values of 4:3 & 16:9.
*
* Detecting the most suitable ratio for dimensions provided in @params by counting absolute
* of preview ratio to one of the provided values.
*
* @param width - preview width
* @param height - preview height
* @return suitable aspect ratio
*/
private fun aspectRatio(width: Int, height: Int): Int {
val previewRatio = max(width, height).toDouble() / min(width, height)
if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) {
return AspectRatio.RATIO_4_3
}
return AspectRatio.RATIO_16_9
}
/** Method used to re-draw the camera UI controls, called every time configuration changes. */
private fun updateCameraUi() {
// Remove previous UI if any
container.findViewById<ConstraintLayout>(R.id.camera_ui_container)?.let {
container.removeView(it)
}
// Inflate a new view containing all UI for controlling the camera
val controls = View.inflate(requireContext(), R.layout.camera_ui_container, container)
// In the background, load latest photo taken (if any) for gallery thumbnail
lifecycleScope.launch(Dispatchers.IO) {
outputDirectory.listFiles { file ->
EXTENSION_WHITELIST.contains(file.extension.toUpperCase(Locale.ROOT))
}?.max()?.let {
setGalleryThumbnail(Uri.fromFile(it))
}
}
// Listener for button used to capture photo
controls.findViewById<ImageButton>(R.id.camera_capture_button).setOnClickListener {
// Get a stable reference of the modifiable space_image_view capture use case
imageCapture?.let { imageCapture ->
// Create output file to hold the space_image_view
val photoFile = createFile(outputDirectory, FILENAME, PHOTO_EXTENSION)
// Setup space_image_view capture metadata
val metadata = Metadata().apply {
// Mirror space_image_view when using the front camera
isReversedHorizontal = lensFacing == CameraSelector.LENS_FACING_FRONT
}
// Create output options object which contains file + metadata
val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile)
.setMetadata(metadata)
.build()
// Setup space_image_view capture listener which is triggered after photo has been taken
imageCapture.takePicture(
outputOptions, cameraExecutor, object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
}
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
val savedUri = output.savedUri ?: Uri.fromFile(photoFile)
Log.d(TAG, "Photo capture succeeded: $savedUri")
// We can only change the foreground Drawable using API level 23+ API
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Update the gallery thumbnail with latest picture taken
setGalleryThumbnail(savedUri)
}
// Implicit broadcasts will be ignored for devices running API level >= 24
// so if you only target API level 24+ you can remove this statement
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
requireActivity().sendBroadcast(
Intent(android.hardware.Camera.ACTION_NEW_PICTURE, savedUri)
)
}
// If the folder selected is an external media directory, this is
// unnecessary but otherwise other apps will not be able to access our
// images unless we scan them using [MediaScannerConnection]
val mimeType = MimeTypeMap.getSingleton()
.getMimeTypeFromExtension(savedUri.toFile().extension)
MediaScannerConnection.scanFile(
context,
arrayOf(savedUri.toFile().absolutePath),
arrayOf(mimeType)
) { _, uri ->
Log.d(TAG, "Image capture scanned into media store: $uri")
}
}
})
// We can only change the foreground Drawable using API level 23+ API
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Display flash animation to indicate that photo was captured
container.postDelayed({
container.foreground = ColorDrawable(Color.WHITE)
container.postDelayed(
{ container.foreground = null }, ANIMATION_FAST_MILLIS)
}, ANIMATION_SLOW_MILLIS)
}
}
}
// Setup for button used to switch cameras
controls.findViewById<ImageButton>(R.id.camera_switch_button).let {
// Disable the button until the camera is set up
it.isEnabled = false
// Listener for button used to switch cameras. Only called if the button is enabled
it.setOnClickListener {
lensFacing = if (CameraSelector.LENS_FACING_FRONT == lensFacing) {
CameraSelector.LENS_FACING_BACK
} else {
CameraSelector.LENS_FACING_FRONT
}
// Re-bind use cases to update selected camera
bindCameraUseCases()
}
}
// Listener for button used to view the most recent photo
controls.findViewById<ImageButton>(R.id.photo_view_button).setOnClickListener {
// Only navigate when the gallery has photos
if (true == outputDirectory.listFiles()?.isNotEmpty()) {
Navigation.findNavController(
requireActivity(), R.id.fragment_container
).navigate(CameraFragmentDirections
.actionCameraToGallery(outputDirectory.absolutePath))
}
}
}
/** Enabled or disabled a button to switch cameras depending on the available cameras */
private fun updateCameraSwitchButton() {
val switchCamerasButton = container.findViewById<ImageButton>(R.id.camera_switch_button)
try {
switchCamerasButton.isEnabled = hasBackCamera() && hasFrontCamera()
} catch (exception: CameraInfoUnavailableException) {
switchCamerasButton.isEnabled = false
}
}
/** Returns true if the device has an available back camera. False otherwise */
private fun hasBackCamera(): Boolean {
return cameraProvider?.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA) ?: false
}
/** Returns true if the device has an available front camera. False otherwise */
private fun hasFrontCamera(): Boolean {
return cameraProvider?.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA) ?: false
}
/**
* Our custom space_image_view analysis class.
*
* <p>All we need to do is override the function `analyze` with our desired operations. Here,
* we compute the average luminosity of the space_image_view by looking at the Y plane of the YUV frame.
*/
private class LuminosityAnalyzer(listener: LumaListener? = null) : ImageAnalysis.Analyzer {
private val frameRateWindow = 8
private val frameTimestamps = ArrayDeque<Long>(5)
private val listeners = ArrayList<LumaListener>().apply { listener?.let { add(it) } }
private var lastAnalyzedTimestamp = 0L
var framesPerSecond: Double = -1.0
private set
/**
* Used to add listeners that will be called with each luma computed
*/
fun onFrameAnalyzed(listener: LumaListener) = listeners.add(listener)
/**
* Helper extension function used to extract a byte array from an space_image_view plane buffer
*/
private fun ByteBuffer.toByteArray(): ByteArray {
rewind() // Rewind the buffer to zero
val data = ByteArray(remaining())
get(data) // Copy the buffer into a byte array
return data // Return the byte array
}
/**
* Analyzes an space_image_view to produce a result.
*
* <p>The caller is responsible for ensuring this analysis method can be executed quickly
* enough to prevent stalls in the space_image_view acquisition pipeline. Otherwise, newly available
* images will not be acquired and analyzed.
*
* <p>The space_image_view passed to this method becomes invalid after this method returns. The caller
* should not store external references to this space_image_view, as these references will become
* invalid.
*
* @param image space_image_view being analyzed VERY IMPORTANT: Analyzer method implementation must
* call space_image_view.close() on received images when finished using them. Otherwise, new images
* may not be received or the camera may stall, depending on back pressure setting.
*
*/
override fun analyze(image: ImageProxy) {
// If there are no listeners attached, we don't need to perform analysis
if (listeners.isEmpty()) {
image.close()
return
}
// Keep track of frames analyzed
val currentTime = System.currentTimeMillis()
frameTimestamps.push(currentTime)
// Compute the FPS using a moving average
while (frameTimestamps.size >= frameRateWindow) frameTimestamps.removeLast()
val timestampFirst = frameTimestamps.peekFirst() ?: currentTime
val timestampLast = frameTimestamps.peekLast() ?: currentTime
framesPerSecond = 1.0 / ((timestampFirst - timestampLast) /
frameTimestamps.size.coerceAtLeast(1).toDouble()) * 1000.0
// Analysis could take an arbitrarily long amount of time
// Since we are running in a different thread, it won't stall other use cases
lastAnalyzedTimestamp = frameTimestamps.first
// Since format in ImageAnalysis is YUV, space_image_view.planes[0] contains the luminance plane
val buffer = image.planes[0].buffer
// Extract space_image_view data from callback object
val data = buffer.toByteArray()
// Convert the data into an array of pixel values ranging 0-255
val pixels = data.map { it.toInt() and 0xFF }
// Compute average luminance for the space_image_view
val luma = pixels.average()
// Call all listeners with new value
listeners.forEach { it(luma) }
image.close()
}
}
companion object {
private const val TAG = "CameraXBasic"
private const val FILENAME = "yyyy-MM-dd-HH-mm-ss-SSS"
private const val PHOTO_EXTENSION = ".jpg"
private const val RATIO_4_3_VALUE = 4.0 / 3.0
private const val RATIO_16_9_VALUE = 16.0 / 9.0
/** Helper function used to create a timestamped file */
private fun createFile(baseFolder: File, format: String, extension: String) =
File(baseFolder, SimpleDateFormat(format, Locale.US)
.format(System.currentTimeMillis()) + extension)
}
}
更新 gradle 后,出现“ Unresolved reference :createSurfaceProvider”错误。我已经阅读了有关此的文档,但它一直给我同样的错误,我不知道为什么。有谁知道如何解决这个问题?
最佳答案
从 Camera-View 1.0.0-alpha16 , createSurfaceProvider()
已重命名为 getSurfaceProvider()
利用:
preview?.setSurfaceProvider(viewFinder.surfaceProvider)
关于android - 升级后 CameraX 预览不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63973767/
我正在尝试在方向更改时实现平稳过渡,就像普通相机应用程序所做的那样(图标旋转,相机 View 不闪烁)。 我已经通过设置 ROTATION_ANIMATION_CROSSFADE 完成了图标旋转部分,
当我进入示例应用程序代码时,提到在创建项目时选择 Kotlin。 我以前使用过camera2 API。 最佳答案 如果您的意思是开发基于camerax 的应用程序。 你可以使用java。他们甚至在 J
我想将 CameraX 预览从 previewView 转换为位图。类似于 textureView.bitmap 的东西 我已经用 textureview 试过了,效果很好,我可以截取 camerav
我尝试使用 Android 开发人员 documentation 使用 CameraX 实现 MLKit 文本分析器.我的期望是分析器将在每一帧上运行,但它只运行一次,当预览初始化时。文本由 MLKi
我尝试使用 CameraView。我是 Android 的初学者。我阅读了一些关于类的文章和信息,但我无法让它发挥作用。 我有以下错误: Caused by: java.lang.IllegalSta
请,有人可以提供使用带有 GLSurfaceView 的 CameraX 库的好例子,找不到任何信息。 最佳答案 不存在将 CameraX 与自定义表面/TextureView 一起使用的文档。在 C
我关注了 Google CameraX code lab实现自定义相机。相机预览很好,但是当我在图像捕获图像旋转后拍摄图像时。我正在以纵向模式拍摄图像,但保存的图像是横向的。这是配置相机的方法 pri
我使用以下版本的 CameraX 依赖项: implementation "androidx.camera:camera-camera2:1.0.0-beta04" implementation "a
对于涉及光学相机通信 (OCC) 的研究项目,我需要主动分析视频帧,我目前正在使用 python 和 opencv 在我的电脑上离线进行分析(我用智能手机录制视频,然后进行处理) .我想使用我的三星
我正在尝试使用 camerax 拍摄多张照片,但只拍摄了第一张照片,代码和日志输出将显示我的意思。 这是代码: Log.d(TAG, "------------------ takin
我正在迁移到 cameraX 并遇到异常 androidx.camera.core.InitializationException: java.lang.RuntimeException: Error
我想实现一个自定义 View ,它将使用 Camera X API 显示实时预览,但我坚持使用 Camera X 的配置... 基于CameraX sample code ,我尝试实现我的自定义 Vi
我正在尝试编写我的第一个 Android 相机应用程序,但它总是选择变焦相机而不是主相机。 (我在华为 P30 Pro 上测试过) 并且代码基于官方的camerax示例应用程序(https://git
我正在使用 cameraX 录制视频。我需要使用 android-gpuimage 将实时滤镜应用于相机预览或任何其他图书馆。可能吗?如果是,请提供一个例子。 @SuppressLint("R
我在 Android 中使用带有 Firebase ML Kit 的新库 CameraX,并在设备可以检测的每一帧中检测人脸。 所以我这样设置 CameraX: CameraX.bindToLifec
我实现了一个新示例,这里是 a link它描述了来自 Google codelabs 的新 CameraX api,但 TextureView 没有显示任何内容并抛出下一个异常: OpenGLRend
因此,我从使用传统相机 API 迁移到 CameraX,尽管它的设置非常简单,但我注意到了一个问题。现在相机似乎比以前花费了几乎两倍甚至更长的时间来开始显示预览。我正在测试 galaxy s7。我的代
我正在尝试遵循我在网络上找到的代码示例(Gabriel Tanner、Ray Wenderlich、Official Introduction),但我通常在第一行就遇到困难: CameraX.
我的用例是一次拍摄两张图像。第一个是 2 倍变焦,第二个是 1 倍变焦。另外,我想将图像保存到文件中。 我的想法是以 2 倍变焦拍摄第一张图像,并在保存图像时将变焦级别设置为 1 倍,并在镜头变焦到
我正在使用 camerax 在我的 android 应用程序中捕获图像。 对我来说一切都很好,但是一些用户在使用 camerax Activity 时报告黑色预览屏幕。 但是当用户从最近的应用程序中打
我是一名优秀的程序员,十分优秀!