- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个自定义的相机应用,该应用具有居中的矩形 View ,如下所示:
拍照时,我想忽略矩形外的所有内容。这是我的XML布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black_50">
<TextureView
android:id="@+id/viewFinder"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_margin="16dp"
android:background="@drawable/rectangle"
app:layout_constraintBottom_toTopOf="@+id/cameraBottomView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/cameraBottomView"
android:layout_width="match_parent"
android:layout_height="130dp"
android:background="@color/black_50"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageButton
android:id="@+id/cameraCaptureImageButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:src="@drawable/ic_capture_image"
app:layout_constraintBottom_toBottomOf="@id/cameraBottomView"
app:layout_constraintEnd_toEndOf="@id/cameraBottomView"
app:layout_constraintStart_toStartOf="@id/cameraBottomView"
app:layout_constraintTop_toTopOf="@id/cameraBottomView"
tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>
class CameraFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_camera, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewFinder.post { setupCamera() }
}
private fun setupCamera() {
CameraX.unbindAll()
CameraX.bindToLifecycle(
this,
buildPreviewUseCase(),
buildImageCaptureUseCase(),
buildImageAnalysisUseCase()
)
}
private fun buildPreviewUseCase(): Preview {
val preview = Preview(
UseCaseConfigBuilder.buildPreviewConfig(
viewFinder.display
)
)
preview.setOnPreviewOutputUpdateListener { previewOutput ->
updateViewFinderWithPreview(previewOutput)
correctPreviewOutputForDisplay(previewOutput.textureSize)
}
return preview
}
private fun updateViewFinderWithPreview(previewOutput: Preview.PreviewOutput) {
val parent = viewFinder.parent as ViewGroup
parent.removeView(viewFinder)
parent.addView(viewFinder, 0)
viewFinder.surfaceTexture = previewOutput.surfaceTexture
}
/**
* Corrects the camera/preview's output to the display, by scaling
* up/down and/or rotating the camera/preview's output.
*/
private fun correctPreviewOutputForDisplay(textureSize: Size) {
val matrix = Matrix()
val centerX = viewFinder.width / 2f
val centerY = viewFinder.height / 2f
val displayRotation = getDisplayRotation()
val (dx, dy) = getDisplayScalingFactors(textureSize)
matrix.postRotate(displayRotation, centerX, centerY)
matrix.preScale(dx, dy, centerX, centerY)
// Correct preview output to account for display rotation and scaling
viewFinder.setTransform(matrix)
}
private fun getDisplayRotation(): Float {
val rotationDegrees = when (viewFinder.display.rotation) {
Surface.ROTATION_0 -> 0
Surface.ROTATION_90 -> 90
Surface.ROTATION_180 -> 180
Surface.ROTATION_270 -> 270
else -> throw IllegalStateException("Unknown display rotation ${viewFinder.display.rotation}")
}
return -rotationDegrees.toFloat()
}
private fun getDisplayScalingFactors(textureSize: Size): Pair<Float, Float> {
val cameraPreviewRation = textureSize.height / textureSize.width.toFloat()
val scaledWidth: Int
val scaledHeight: Int
if (viewFinder.width > viewFinder.height) {
scaledHeight = viewFinder.width
scaledWidth = (viewFinder.width * cameraPreviewRation).toInt()
} else {
scaledHeight = viewFinder.height
scaledWidth = (viewFinder.height * cameraPreviewRation).toInt()
}
val dx = scaledWidth / viewFinder.width.toFloat()
val dy = scaledHeight / viewFinder.height.toFloat()
return Pair(dx, dy)
}
private fun buildImageCaptureUseCase(): ImageCapture {
val capture = ImageCapture(
UseCaseConfigBuilder.buildImageCaptureConfig(
viewFinder.display
)
)
cameraCaptureImageButton.setOnClickListener {
capture.takePicture(
FileCreator.createTempFile(JPEG_FORMAT),
Executors.newSingleThreadExecutor(),
object : ImageCapture.OnImageSavedListener {
override fun onImageSaved(file: File) {
requireActivity().runOnUiThread {
launchGalleryFragment(file.absolutePath)
}
}
override fun onError(
imageCaptureError: ImageCapture.ImageCaptureError,
message: String,
cause: Throwable?
) {
Toast.makeText(requireContext(), "Error: $message", Toast.LENGTH_LONG)
.show()
Log.e("CameraFragment", "Capture error $imageCaptureError: $message", cause)
}
})
}
return capture
}
private fun buildImageAnalysisUseCase(): ImageAnalysis {
val analysis = ImageAnalysis(
UseCaseConfigBuilder.buildImageAnalysisConfig(
viewFinder.display
)
)
analysis.setAnalyzer(
Executors.newSingleThreadExecutor(),
ImageAnalysis.Analyzer { image, rotationDegrees ->
Log.d(
"CameraFragment",
"Image analysis: $image - Rotation degrees: $rotationDegrees"
)
})
return analysis
}
private fun launchGalleryFragment(path: String) {
val action = CameraFragmentDirections.actionLaunchGalleryFragment(path)
findNavController().navigate(action)
}
}
class GalleryFragment : Fragment() {
private lateinit var imageView: ImageView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_gallery, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
imageView = view.findViewById(R.id.img)
val imageFilePath = GalleryFragmentArgs.fromBundle(arguments!!).data
val bitmap = BitmapFactory.decodeFile(imageFilePath)
val rotatedBitmap = bitmap.rotate(90)
if (imageFilePath.isBlank()) {
Log.i(
"GalleryFragment",
"Image is Null or Empty"
)
} else {
Glide.with(activity!!)
.load(rotatedBitmap)
.into(imageView)
}
}
private fun Bitmap.rotate(degree:Int):Bitmap{
// Initialize a new matrix
val matrix = Matrix()
// Rotate the bitmap
matrix.postRotate(degree.toFloat())
// Resize the bitmap
val scaledBitmap = Bitmap.createScaledBitmap(
this,
width,
height,
true
)
// Create and return the rotated bitmap
return Bitmap.createBitmap(
scaledBitmap,
0,
0,
scaledBitmap.width,
scaledBitmap.height,
matrix,
true
)
}
}
最佳答案
正如您所提到的,这是我如何裁剪由cameraX拍摄的图像的示例。我不知道这是否是最好的方法,我很想知道其他解决方案。
camerax_version =“1.0.0-alpha07”
CameraFragment.java
初始化cameraX:
// Views
private PreviewView previewView;
// CameraX
private ProcessCameraProvider cameraProvider;
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
private CameraSelector cameraSelector;
private Executor executor;
private ImageCapture imageCapture;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
cameraProviderFuture = ProcessCameraProvider.getInstance(getContext());
executor = ContextCompat.getMainExecutor(getContext());
cameraSelector = new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
previewView = view.findViewById(R.id.preview);
ImageButton btnCapture = view.findViewById(R.id.btn_capture);
// Wait for the view to be properly laid out
previewView.post(() ->{
//Initialize CameraX
cameraProviderFuture.addListener(() -> {
if(cameraProvider != null) cameraProvider.unbindAll();
try {
cameraProvider = cameraProviderFuture.get();
// Set up the preview use case to display camera preview
Preview preview = new Preview.Builder()
.setTargetAspectRatio(AspectRatio.RATIO_4_3)
.setTargetRotation(previewView.getDisplay().getRotation())
.build();
preview.setPreviewSurfaceProvider(previewView.getPreviewSurfaceProvider());
// Set up the capture use case to allow users to take photos
imageCapture = new ImageCapture.Builder()
.setCaptureMode(ImageCapture.CaptureMode.MINIMIZE_LATENCY)
.setTargetRotation(previewView.getDisplay().getRotation())
.setTargetAspectRatio(AspectRatio.RATIO_4_3)
.build();
// Apply declared configs to CameraX using the same lifecycle owner
cameraProvider.bindToLifecycle(this, cameraSelector, preview,imageCapture);
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}, ContextCompat.getMainExecutor(getContext()));
});
btnCapture.setOnClickListener(v -> {
String format = "yyyy-MM-dd-HH-mm-ss-SSS";
SimpleDateFormat fmt = new SimpleDateFormat(format, Locale.US);
String date = fmt.format(System.currentTimeMillis());
File file = new File(getContext().getCacheDir(), date+".jpg");
imageCapture.takePicture(file, executor, imageSavedListener);
});
}
private ImageCapture.OnImageSavedCallback imageSavedListener = new ImageCapture.OnImageSavedCallback() {
@Override
public void onImageSaved(@NonNull File photoFile) {
// Create new fragment and transaction
Fragment newFragment = new GalleryFragment();
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
// Set arguments
Bundle args = new Bundle();
args.putString("KEY_PATH", Uri.fromFile(photoFile).toString());
newFragment.setArguments(args);
// Replace whatever is in the fragment_container view with this fragment,
transaction.replace(R.id.fragment_container, newFragment,null);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
@Override
public void onError(int imageCaptureError, @NonNull String message, @Nullable Throwable cause) {
if (cause != null) {
cause.printStackTrace();
}
}
};
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String path = getArguments().getString("KEY_PATH");
sourceUri = Uri.parse(path);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Initialize the views
ImageView imageView = view.findViewById(R.id.image_view);
View cropArea = view.findViewById(R.id.crop_area);
// Display the image
Glide.with(this).load(sourceUri).listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
// Get original bitmap
sourceBitmap = ((BitmapDrawable)resource).getBitmap();
// Create a new bitmap corresponding to the crop area
int[] cropAreaXY = new int[2];
int[] placeHolderXY = new int[2];
Rect rect = new Rect();
imageView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
@Override
public boolean onPreDraw() {
try {
imageView.getLocationOnScreen(placeHolderXY);
cropArea.getLocationOnScreen(cropAreaXY);
cropArea.getGlobalVisibleRect(rect);
croppedBitmap = Bitmap.createBitmap(sourceBitmap, cropAreaXY[0], cropAreaXY[1] - placeHolderXY[1], rect.width(), rect.height());
// Save the croppedBitmap if you wish
getActivity().runOnUiThread(() -> imageView.setImageBitmap(croppedBitmap));
return true;
}finally {
imageView.getViewTreeObserver().removeOnPreDrawListener(this);
}
}
});
return false;
}
}).into(imageView);
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
<androidx.camera.view.PreviewView
android:id="@+id/preview"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="3:4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/crop_area"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="8dp"
android:background="@drawable/rectangle_round_corners"
app:layout_constraintBottom_toBottomOf="@+id/preview"
app:layout_constraintDimensionRatio="4.5:3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/cameraBottomView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/preview" />
<ImageButton
android:id="@+id/btn_capture"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/ic_shutter"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/preview" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/layout_main"
android:background="@android:color/black"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/crop_area"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="4.5:3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
关于kotlin - 如何在CameraX上的相机预览中裁剪图像矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59242315/
有人能给我一些代码示例,了解如何从相机捕获“完整”图像,然后在“startActivityForResult”中将其转换为字节,以及显示在 imageView 中的位图。任何帮助将不胜感激。 山姆 最
我有一个带有两个圆的组,当我用平移过渡移动其中一个时,我应该看到静止的一个保持在中心(位于场景图的中间),而另一个移动。取而代之的是,“摄像机”跟随移动的圆圈,使其看起来好像都在分开。 有没有一种方法
我希望停止 Phonegap 将图片保存到 iOS 上的相机胶卷。 我发现了一种可能的解决方案,但我不太喜欢它。该解决方案需要通过删除这行代码来 fork phonegap API。 UIImageW
我最近开始使用 JOGL,我知道如何在 Canvas 上创建和绘制对象,但我找不到有关如何设置和旋转相机的教程或说明。我只找到了源代码,但由于我对此很陌生,所以它没有太大帮助。 有人知道一个好的教程或
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 8 年前。 Improve this ques
我想实现这样的目标: 因此,您捕获和处理的唯一内容是矩形中的区域。我需要这个,因为我想做一些 OCR 而我不想要整个屏幕。 最佳答案 也许可以帮助您这个来源,(在相机预览顶部绘制一个边界框以捕获部分图
我正在开发一个 Android 应用程序,我希望我的应用程序能够拍照并显示它们。我的问题是它制作了图片,将它存储在 SD 卡上但没有在我的应用程序中显示它,ImageView 保持空白。这是我的代码:
我正在研究 Android 相机教程,SDK 11。出于某种原因,我在 handleCameraPhoto() 中得到了一个空指针。我唯一看到的是“无法将结果 ResultInfo{who=null,
我一直在尝试实现此代码,我在其中从相机捕获图像并将其显示在我的图像查看器中,然后可以将其设置为墙纸。它在我的模拟器中运行良好,但在我的手机上,当我拍摄图像并单击“确定”时,它会强制关闭。有什么帮助吗?
我想将预览中的某些像素更改为比其余像素暗一点。假设我希望预览的上半部分比预览的下半部分暗一点。 我试图像这样使用 setPreviewCallback: camera.setPreviewCallba
我想为我的应用程序启用相机/照片库设置。我可以显示警报以编程方式启用这些吗就像应用程序启动时一样。我已附上图片以显示我希望看到我的应用程序的类似设置 对于我的应用程序,我没有看到此设置。 我的问题是这
所以我正在开发类似于相机应用程序的东西。它在原生 OpenGL 纹理上绘制实时相机预览。如果按下按钮,则会以原始形式捕获静态图像(可能比实时预览分辨率更高)。 这是我的代码的大纲。为了清楚起见,我没有
我想在我的 Android 应用程序中启动相机 Activity ,我知道该怎么做。我想问一下当相机 Activity 结束时,我如何检查它是否是用户拍摄的照片或视频? 已更新 我有一个对话框,其中询
我在横向模式下有自定义全屏摄像头。设备尺寸为 1024 x 600。 支持的预览尺寸列表 宽 x 高 176 x 144 320 x 240 352 x 288 528 x 432 640 x 480
请看下图!! 所以在这张图片中...您可以看到底部的弹出窗口,当用户“点击”“相机”按钮时,它会为用户提供 3 个选项。 那是什么观点?它是一个模态视图 Controller ,在选择一个选项时被关闭
我发布了一个应用程序,其中一项基本功能是允许用户拍照,然后将该照片保存在其外部存储上的特定文件夹中。 一切似乎都运行良好,但我现在收到两份报告,声称在拍照后单击“完成”退出相机(并返回到 Activi
我在尝试实时更换相机时遇到问题,它适用于本地视频,但远程人员看不到新相机,但仍然可以看到旧相机。我试图停止流并再次初始化,但仍然无法正常工作。这只是我的一些代码。 我到处搜索,但找不到解决方案。有人可
一个简单但非常复杂的问题:为 Flutter 相机添加点击对焦功能的最佳方法是什么? 我在整个万维网上搜索了优雅的解决方案,但一无所获。 你有想法吗? 最佳答案 我可能会迟到,但你可以试试 adv_c
我正在尝试使用 gluLookAt 方法设置 3D 相机。所以我有一个 10x10x10 的立方体,现在我想在那个立方体内移动相机。我有这样的事情: gluLookAt( camera->x,came
我赠送一个 UIImagePickerController在我的应用程序中通过在 sheet 中呈现逻辑修饰符。简而言之,以下三种类型处理显示和关闭 UIImagePickerController 的
我是一名优秀的程序员,十分优秀!