Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Taken photo is bigger than the preview

I'm trying to capture photos directly using the camera api, but this is the preview I got: enter image description here

& this is the image taken after calling takePicture() which is bigger than the preview itself:

enter image description here

(note: I cropped the height of the previous 2 photos to enhance question readability, & kept the width as is)

I'm using this utility method to choose best optimal preview size before starting the camera preview:

public static Camera.Size getBestAspectPreviewSize(int displayOrientation,
                                                   int width,
                                                   int height,
                                                   Camera.Parameters parameters) {
    double targetRatio = (double) width / height;
    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;
    if (displayOrientation == 90 || displayOrientation == 270) {
        targetRatio = (double) height / width;
    }
    List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
    Collections.sort(sizes,
            Collections.reverseOrder(new SizeComparator()));
    for (Camera.Size size : sizes) {
        double ratio = (double) size.width / size.height;
        if (Math.abs(ratio - targetRatio) < minDiff) {
            optimalSize = size;
            minDiff = Math.abs(ratio - targetRatio);
        }
        if (minDiff < 0.0d) {
            break;
        }
    }
    return (optimalSize);
}

& this method to choose a suitable picture size:

public static Camera.Size getBiggestSafePictureSize(Camera.Parameters parameters) {
    Camera.Size result = null;
    long used = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
    long availableMemory = Runtime.getRuntime().maxMemory() - used;
    for (Camera.Size size : parameters.getSupportedPictureSizes()) {
        int newArea = size.width * size.height;
        long neededMemory = newArea * 4 * 4; // newArea * 4 Bytes/pixel * 4 needed copies of the bitmap (for safety :) )
        if (neededMemory > availableMemory)
            continue;
        if (result == null) {
            result = size;
        } else {
            int resultArea = result.width * result.height;
            if (newArea > resultArea) {
                result = size;
            }
        }
    }
    return (result);
}

& this is the camera preview element in the layout:

<FrameLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/cameraPreview"></FrameLayout>

& I'm following the official documentation for creating the camera preview itself

So, how to force the camera preview to show the exact photo that will be taken?

like image 952
AbdelHady Avatar asked Nov 16 '14 14:11

AbdelHady


2 Answers

Finally I found it :)

according to this answer & I quote:

While the typical camera is a 4:3 aspect ratio, the preview may also be available in 5:3 and 16:9 ratios and this seems to be accomplished by actually extending the horizontal field of view...

So we need to find a preview size & a picture size, both with 4:3 aspect ratio to be able to utilize the full angle of the camera, so I changed my code like this:

public static Camera.Size determineBestPreviewSize(Camera.Parameters parameters) {
    List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
    return determineBestSize(sizes);
}

public static Camera.Size determineBestPictureSize(Camera.Parameters parameters) {
    List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
    return determineBestSize(sizes);
}

protected static Camera.Size determineBestSize(List<Camera.Size> sizes) {
    Camera.Size bestSize = null;
    long used = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
    long availableMemory = Runtime.getRuntime().maxMemory() - used;
    for (Camera.Size currentSize : sizes) {
        int newArea = currentSize.width * currentSize.height;
        long neededMemory = newArea * 4 * 4; // newArea * 4 Bytes/pixel * 4 needed copies of the bitmap (for safety :) )
        boolean isDesiredRatio = (currentSize.width / 4) == (currentSize.height / 3);
        boolean isBetterSize = (bestSize == null || currentSize.width > bestSize.width);
        boolean isSafe = neededMemory < availableMemory;
        if (isDesiredRatio && isBetterSize && isSafe) {
            bestSize = currentSize;
        }
    }
    if (bestSize == null) {
        return sizes.get(0);
    }
    return bestSize;
}
like image 165
AbdelHady Avatar answered Oct 08 '22 10:10

AbdelHady


You should run the same loop over the sizes returned by parameters.getSupportedPictureSizes(), and not rely on the default picture size. Furthermore, I would rather look for the best corresponding pair of preview/picture sizes, and let the picture be cropped on the screen if this aspect ratio does not match the aspect ratio of cameraPreview layout.

like image 34
Alex Cohn Avatar answered Oct 08 '22 10:10

Alex Cohn