I am capturing the image to transform it into a square of a certain size. When I capture an image using different phones, in some of them the image captured is the same as the image shown in the preview, but in some phones, the image captured is rotated.

Below is the code:

On button click:

bGetImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                final Bitmap[] bitmap = {null};
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                    imageCapture.takePicture(getMainExecutor(),new ImageCapture.OnImageCapturedCallback() {
                        @Override
                        public void onCaptureSuccess(@NonNull ImageProxy image) {
                            super.onCaptureSuccess(image);
                            Log.d(TAG, "onCaptureSuccess: testview.innerRectangle " + testview.innerRectangle.width());
                            Log.d(TAG, "onCaptureSuccess: testview.innerRectangle " + testview.innerRectangle.height());
                            OutputTransform source = previewView.getOutputTransform();
                            // imageProxy is the output of the ImageCapture.
                            OutputTransform target = new ImageProxyTransformFactory().getOutputTransform(image);
                            //print size of target
                            Log.d(TAG, "onCaptureSuccess: target " + target.getMatrix().toString());
                            // Build the transform from ImageAnalysis to PreviewView
                            CoordinateTransform coordinateTransform = new CoordinateTransform(source, target);
                            // The variable box here is your bounding box in PreviewView
                            coordinateTransform.mapRect(testview.innerRectangle);

                            Log.d(TAG, "onCaptureSuccess: testview.innerRectangle " + testview.innerRectangle.width());
                            Log.d(TAG, "onCaptureSuccess: testview.innerRectangle " + testview.innerRectangle.height());
                            bitmap[0] = imageProxytoBitmap(image);
                            Log.d(TAG, "onCaptureSuccess: bitmap[0] " + bitmap[0].getWidth());
                            Log.d(TAG, "onCaptureSuccess: bitmap[0] " + bitmap[0].getHeight());

//                            bitmap[0] = Bitmap.createBitmap(bitmap[0],(int)testview.innerRectangle.left,(int)testview.innerRectangle.top,(int)testview.innerRectangle.width(),(int)testview.innerRectangle.height());

                            try {
                                Uri uri = getUri(bitmap[0], getContentResolver());
                                Log.d(TAG, "onCaptureSuccess: bitmap[0] " + bitmap[0].getWidth());
                                Log.d(TAG, "onCaptureSuccess: bitmap[0] " + bitmap[0].getHeight());
                                String path = uri.toString();
                                moveToScanActivity(path);
                            } catch (IOException e) {
                                Log.e(TAG, "onCaptureSuccess: ",e);
                            }
                        }
                    });
                }

            }
        });

Camera Provider initialization:


        cameraProviderFuture.addListener(() -> {
            try {
                ProcessCameraProvider cameraProvider = cameraProviderFuture.get();

                CameraSelector selector = CameraSelector.DEFAULT_BACK_CAMERA;

                cameraProvider.unbindAll();
//                Camera camera = cameraProvider.bindToLifecycle(this, selector);

                bindPreview(cameraProvider);
            } catch (ExecutionException | InterruptedException e) {
                // No errors need to be handled for this Future.
                // This should never be reached.
            }

        }, ContextCompat.getMainExecutor(this));

Other functions I am using:

void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
        Log.d(TAG, "bindPreview: width " + width);
        Log.d(TAG, "bindPreview: height " + height);
        Preview preview = new Preview.Builder()
                .setTargetResolution(new Size(width, height))
                .setTargetRotation(ROTATION_0)
                .build();

        previewView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(
                    View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                Size newViewFinderDimens = new Size(right - left, bottom - top);
                updateTransform(0, MainActivity.bufferDimens, newViewFinderDimens);
            }
        });

         imageCapture =
                new ImageCapture.Builder()
                        .setTargetResolution(new Size(width, height))
                        .setTargetRotation(ROTATION_0)
                        .build();

        CameraSelector cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build();

        preview.setSurfaceProvider(previewView.getSurfaceProvider());

        UseCaseGroup useCaseGroup = new UseCaseGroup.Builder()
                .addUseCase(preview)
                .addUseCase(imageCapture)
                .build();


        cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, useCaseGroup);

        previewHeight = previewView.getHeight();
        previewWidth = previewView.getWidth();
    }

private Uri getUri(Bitmap bitmap, ContentResolver contentResolver) throws FileNotFoundException {
        File file = new File(getApplicationContext().getExternalMediaDirs()[0].getAbsolutePath(),"Mytittle_" + System.currentTimeMillis() + ".png");
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(file));
        Log.d(TAG, "getUri: path " + file.getAbsolutePath());
        return Uri.parse(file.getAbsolutePath());
    }

private Bitmap rotateImage(Bitmap img, int degree)
    {
        Matrix matrix = new Matrix();
        matrix.postRotate(degree);
        return Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, false);
    }
public void updateTransform(int rotation, Size newBufferDimens, Size newViewFinderDimens) {
        if (rotation == viewFinderRotation &&
                newBufferDimens == bufferDimens &&
                newViewFinderDimens == viewFinderDimens) {
            // Nothing has changed, no need to transform output again
            //Log.d("AK", "nothing has changed, no need to transform output again");
            return;
        }

        if (newBufferDimens.getWidth() == 0 || newBufferDimens.getHeight() == 0) {
            // Invalid buffer dimens - wait for valid inputs before setting matrix
            //Log.d("AK", "returning from here newbufferdimens");
            return;
        } else {
            // Update internal field with new inputs
            bufferDimens = newBufferDimens;
        }

        if (newViewFinderDimens.getWidth() == 0 || newViewFinderDimens.getHeight() == 0) {
            // Invalid view finder dimens - wait for valid inputs before setting matrix
            //Log.d("AK", "returning from here newViewfinder");
            return;
        } else {
            // Update internal field with new inputs
            viewFinderDimens = newViewFinderDimens;
        }

        Matrix matrix = new Matrix();
        Log.d(TAG, "Applying output transformation.\n" +
                "View finder size: " + viewFinderDimens + "\n" +
                "Preview output size: " + bufferDimens + "\n" +
                "View finder rotation: " + viewFinderRotation + "\n" +
                "Preview output rotation: " + 0);
        float centerX = previewView.getWidth() / 2f;
        float centerY = previewView.getHeight() / 2f;

        // Correct preview output to account for display rotation
        float rotationDegrees;
        switch (previewView.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);

        float bufferRatio = bufferDimens.getHeight() / (float) bufferDimens.getWidth();
        int scaledWidth;
        int scaledHeight;

        if (previewView.getWidth() > previewView.getHeight()) {
            scaledHeight = viewFinderDimens.getWidth();
            scaledWidth = round(viewFinderDimens.getWidth() * bufferRatio);
        } else {
            scaledHeight = viewFinderDimens.getHeight();
            scaledWidth = round(viewFinderDimens.getHeight() * bufferRatio);
        }

        Canvas canvas = new Canvas();
        float xScale = scaledWidth / (float) viewFinderDimens.getWidth();
        float yScale = scaledHeight / (float) viewFinderDimens.getHeight();
        //Log.d("AK", "scale x y" + xScale + " " + yScale);
        matrix.preScale(xScale, yScale, centerX, centerY);


    }
private Bitmap imageProxytoBitmap(ImageProxy image) {

        ByteBuffer buffer =image.getPlanes()[0].getBuffer();
        buffer.rewind();
        byte[] bytes = new byte[buffer.capacity()];
        buffer.get(bytes);
        byte[] cloneBytes = bytes.clone();

        return BitmapFactory.decodeByteArray(cloneBytes, 0, cloneBytes.length);

    }

I want the captured image to exactly same as the preview (unrotated image)

1

There are 1 best solutions below

0
Xi 张熹 On

If you open the rotated image in the Google Photo app, are they still rotated? If not, then it means that you are not using the EXIF info.

Basically when a photo is captured, it may or may not be rotated depending on the OEM. When it's not rotated, CameraX saves the rotation info in the TAG_ORIENTATION tag. You will need to read that info and apply it on the Bitmap yourself. Something like:

// Read the exif rotation value from the JPEG byte buffer
ExifInterface exifInterface = new ExifInterface(jpegFilePath);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);

// Decode the JPEG byte buffer into a bitmap
Bitmap bitmap = BitmapFactory.decodeFile(jpegFilePath);

// Rotate the bitmap based on the exif rotation value
Matrix matrix = new Matrix();
switch (orientation) {
    case ExifInterface.ORIENTATION_ROTATE_90:
        matrix.postRotate(90);
        break;
    case ExifInterface.ORIENTATION_ROTATE_180:
        matrix.postRotate(180);
        break;
    case ExifInterface.ORIENTATION_ROTATE_270:
        matrix.postRotate(270);
        break;
}
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

Code not tested. You might need to swap width/height during rotation.