7

I've got a camera app that selects a preview size based on characteristics of my layout (primarily aspect ratio) and then selects a picture size based on other constraints (minimum dimensions). This often results in a picture with a different aspect ratio than the preview.

This is not a problem in itself, but I need to map a rectangle on my preview to an equivalent rectangle on the picture so that I can extract the same area of the final photo that was visible in the preview when the photo was taken.

I understand that having different aspect ratios means that there will be portions of the rectangles that do not overlap, but I'm not working close enough to the edges that this should be an issue.

If it's not possible to know how the preview and photo map directly, is there perhaps a way to determine how they each map to the native camera? If I could programatically detect the native camera aspect ratio I might be able to determine the cropping scheme.

goto10
  • 4,370
  • 1
  • 22
  • 33

2 Answers2

14

After some additional trial and error, I've made the following tentative conclusions:

  1. The largest image size provided by Camera.Parameters.getSupportedPictureSizes represents the native resolution of the camera.

  2. The content of other picture sizes, as well as well as the preview sizes provided by Camera.Parameters.getSupportedPreviewSizes, will match the native content when scaled up as described for Matrix.ScaleToFit.CENTER. (basically scale from the center until either top/bottom or left/right hits the bounds of the native resolution. Cropping occurs in the dimension that doesn't reach the bounds of the native resolution if the aspect ratios don't match

So, given that, my solution was to first scale the preview selection rectangle to the native camera picture size. Then, now that I know which area of the native resolution contains the content I want, I can do a similar operation to then scale that rectangle on the native resolution to the smaller picture that was actually captured per Camera.Parameters.setPictureSize.

timemanx
  • 4,493
  • 6
  • 34
  • 43
goto10
  • 4,370
  • 1
  • 22
  • 33
  • @mpellegr take a look at my question&answer I've posted recently: http://stackoverflow.com/questions/24394334/how-to-take-a-photo-of-the-same-aspect-ratio-as-in-preview-size/ it contains the code I've used in my project that uses this approach. – aga Jun 24 '14 at 19:05
  • This solution does't work when cropping occurs in both left-right and top-bottom. I come across this situation in huawei mate 8. – QuinnChen Oct 10 '16 at 07:12
0

I'm not too sure of what you're asking for, but the preview size actually is not determined by your layout. How it is displayed is determined by the layout. I'm assuming that you are using a SurfaceView to hold your preview/camera object.

You can get the actual preview size with this method http://developer.android.com/reference/android/hardware/Camera.Parameters.html#getPreviewSize()

And additionally, you can get the dimensions of your "displayed" preview by using the width and height you get from onSurfaceChanged() (It is part of the surfaceholder callback)

I'm not sure how important that is. But the main point is now that you know the actual preview size from getPreviewSize() you can do math and get your points accordingly.

This matches perfectly with onPreviewFrame(byte[] data, Camera camera) http://developer.android.com/reference/android/hardware/Camera.PreviewCallback.html

The byte[]data is in the YUV format, which you will probably need to convert to a bitmap before messing around with. But other than that it will have the same dimensions as what you get from calling getPreviewSize

Matthew
  • 21
  • 2
  • I'm sorry, I should have been more clear. *I* am choosing a preview size based on the constraints of my layout. I iterate through the available sizes to choose the one that best fits my layout. Regardless, how I choose my preview size is a separate issue, unrelated the subject of my question - how to map a rectangle of the preview to a rectangle of the picture when the two have different aspect ratios. Getting onPreviewFrame doesn't work for me because I need the picture taken by the camera, not just a frame of my preview. A preview frame will be much smaller, won't sync to the flash, etc. – goto10 Aug 09 '13 at 04:28