16

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?

AbdelHady
  • 9,334
  • 8
  • 56
  • 83

2 Answers2

23

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;
}
Community
  • 1
  • 1
AbdelHady
  • 9,334
  • 8
  • 56
  • 83
2

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.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • Well, I've edited the question to add the method I use for choosing the picture size. But I think it is all about the preview, because it is not showing the full possible angle of the camera like the picture taken. I tried to compare my preview surface with the one in Instagram, & Instagram's preview was showing the full angle like the picture taken by my code, so the problem is in my preview somehow – AbdelHady Nov 17 '14 at 11:20
  • What sizes do you get on your device? Are they of same aspect ratio? – Alex Cohn Nov 17 '14 at 13:20
  • Well, the methods I'm using gave me the following on LG-G2: the preview size is 1776X1080, & the picture size is 3264X2448 – AbdelHady Nov 17 '14 at 15:22
  • But still, as I told you, when I open Instagram on the same 2 devices it opens with a larger camera angle showing a preview just like the photo taken by my app, So the problem is in my preview! – AbdelHady Nov 17 '14 at 15:23
  • As I wrote, you have different aspect ratios: **5:3** for preview, and **4:3** for stills. If you want such picture, you should choose a preview size that is **4:3** too. Unfortunately, I could not find the full list of supported sizes for your device, but I know that **640x480** is supported. – Alex Cohn Nov 17 '14 at 16:04
  • Well, I've tried a picture size with the same aspect ratio, & still getting same results – AbdelHady Nov 18 '14 at 11:13
  • 1
    Please choose the preview size to fit **4:3**, not the other way around. – Alex Cohn Nov 18 '14 at 12:58
  • but a preview of 4:3 is skewed & doesn't fit the aspect ratio for the device screen – AbdelHady Nov 18 '14 at 13:52
  • First of all, let us see if this preview matches the still picture. Second, choose preview and picture sizes with **16:9** aspect ratio, and check if the two still fit. – Alex Cohn Nov 18 '14 at 14:38
  • I wasn't convinced that we should care about the aspect ratio of the picture size as my problem was in the preview, but after trying with different screen sizes I got it & added my full answer here that solved both issues (preview & picture issues). Thanks for your help. – AbdelHady Nov 18 '14 at 19:01
  • 16:9 i have both preview and picture sizes and not working - still image has like bigger "view" like bigger angle of view or something like this, 4:3 is bad, coz not match screen size, does anyone has any solution ? fo 16:9 or ideally for any match preview and picture sizes? – Stepan Maksymov Nov 19 '18 at 22:27