J'ai essayé CameraX présenté à Google I / O 2019 sur Fragment en Java, je vais donc le présenter brièvement.
Il est facile de procéder en regardant le [Tutoriel] officiel (https://codelabs.developers.google.com/codelabs/camerax-getting-started/#0), donc je vais continuer en regardant ceci.
La création d'un projet et l'ajout de dépendances sont conformes au didacticiel, je les omettrai donc dans cet article.
Ajoutez TextureView à layout.xml pour l'afficher dans Fragment.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="#FFFFFF">
<TextureView
android:id="@+id/view_finder"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<RelativeLayout
android:id="@+id/camera_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#456700"
android:padding="15dp">
<ImageButton
android:id="@+id/camera_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/common_backbtn"
android:layout_alignParentLeft="true"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/camera_bottom_control"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#456700"
android:padding="20dp">
<Button
android:id="@+id/capture_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Tirer"
/>
</RelativeLayout>
</RelativeLayout>
Ça ressemble à ça ↓
TextureView est placé sur toute la surface et des éléments d'écran y sont superposés.
Tout ce que vous avez à faire est de définir l'aperçu et de le lier au cycle de vie du fragment.
C'est facile car vous liez simplement le PreviewConfig créé par CameraX.bindToLifecycle.
public void startCamera() {
PreviewConfig.Builder builder = new PreviewConfig.Builder();
builder.setTargetResolution(new Size(App.width, App.height));
PreviewConfig previewConfig = builder.build();
preview = new Preview(previewConfig);
preview.setOnPreviewOutputUpdateListener(new Preview.OnPreviewOutputUpdateListener() {
@Override
public void onUpdated(@NonNull Preview.PreviewOutput output) {
ViewGroup viewGroup = (ViewGroup) viewFinder.getParent();
viewGroup.removeView(viewFinder);
viewGroup.addView(viewFinder, 0);
viewFinder.setSurfaceTexture(output.getSurfaceTexture());
updateTransform();
}
});
CameraX.bindToLifecycle(this, preview);
}
public void updateTransform() {
Matrix matrix = new Matrix();
float centerX = viewFinder.getWidth() / 2f;
float centerY = viewFinder.getHeight() / 2f;
float rotationDegrees;
switch (viewFinder.getDisplay().getRotation()) {
case Surface.ROTATION_0:
rotationDegrees = 0f;
break;
case Surface.ROTATION_90:
rotationDegrees = 90f;
break;
case Surface.ROTATION_180:
rotationDegrees = 180f;
break;
case Surface.ROTATION_270:
rotationDegrees = 270f;
break;
default:
return;
}
matrix.postRotate(-rotationDegrees, centerX, centerY);
viewFinder.setTransform(matrix);
}
Fondamentalement, écrivez simplement ceci, et si vous appelez startCamera après avoir obtenu l'autorisation de la caméra, l'aperçu sera affiché.
Vous ne pouvez pas l'utiliser pour quoi que ce soit juste en prévisualisant la caméra, alors capturons l'image à ce moment-là lorsque capture_button est enfoncé.
Ajoutez le code suivant avant de lier la méthode startCamera ci-dessus.
ImageCaptureConfig.Builder imageBuilder = new ImageCaptureConfig.Builder();
imageBuilder.setTargetResolution(new Size(App.width, App.height));
imageBuilder.setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY);
imageBuilder.setFlashMode(FlashMode.ON);
ImageCaptureConfig imageCaptureConfig = imageBuilder.build();
imageCapture = new ImageCapture(imageCaptureConfig);
Je configure la capture d'image. Ici, Flash est activé pour maximiser la qualité. Après avoir créé ImageCaptureConfig, ajoutons également ImageCaptureConfig à la méthode de liaison.
CameraX.bindToLifecycle(this, preview, imageCapture);
Maintenant, vous êtes prêt à partir.
Vous pouvez capturer en appelant imageCapture.takePicture (), définissons donc un événement pour le bouton.
btnCamera.setOnClickListener((View v) -> {
imageCapture.takePicture(CameraFragment.this, new ImageCapture.OnImageCapturedListener() {
@Override
public void onCaptureSuccess(ImageProxy imageProxy, int rotationDegrees) {
}
@Override
public void onError(
@NonNull ImageCapture.ImageCaptureError imageCaptureError, @NonNull String message,
@Nullable Throwable cause) {
}
});
}
});
Executor est requis pour l'argument de takePicture, nous allons donc implémenter ici Executor dans Fragment afin qu'UiThread puisse exécuter le traitement après avoir pris une photo.
public class CameraFragment implements Executor {
@Override
public void execute(Runnable command) {
if(getActivity() != null){
getActivity().runOnUiThread(command);
}
}
}
Lorsque vous appuyez sur le bouton de prise de vue et que la prise de vue est réussie, onCaptureSuccess (ImageProxy imageProxy, int rotationDegrees) est appelé et l'image peut être acquise depuis imageProxy!
C'est facile ...
Qu'est-ce qui a été écrit sur Camera2?
C'est un mot difficile à monter sur la caméra, donc j'attendais ça.
Eh bien, je l'ai décrit très facilement, mais je vais le présenter car il y avait des points addictifs.
Il n'y a pas de son d'obturateur. Oui.
Je cherchais quelque chose qui pourrait être défini dans les paramètres de capture, mais on ne le trouve nulle part ...
Si vous voulez le faire sonner, essayez de le forcer.
MediaActionSound sound = new MediaActionSound();
sound.play(MediaActionSound.SHUTTER_CLICK);
Oui, c'est ça.
public Bitmap imageProxyToBitmap(ImageProxy image, int rotationDegrees) {
ImageProxy.PlaneProxy planeProxy = image.getPlanes()[0];
ByteBuffer buffer = planeProxy.getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
Matrix mat = new Matrix();
mat.postRotate(rotationDegrees);
if (rotationDegrees != 0) {
return rotate(BitmapFactory.decodeByteArray(bytes, 0, bytes.length), rotationDegrees);
} else {
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
}
public Bitmap rotate(Bitmap in, int angle) {
Matrix mat = new Matrix();
mat.postRotate(angle);
return Bitmap.createBitmap(in, 0, 0, in.getWidth(), in.getHeight(), mat, true);
}
Q. Pourquoi TextureView se trouve-t-il sur toute la surface du fichier de mise en page? Ne devrait-il pas rentrer dans la zone de prévisualisation?
R. J'ose tout recommencer.
Si la taille de l'aperçu et le rapport hauteur / largeur de la taille de TextureView ne correspondent pas, l'aperçu sera déformé et affiché, ou si vous créez un écran avec une zone d'aperçu qui est petite par rapport à la taille de l'écran, vous avez vu que TextureView est conçue pour s'adapter à la zone d'aperçu. L'aperçu sera très difficile à voir car les choses seront affichées dans une taille réduite dans TextureView.
Si vous placez TextureView sur toute la surface, tous les problèmes ci-dessus seront résolus et vous pourrez prendre des photos avec la même sensation que l'appareil photo sur toute la surface que vous utilisez habituellement, afin de pouvoir prendre des photos sans aucun inconfort.
Si vous voulez une image de la seule zone visible par l'utilisateur, vous pouvez la découper après la prise de vue.
Veuillez noter que CameraX est toujours une version alpha, donc l'interface peut changer dans la version finale.
De plus, bien que cela ne soit pas présenté ici, il semble qu'il existe une API qui facilite l'utilisation des effets de fournisseur spécifiques à l'appareil (flou, HDR, vue nocturne), je voudrais donc essayer cela également à l'avenir.
Recommended Posts