David Xu
David Xu

Reputation: 5597

Android camera - taken picture inconsistent with preview

I'm having an issue with the camera on Android, basically when I take a photo with the Camera class, the taken output picture actually shows more than the preview. The best way to put it would be the preview is cropped. How would I fix this?

I've run the app on Samsung Galaxy S4, Samsung Galaxy S3, HTC One M8 and Nexus One and all exhibit this same issue. (All running Android 4.0 ICS)

The camera preview is full screen in an Activity with no Action Bar and the status bar hidden.

The camera i'm trying to create is portrait so I've set displayOrientation to 90.

The code I use for determining preview size and output photo size is as follows (I believe the problem is most likely here somewhere):

public static Camera.Size getBestAspectPreviewSize(int displayOrientation,
                                                 int width,
                                                 int height,
                                                 Camera.Parameters parameters,
                                                 double closeEnough) {
double targetRatio=(double)width / height;
Camera.Size optimalSize=null;
double minDiff=Double.MAX_VALUE;

if (displayOrientation == 90 || displayOrientation == 270) {
  targetRatio=(double)height / width;
}

List<Size> sizes=parameters.getSupportedPreviewSizes();

Collections.sort(sizes,
                 Collections.reverseOrder(new SizeComparator()));

for (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 < closeEnough) {
    break;
  }
}

return(optimalSize);
}


 public static Camera.Size getLargestPictureSize(CameraHost host,
                                              Camera.Parameters parameters,
                                              boolean enforceProfile) {
Camera.Size result=null;

for (Camera.Size size : parameters.getSupportedPictureSizes()) {

  // android.util.Log.d("CWAC-Camera",
  // String.format("%d x %d", size.width, size.height));

  if (!enforceProfile
      || (size.height <= host.getDeviceProfile()
                             .getMaxPictureHeight() && size.height >= host.getDeviceProfile()
                                                                          .getMinPictureHeight())) {
    if (result == null) {
      result=size;
    }
    else {
      int resultArea=result.width * result.height;
      int newArea=size.width * size.height;

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

if (result == null && enforceProfile) {
  result=getLargestPictureSize(host, parameters, false);
}

return(result);
 }

Size comparator class:

private static class SizeComparator implements
  Comparator<Camera.Size> {
@Override
public int compare(Size lhs, Size rhs) {
  int left=lhs.width * lhs.height;
  int right=rhs.width * rhs.height;

  if (left < right) {
    return(-1);
  }
  else if (left > right) {
    return(1);
  }

  return(0);
}
}

This is using cwac-camera and using SimpleCameraHost with no changes.

Any help is appreciated!

Upvotes: 0

Views: 879

Answers (1)

CommonsWare
CommonsWare

Reputation: 1006869

How would I fix this?

If you are using the full-bleed preview, the preview will be cropped in most cases, as the aspect ratio of the CameraView is unlikely to match the aspect ratio of the preview frames.

Quoting the documentation:

The original default behavior of CameraFragment and CameraView was to show the entire preview, as supplied by the underlying Camera API. Since the aspect ratio of the preview frames may be different than the aspect ratio of the CameraView, this results in a "letterbox" effect, where the background will show through on one axis on the sides.

The new default behavior is to completely fill the CameraView, at the cost of cropping off some of the actual preview frame, what is known as "full-bleed preview" (stealing some terminology from the world of print media).

To control this behavior:

  • Have your CameraHost return true or false from useFullBleedPreview()

  • Or, call useFullBleedPreview() on your SimpleCameraHost.Builder, passing in a boolean value to use by default.

Note that the pictures and videos taken by this library are unaffected by useFullBleedPreview(). Hence, if useFullBleedPreview() returns true, the picture or video may contain additional content on the edges that was not visible in the preview.

Upvotes: 1

Related Questions