12

I am on a Camera App which taking basic pictures. I have an issue when I get the best optimal preview size.

In fact, with this first code :

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    if (isPreviewRunning) {
        mCamera.stopPreview();
    }
    Camera.Parameters parameters = mCamera.getParameters();
    mCamera.setParameters(parameters);
    mCamera.startPreview();
    isPreviewRunning = true;
}

The picture has a good quality :

http://img689.imageshack.us/i/04042011172937.jpg/

But, with this code :

private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.05;
    double targetRatio = (double) w / h;
    if (sizes == null) return null;

    Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    // Try to find an size match aspect ratio and size
    for (Size size : sizes) {
        double ratio = (double) size.width / size.height;
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
        if (Math.abs(size.height - targetHeight) < minDiff) {
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        }
    }

    // Cannot find the one match the aspect ratio, ignore the requirement
    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }
    return optimalSize;
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    // Now that the size is known, set up the camera parameters and begin
    // the preview.
    if (isPreviewRunning) {
        mCamera.stopPreview();
    }
    Camera.Parameters parameters = mCamera.getParameters();

    List<Size> sizes = parameters.getSupportedPreviewSizes();
    Size optimalSize = getOptimalPreviewSize(sizes, w, h);
    parameters.setPreviewSize(optimalSize.width, optimalSize.height);

    mCamera.setParameters(parameters);
    mCamera.startPreview();
    isPreviewRunning =true;
}

The picture is totally distorted :

http://img97.imageshack.us/i/04042011173220.jpg/

How can I resolve this problem??

I am using a HTC Desire HD.

It is probably my saving method too ? :

PictureCallback mPictureCallbackJpeg = new PictureCallback() {      
        public void onPictureTaken(byte[] imageData, Camera camera) {
    ....

    BitmapFactory.Options options=new BitmapFactory.Options();
                            options.inSampleSize = 5; 
                            Bitmap myImage = BitmapFactory.decodeByteArray(imageData, 0,imageData.length,options);
                            FileOutputStream fOut = new FileOutputStream(path + "/"+fl);
                            BufferedOutputStream bos = new BufferedOutputStream(fOut);


    myImage.compress(CompressFormat.JPEG, 100, bos);
    bos.flush();
    bos.close();
    ....
}

Thanks

Lee Han Kyeol
  • 2,371
  • 2
  • 29
  • 44
jc_35
  • 1,073
  • 1
  • 9
  • 15

2 Answers2

26

I just suffered through the same problem, and came up with a similar but lighter weight solution. I don't see anything wrong with your saving method though.

private Camera.Size getBestPreviewSize(int width, int height)
{
        Camera.Size result=null;    
        Camera.Parameters p = camera.getParameters();
        for (Camera.Size size : p.getSupportedPreviewSizes()) {
            if (size.width<=width && size.height<=height) {
                if (result==null) {
                    result=size;
                } else {
                    int resultArea=result.width*result.height;
                    int newArea=size.width*size.height;

                    if (newArea>resultArea) {
                        result=size;
                    }
                }
            }
        }
    return result;

}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    //This line helped me set the preview Display Orientation to Portrait
            //Only works API Level 8 and higher unfortunately.

    camera.setDisplayOrientation(90);

    Camera.Parameters parameters = camera.getParameters();
    Camera.Size size = getBestPreviewSize(width, height);
    parameters.setPreviewSize(size.width, size.height);
    camera.setParameters(parameters);
    camera.startPreview();

}
Seantron
  • 519
  • 6
  • 10
  • 2
    I had a problem with getOptimalPreviewSize on HTC Desire. Function getSupportedPreviewSizes returns sizes: 1280x720, 840x480, 768:432, etc. Call getOptimalPreviewSize(480,800) returns 1280x720. As result, call of setPreviewDisplay hangs the application (it was necessary to restart the device to restore camera functionality). As result, I used getBestPreviewSize with a little modification: if ((size.width <= width && size.height <= height) || (size.height <= width && size.width <= height)) { ... It works fine. – dvpublic Oct 24 '12 at 01:12
  • Yet another reason I hate Android dev, but thanks for that info. Which OS on the HTC Desire by the way? – Seantron Oct 28 '12 at 01:14
  • It was HTC Desire with Android 2.2.2 – dvpublic Oct 30 '12 at 10:13
5

The best way is to get preview size with the closest aspect ratio:

Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
        Camera.Size result=null;
        float dr = Float.MAX_VALUE;
        float ratio = (float)width/(float)height;

        for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
            float r = (float)size.width/(float)size.height;
            if( Math.abs(r - ratio) < dr && size.width <= width && size.height <= height ) {
                dr = Math.abs(r - ratio);
                result = size;
            }
        }

        return result;
    }

Where width and height parameters are your surface size.

Max
  • 16,679
  • 4
  • 44
  • 57
  • 2
    This does display the correct aspect ratio, but when you capture the photo its crops the sides of it. How would you go about preventing that from happening? – Will Jamieson Jun 25 '13 at 18:54
  • Same happening with me. Will, were you able to solve your problem? – Prateek Aug 19 '14 at 20:09
  • 1
    @WillJamieson you must also choose the picture size from the list returned from getSupportedPictureSizes(). This size may be different from the chosen preview size (usually bigger), but you should keep same aspect ratio. – Alex Cohn Sep 05 '17 at 11:08