相机尺寸和4:3宽高比不匹配 [英] Camera Size and 4:3 aspect ratio is not matching

查看:274
本文介绍了相机尺寸和4:3宽高比不匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用相机的Surface视图显示相机和拍摄照片
i需要相机预览为特定的比例4:3,instagram是一个正方形,我是一个矩形。



如果你看看instagram应用程序的相机预览没有伸展或压缩,但在我的它的压缩。



这是我的相机预览类:

  class CustomCam extends SurfaceView implements SurfaceHolder.Callback {

private final String TAG = PIC-FRAME;
private static final double ASPECT_RATIO = 4.0 / 3.0;
private static final int PICTURE_SIZE_MAX_WIDTH = 1280;
private static final int PREVIEW_SIZE_MAX_WIDTH = 640;

private SurfaceHolder mHolder;
私人相机mCamera;
private显示显示;
public List< Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;

public CustomCam(Activity context,Camera camera){
super(context);
mCamera = camera;
display =((WindowManager)context.getSystemService(Context.WINDOW_SERVICE))。getDefaultDisplay();

mSupportedPreviewSizes = mCamera.getParameters()。getSupportedPreviewSizes();
for(Camera.Size str:mSupportedPreviewSizes)
Log.e(TAG,str.width +/+ str.height);
//安装一个SurfaceHolder.Callback,这样当
//底层表面被创建和销毁时我们就会收到通知。
mHolder = getHolder();
mHolder.addCallback(this);
//弃用设置,但在3.0之前的Android版本中需要
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

setKeepScreenOn(true);
}

public void surfaceDestroyed(SurfaceHolder holder){
//空。请小心在您的活动中释放相机预览。
this.getHolder()。removeCallback(this);
}

@Override
public void surfaceCreated(SurfaceHolder holder){

}

private Camera.Size getBestPreviewSize int width,int height){
Camera.Size result = null;
Camera.Parameters p = mCamera.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;
}
}
}
}
返回结果;

}

@Override
public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){
//这行帮助了我将预览显示方向设置为纵向
//仅适用于API级别8和更高版本。

try {
Camera.Parameters parameters = mCamera.getParameters();
// Camera.Size size = getBestPreviewSize(width,height);
// Camera.Size size = getOptimalPreviewSize(mSupportedPreviewSizes,width,height);
// parameters.setPreviewSize(mPreviewSize.width,mPreviewSize.height);
// initialCameraPictureSize(parameters);
// parameters.setPreviewSize(size.width,size.height);

Camera.Size bestPreviewSize = determineBestPreviewSize(parameters);
Camera.Size bestPictureSize = determineBestPictureSize(parameters);

parameter.setPreviewSize(bestPreviewSize.width,bestPreviewSize.height);
parameter.setPictureSize(bestPictureSize.width,bestPictureSize.height);

parameter.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCamera.setDisplayOrientation(90);
mCamera.getParameters()。setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setPreviewDisplay(mHolder);
mCamera.setParameters(parameters);
mCamera.startPreview();

} catch(IOException e){
e.printStackTrace();
}

}

public static void initialCameraPictureSize(Camera.Parameters parameters){

List list = parameters.getSupportedPictureSizes();
if(list!= null){
Camera.Size size = null;
迭代器迭代器= list.iterator();
do {
if(!iterator.hasNext())
break;
Camera.Size size1 =(Camera.Size)iterator.next();
if(Math.abs(3F *((float)size1.width / 4F) - (float)size1.height)< 0.1F *(float)size1.width& || size1.height> size.height&& size1.width< 3000))
size = size1;
} while(true);
if(size!= null)
parameter.setPictureSize(size.width,size.height);
else
Log.e(CameraSettings,找不到支持的图片大小);
}
}

private Camera.Size getOptimalPreviewSize(List< Camera.Size> sizes,int w,int h){
final double ASPECT_TOLERANCE = 0.1;
double targetRatio =(double)h / w;

if(sizes == null)return null;

Camera.Size optimumSize = null;
double minDiff = Double.MAX_VALUE;

int targetHeight = h;

for(Camera.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){
optimumSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}

if(optimalSize == null){
minDiff = Double.MAX_VALUE;
for(Camera.Size size:sizes){
if(Math.abs(size.height - targetHeight)< minDiff){
optimumSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimumSize;
}

/ **
*测量视图及其内容以确定测量的宽度和
*测量的高度。
* /
@Override
protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);

if(width> height * ASPECT_RATIO){
width =(int)(height * ASPECT_RATIO + 0.5);
} else {
height =(int)(width / ASPECT_RATIO + 0.5);
}

setMeasuredDimension(width,height);
}

protected Camera.Size determineBestSize(List< Camera.Size> sizes,int widthThreshold){
Camera.Size bestSize = null;

for(Camera.Size currentSize:sizes){
boolean isDesiredRatio =(currentSize.width / 4)==(currentSize.height / 3);
boolean isBetterSize =(bestSize == null || currentSize.width> bestSize.width);
boolean isInBounds = currentSize.width< = PICTURE_SIZE_MAX_WIDTH;

if(isDesiredRatio&& isInBounds&& isBetterSize){
bestSize = currentSize;
}
}

if(bestSize == null){
return sizes.get(0);
}

return bestSize;
}

private Camera.Size determineBestPreviewSize(Camera.Parameters parameters){
List< Camera.Size> sizes = parameters.getSupportedPreviewSizes();

return determineBestSize(sizes,PREVIEW_SIZE_MAX_WIDTH);
}

private Camera.Size determineBestPictureSize(Camera.Parameters parameters){
List< Camera.Size> sizes = parameters.getSupportedPictureSizes();

return determineBestSize(sizes,PICTURE_SIZE_MAX_WIDTH);
}
}

我的自定义框架布局:

  CustomFrameLayout扩展FrameLayout {

私人静态最终浮动RATIO = 4f / 3f;

public CustomFrameLayout(Context context){
super(context);
}

public CustomFrameLayout(Context context,AttributeSet attrs){
super(context,attrs);
}

public CustomFrameLayout(Context context,AttributeSet attrs,int defStyleAttr){
super(context,attrs,defStyleAttr);
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CustomFrameLayout(Context context,AttributeSet attrs,int defStyleAttr,
int defStyleRes){
super(context,attrs,defStyleAttr,defStyleRes);
}

@Override
protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){
super.onMeasure(widthMeasureSpec,heightMeasureSpec);

int width = getMeasuredWidth();
int height = getMeasuredHeight();
int widthWithoutPadding = width - getPaddingLeft() - getPaddingRight();
int heigthWithoutPadding = height - getPaddingTop() - getPaddingBottom();

int maxWidth =(int)(heigthWithoutPadding * RATIO);
int maxHeight =(int)(widthWithoutPadding / RATIO);

if(widthWithoutPadding> maxWidth){
width = maxWidth + getPaddingLeft()+ getPaddingRight();
} else {
height = maxHeight + getPaddingTop()+ getPaddingBottom();
}

setMeasuredDimension(width,height);
}

但是凸轮预览压缩在框架布局内如何解决?问题 ?



更新



一些研究发现,
ASPECT_RATIO = 4:3

  @Override 
protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);

if(width> height * ASPECT_RATIO){
width =(int)(height * ASPECT_RATIO + 0.5);
} else {
height =(int)(width / ASPECT_RATIO + 0.5);
}

setMeasuredDimension(width,height);
}

解决方案

所以我想到一个解决方案,可能(就像Instagram的),使你的相机全尺寸,然后隐藏布局的一些区域,使其看起来像4:3的比例。然后通过使用一些裁剪机制必须剪切图像,使图像看起来像4:3。



说我总是从顶部显示4:3的比例和休息的下面部分是隐藏的,所以现在只要我拍照片我想把图像从顶部到4:3的比例,并保存。



实现这个,这是一个可行的解决方案吗?

解决方案

据我所知,你当前的问题是如何裁剪图像接收和显示它。这里有一个小例子:

  @OnClick(R.id.btn_record_start)
public void takePhoto b $ b if(null!= actions){
EasyCamera.PictureCallback callback = new EasyCamera.PictureCallback(){
public void onPictureTaken(byte [] data,EasyCamera.CameraActions actions){
// store picture
Bitmap bitmap = ImageUtils.getExifOrientedBitmap(data);
if((portrait&& bitmap.getHeight()< bitmap.getWidth())||
(!portrait&&& bitmap.getHeight()> bitmap.getWidth )){
Matrix matrix = new Matrix();
matrix.postRotate(90);
bitmap =
Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),
matrix,true);
}

Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId,info);
if(Camera.CameraInfo.CAMERA_FACING_FRONT == info.facing){
Matrix matrix = new Matrix();
matrix.postRotate(180);
bitmap =
Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),
matrix,true);
}
showPhoto(bitmap);
}
};
actions.takePicture(EasyCamera.Callbacks.create()
.withJpegCallback(callback));
}
}

这是我用来处理图片的方法拍摄照片后的方向。
它可以很容易地修改,以处理裁剪太。要实现这一点,你必须指定图像的目标宽度和高度(目前我发送的整个位图的大小)。一个可能的解决方案是获取图片的高度并删除过多的宽度 - 因此您发送到 createBitmap 方法将 bitmap.getHeight()* 4.0 / 3.0 bitmap.getHeight()。这是修改后的示例:

  @OnClick(R.id.btn_record_start)
public void takePhoto b $ b if(null!= actions){
EasyCamera.PictureCallback callback = new EasyCamera.PictureCallback(){
public void onPictureTaken(byte [] data,EasyCamera.CameraActions actions){
// store picture
Bitmap bitmap = ImageUtils.getExifOrientedBitmap(data);
if((portrait&& bitmap.getHeight()< bitmap.getWidth())||
(!portrait&&& bitmap.getHeight()> bitmap.getWidth )){
Matrix matrix = new Matrix();
Matrix.postRotate(90);
bitmap =
Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),
matrix,true);
}

Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId,info);
if(Camera.CameraInfo.CAMERA_FACING_FRONT == info.facing){
Matrix matrix = new Matrix();
matrix.postRotate(180);
bitmap =
Bitmap.createBitmap(bitmap,0,0,(int)(bitmap.getHeight()* 4.0 / 3.0),bitmap.getHeight(),
matrix,true);
}
showPhoto(bitmap);
}
}
actions.takePicture(EasyCamera.Callbacks.create()
.withJpegCallback(callback));
}
}

注意事项:




  • 您可以用 ASPECT_RATIO 4.0 / 3.0 c $ c> variable

  • 我的示例是执行图片旋转,使其看起来像是在预览期间,在您的情况下,所需的UI可能不同。

  • 我使用 EasyCamera 图书库简化了相机管理



以下是我使用的其他ImageUtils方法:



getExifOrientedBitmap / p>

  public static Bitmap getExifOrientedBitmap(byte [] data){
File newPhotoFile = writeToFile(data);
if(newPhotoFile == null){
return null;
}

位图位图= BitmapFactory.decodeByteArray(data,0,data.length);
bitmap = fixOrientationIfNeeded(newPhotoFile,bitmap);
newPhotoFile.delete();
return bitmap;
}

writeToFile

  @Nullable 
public static File writeToFile(byte [] data){
File dir = PhotoMessageComposer.getPhotoDir
if(!dir.exists()){
dir.mkdir();
}
文件newPhotoFile =新文件(dir,ImageUtils.getRandomFilename());
FileOutputStream fos = null;
try
{
fos = new FileOutputStream(newPhotoFile);
fos.write(data);
fos.close();
} catch(异常错误){
return null;
} finally {
try {
if(fos!= null){
fos.close();
}
} catch(IOException e){
e.printStackTrace();
}
}
return newPhotoFile;
}

getPhotoDir

  @NonNull 
public static File getPhotoDir(){
return new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
PICTURES_DIR);
}

getRandomFileName

  public static String getRandomFilename(){
return UUID.randomUUID()toString()+ IMAGE_EXTENSION;
}

fixOrientationIfNeeded

  public static Bitmap fixOrientationIfNeeded(File sourceFile,Bitmap source){
ExifInterface exif;
try {
exif = new ExifInterface(sourceFile.getAbsolutePath());
int exifOrientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);

if(exifOrientation!= ExifInterface.ORIENTATION_NORMAL){
Matrix matrix = new Matrix();
int angle = findRotationAngle(exifOrientation);
matrix.postRotate(angle);
source = Bitmap.createBitmap(source,0,0,source.getWidth(),
source.getHeight(),matrix,true);
return source;
}
} catch(IOException e){
e.printStackTrace();
}
return source;
}

findRotationAngle

  protected static int findRotationAngle(int exifOrientation){
switch(exifOrientation){
case ExifInterface.ORIENTATION_ROTATE_270:
return 270;
case ExifInterface.ORIENTATION_ROTATE_180:
return 180;
case ExifInterface.ORIENTATION_ROTATE_90:
return 90;
默认值:
return 0;
}
}

从这个 ImageUtils 类实现已经有几年了,所以可能有更好的方法来处理这些操作。他们应该是足够好的起点,虽然。


I am using the Surface View of Camera to show camera and take a photo i need the camera preview to be of specific ration 4:3, instagram is a square and mine is a rectangle.

If you look at the instagram app the camera preview is not stretching or compressed, but in mine its compressed.

This is my Camera Preview Class :

class CustomCam extends SurfaceView implements SurfaceHolder.Callback {

    private final String TAG = "PIC-FRAME";
    private static final double ASPECT_RATIO = 4.0 / 3.0;
    private static final int PICTURE_SIZE_MAX_WIDTH = 1280;
    private static final int PREVIEW_SIZE_MAX_WIDTH = 640;

    private SurfaceHolder mHolder;
    private Camera mCamera;
    private Display display;
    public List<Camera.Size> mSupportedPreviewSizes;
    private Camera.Size mPreviewSize;

    public CustomCam(Activity context, Camera camera) {
        super(context);
        mCamera = camera;
        display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

        mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
        for (Camera.Size str : mSupportedPreviewSizes)
            Log.e(TAG, str.width + "/" + str.height);
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        setKeepScreenOn(true);
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
        this.getHolder().removeCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

    }

    private Camera.Size getBestPreviewSize(int width, int height) {
        Camera.Size result = null;
        Camera.Parameters p = mCamera.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.

        try {
            Camera.Parameters parameters = mCamera.getParameters();
//        Camera.Size size = getBestPreviewSize(width, height);
//            Camera.Size size = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
//            parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
//            initialCameraPictureSize(parameters);
//            parameters.setPreviewSize(size.width, size.height);

            Camera.Size bestPreviewSize = determineBestPreviewSize(parameters);
            Camera.Size bestPictureSize = determineBestPictureSize(parameters);

            parameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);
            parameters.setPictureSize(bestPictureSize.width, bestPictureSize.height);

            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
            mCamera.setDisplayOrientation(90);
            mCamera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            mCamera.setPreviewDisplay(mHolder);
            mCamera.setParameters(parameters);
            mCamera.startPreview();

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void initialCameraPictureSize(Camera.Parameters parameters) {

        List list = parameters.getSupportedPictureSizes();
        if (list != null) {
            Camera.Size size = null;
            Iterator iterator = list.iterator();
            do {
                if (!iterator.hasNext())
                    break;
                Camera.Size size1 = (Camera.Size) iterator.next();
                if (Math.abs(3F * ((float) size1.width / 4F) - (float) size1.height) < 0.1F * (float) size1.width && (size == null || size1.height > size.height && size1.width < 3000))
                    size = size1;
            } while (true);
            if (size != null)
                parameters.setPictureSize(size.width, size.height);
            else
                Log.e("CameraSettings", "No supported picture size found");
        }
    }

    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) h / w;

        if (sizes == null) return null;

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

        int targetHeight = h;

        for (Camera.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);
            }
        }

        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

    /**
     * Measure the view and its content to determine the measured width and the
     * measured height.
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);

        if (width > height * ASPECT_RATIO) {
            width = (int) (height * ASPECT_RATIO + 0.5);
        } else {
            height = (int) (width / ASPECT_RATIO + 0.5);
        }

        setMeasuredDimension(width, height);
    }

    protected Camera.Size determineBestSize(List<Camera.Size> sizes, int widthThreshold) {
        Camera.Size bestSize = null;

        for (Camera.Size currentSize : sizes) {
            boolean isDesiredRatio = (currentSize.width / 4) == (currentSize.height / 3);
            boolean isBetterSize = (bestSize == null || currentSize.width > bestSize.width);
            boolean isInBounds = currentSize.width <= PICTURE_SIZE_MAX_WIDTH;

            if (isDesiredRatio && isInBounds && isBetterSize) {
                bestSize = currentSize;
            }
        }

        if (bestSize == null) {
            return sizes.get(0);
        }

        return bestSize;
    }

    private Camera.Size determineBestPreviewSize(Camera.Parameters parameters) {
        List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();

        return determineBestSize(sizes, PREVIEW_SIZE_MAX_WIDTH);
    }

    private Camera.Size determineBestPictureSize(Camera.Parameters parameters) {
        List<Camera.Size> sizes = parameters.getSupportedPictureSizes();

        return determineBestSize(sizes, PICTURE_SIZE_MAX_WIDTH);
    }
}

My Custom Frame layout :

CustomFrameLayout extends FrameLayout {

    private static final float RATIO = 4f / 3f;

    public CustomFrameLayout(Context context) {
        super(context);
    }

    public CustomFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public CustomFrameLayout(Context context, AttributeSet attrs, int defStyleAttr,
                            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        int widthWithoutPadding = width - getPaddingLeft() - getPaddingRight();
        int heigthWithoutPadding = height - getPaddingTop() - getPaddingBottom();

        int maxWidth = (int) (heigthWithoutPadding * RATIO);
        int maxHeight = (int) (widthWithoutPadding / RATIO);

        if (widthWithoutPadding > maxWidth) {
            width = maxWidth + getPaddingLeft() + getPaddingRight();
        } else {
            height = maxHeight + getPaddingTop() + getPaddingBottom();
        }

        setMeasuredDimension(width, height);
    }

But the cam preview is compressed inside the frame layout how can i solve this ?issue ?

Update

Ok after some research got to know that its because of onMeasure ASPECT_RATIO = 4:3

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);

        if (width > height * ASPECT_RATIO) {
            width = (int) (height * ASPECT_RATIO + 0.5);
        } else {
            height = (int) (width / ASPECT_RATIO + 0.5);
        }

        setMeasuredDimension(width, height);
    }

Solution

So i was thinking of a solution, might be (just like Instagram does) to make your camera at full size and then hide some areas of the layout just to make it look like its 4:3 ratio.Then by using some crop mechanism have to cut the image to make the image look like 4:3.

Say i always show preview from top with 4:3 ratio and rest of the below part is hidden, so now as soon as i take photo i want to crop the image from top to 4:3 ratio and save it.

How can i achieve this, is this a feasible solution ?

解决方案

As far as I understand, your current problem is how to crop the image you receive and show it. Here is a small example:

@OnClick(R.id.btn_record_start)
    public void takePhoto() {
        if (null != actions) {
            EasyCamera.PictureCallback callback = new EasyCamera.PictureCallback() {
                public void onPictureTaken(byte[] data, EasyCamera.CameraActions actions) {
                    // store picture
                    Bitmap bitmap = ImageUtils.getExifOrientedBitmap(data);
                    if ((portrait && bitmap.getHeight() < bitmap.getWidth()) ||
                        (!portrait && bitmap.getHeight() > bitmap.getWidth())) {
                        Matrix matrix = new Matrix();
                        matrix.postRotate(90);
                        bitmap =
                            Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
                                matrix, true);
                    }

                    Camera.CameraInfo info = new Camera.CameraInfo();
                    Camera.getCameraInfo(cameraId, info);
                    if (Camera.CameraInfo.CAMERA_FACING_FRONT == info.facing) {
                        Matrix matrix = new Matrix();
                        matrix.postRotate(180);
                        bitmap =
                            Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
                                matrix, true);
                    }
                    showPhoto(bitmap);
                }
            };
            actions.takePicture(EasyCamera.Callbacks.create()
                .withJpegCallback(callback));
        }
    }

This is a method I'm using to handle image orientation after the photo is taken. It can easily be modified to handle cropping too. To achieve this, you have to specify the target width and height of the image (currently I'm sending the whole bitmap's size). A possible solution is to take the image's height and delete the excessive width - so the params you send to the createBitmap method would be bitmap.getHeight() * 4.0 / 3.0 and bitmap.getHeight(). Here is the modified example:

@OnClick(R.id.btn_record_start)
public void takePhoto() {
    if (null != actions) {
        EasyCamera.PictureCallback callback = new EasyCamera.PictureCallback() {
            public void onPictureTaken(byte[] data, EasyCamera.CameraActions actions) {
                // store picture
                Bitmap bitmap = ImageUtils.getExifOrientedBitmap(data);
                if ((portrait && bitmap.getHeight() < bitmap.getWidth()) ||
                    (!portrait && bitmap.getHeight() > bitmap.getWidth())) {
                    Matrix matrix = new Matrix();
                    matrix.postRotate(90);
                    bitmap =
                        Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
                            matrix, true);
                }

                Camera.CameraInfo info = new Camera.CameraInfo();
                Camera.getCameraInfo(cameraId, info);
                if (Camera.CameraInfo.CAMERA_FACING_FRONT == info.facing) {
                    Matrix matrix = new Matrix();
                    matrix.postRotate(180);
                    bitmap =
                        Bitmap.createBitmap(bitmap, 0, 0, (int) (bitmap.getHeight() * 4.0 / 3.0), bitmap.getHeight(),
                            matrix, true);
                }
                showPhoto(bitmap);
            }
        };
        actions.takePicture(EasyCamera.Callbacks.create()
            .withJpegCallback(callback));
    }
}

A few things to note:

  • you can substitute the 4.0 / 3.0 part with the ASPECT_RATIO variable
  • my example is doing image rotation so it looks as it was during the preview, in your case the required UI might be different.
  • I'm using the EasyCamera library to simplify the camera management

Here are the other ImageUtils methods I'm using:

getExifOrientedBitmap

public static Bitmap getExifOrientedBitmap(byte[] data) {
    File newPhotoFile = writeToFile(data);
    if (newPhotoFile == null) {
        return null;
    }

    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
    bitmap = fixOrientationIfNeeded(newPhotoFile, bitmap);
    newPhotoFile.delete();
    return bitmap;
}

writeToFile

@Nullable
public static File writeToFile(byte[] data) {
    File dir = PhotoMessageComposer.getPhotoDir();
    if (!dir.exists()) {
        dir.mkdir();
    }
    File newPhotoFile = new File(dir, ImageUtils.getRandomFilename());
    FileOutputStream fos = null;
    try
    {
        fos = new FileOutputStream(newPhotoFile);
        fos.write(data);
        fos.close();
    } catch (Exception error) {
        return null;
    } finally {
        try {
            if (fos != null) {
                fos.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return newPhotoFile;
}

getPhotoDir

@NonNull
public static File getPhotoDir() {
    return new File(
        Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) +
            PICTURES_DIR);
}

getRandomFileName

public static String getRandomFilename() {
    return UUID.randomUUID().toString() + IMAGE_EXTENSION;
}

fixOrientationIfNeeded

public static Bitmap fixOrientationIfNeeded(File sourceFile, Bitmap source) {
    ExifInterface exif;
    try {
        exif = new ExifInterface(sourceFile.getAbsolutePath());
        int exifOrientation = exif.getAttributeInt(
                ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_NORMAL);

        if (exifOrientation != ExifInterface.ORIENTATION_NORMAL) {
            Matrix matrix = new Matrix();
            int angle = findRotationAngle(exifOrientation);
            matrix.postRotate(angle);
            source = Bitmap.createBitmap(source, 0, 0, source.getWidth(),
                    source.getHeight(), matrix, true);
            return source;
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return source;
}

findRotationAngle

protected static int findRotationAngle(int exifOrientation) {
    switch (exifOrientation) {
    case ExifInterface.ORIENTATION_ROTATE_270:
        return 270;
    case ExifInterface.ORIENTATION_ROTATE_180:
        return 180;
    case ExifInterface.ORIENTATION_ROTATE_90:
        return 90;
    default:
        return 0;
    }
}

P.S. It has been a few years since this ImageUtils class was implemented, so probably there are better ways to handle some of these operations. They should be good enough for a starting point though.

这篇关于相机尺寸和4:3宽高比不匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆