Android 相机预览在预览中拉伸,而不是在拍照后

Android Camera Preview Stretched in Preview, Not After Picture Taken

我有一个以纵向模式拍照的应用程序,一切正常,只是预览的尺寸与拍照后的图像尺寸不同。预览看起来失真且模糊,但会填满整个屏幕。拍照后,图像清晰,但要么比设备高度短,要么宽度更小(取决于使用的设备)。

下面是一些图像示例和我正在使用的一些代码。

拍照前:

拍照后:

纵向显示的相机预览代码:

protected int getRotationDegrees() {
    android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
    android.hardware.Camera.getCameraInfo(0, info);
    int rotation = ((WindowManager) mContext
            .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
            .getRotation();
    int degrees = 0;

    switch (rotation) {
        case Surface.ROTATION_0:
            degrees = 0;
            break;
        case Surface.ROTATION_90:
            degrees = 90;
            break;
        case Surface.ROTATION_180:
            degrees = 180;
            break;
        case Surface.ROTATION_270:
            degrees = 270;
            break;
    }

    int result = (info.orientation - degrees + 360) % 360;
    return result;
}

拍照后旋转图像的代码:

Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        Bitmap pictureBitmap = null;

        pictureBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);

        int rotationDegrees = mCameraPreview.getRotationDegrees();
        //mRotation = setCameraDisplayOrientation(MainActivity.this, Camera.CameraInfo.CAMERA_FACING_BACK, mCamera);
        Matrix matrix = new Matrix();
        matrix.postRotate(rotationDegrees);

        //Bitmap scaledBitmap = Bitmap.createScaledBitmap(pictureBitmap ,previewWidth ,previewHeight ,true);
        //Bitmap rotatedBitmap = Bitmap.createBitmap(scaledBitmap , 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
        Bitmap rotatedBitmap = Bitmap.createBitmap(pictureBitmap , 0, 0, pictureBitmap.getWidth(), pictureBitmap.getHeight(), matrix, true);

        //rotatedBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
        ImageView previewImage = (ImageView) findViewById(R.id.preview_image);
        previewImage.setImageBitmap(rotatedBitmap);
        mCameraPreview.setVisibility(View.INVISIBLE);
        mButtonCapture.setVisibility(View.INVISIBLE);
        //flCameraPreview.setVisibility(View.INVISIBLE);
    }
};

以前有人遇到过这个问题吗?我仍在尝试了解相机 API。提前致谢!

编辑:我用来 select 我的预览和图片尺寸的代码。

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

    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;
}

这种情况比较典型。预览框的纵横比可能与捕获的图像不完全相同。您可能会遍历支持的预览尺寸以选择最适合您的 SurfaceView 的尺寸(我希望您能正确地做到这一点)。您需要通过支持的图片尺寸进行类似的迭代。如果您找不到令人满意的纵横比相同的一对,则需要 "crop" 在视觉上 SurfaceView 或 ImageView。实现这种裁剪的最简单方法是用其他一些非透明视图覆盖视图中不需要的部分。

也可以将视图(SurfaceView 或 ImageView)强制"hang out",部分超出屏幕。

我在另一个 post 中找到了这个 comment 解决了我的问题!

它会更改视图的大小,使图像在始终尝试填满屏幕时不会被拉伸。