Android onPictureTaken导致质量差/错误的旋转图像

时间:2015-05-10 01:29:44

标签: android image camera

在我的应用程序中保存图像时出现问题。我在Android 4.4.4版上使用Android相机api 1(pre api 21)。设备是OnePlus One。

当我拍摄照片时,我的应用程序中的内置相机似乎可以保存质量较差的图像并逆时针旋转90度(-90)。

以下是图片的示例。

使用默认Android相机应用程序(已保存图像)的纵向视图:

enter image description here

使用内置应用相机的纵向视图:

enter image description here

使用内置应用相机保存的图片(已保存的图片):

enter image description here

第一个问题,旋转方向

现在我猜测的轮换是由于这个原因(如果我没有更改setDisplayOrientation,相机在我的应用程序中有偏差):

public void refreshCamera(Camera camera) {
    if (holder.getSurface() == null) {
        // preview surface does not exist
        return;
    }
    // stop preview before making changes
    try {
        camera.stopPreview();
    } catch (Exception e) {
        // ignore: tried to stop a non-existent preview
    }

    int rotation = ((WindowManager)activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
    int degrees = 0;

    // specifically for back facing camera
    switch (rotation) {
        case Surface.ROTATION_0:
            degrees = 90;
            break;
        case Surface.ROTATION_90:
            degrees = 0;
            break;
        case Surface.ROTATION_180:
            degrees = 270;
            break;
        case Surface.ROTATION_270:
            degrees = 180;
            break;
    }

    camera.setDisplayOrientation(degrees);
    setCamera(camera);
    try {
        camera.setPreviewDisplay(holder);
        camera.startPreview();
    } catch (Exception e) {
        Log.d(VIEW_LOG_TAG, "Error starting camera preview: " + e.getMessage());
    }
}

为了解决这个问题,我想我可以在保存图像时旋转图像,但这似乎浪费了编写这种方法的代码。

第二个问题,质量

对于为什么质量如此糟糕,我无能为力,我猜它与此有关:

private PictureCallback getPictureCallback() {
    return new PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            // save picture on seperate thread so camera can refresh quicker
            new Thread(new SavePicThread(data)).start();
            // refresh camera to continue preview
            cameraPreview.refreshCamera(camera);
        }
    };
}

public class SavePicThread implements Runnable {
    byte[] data;
    public SavePicThread(byte[] data) {
        this.data = data;
    }
    public void run() {
        // make a new picture file
        File pictureFile = getOutputMediaFile();

        if (pictureFile == null) {
            return;
        }
        try {
            // write to the file
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.flush();
            fos.close();
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast toast = Toast.makeText(getActivity(), "Picture saved", Toast.LENGTH_SHORT);
                    toast.show();
                }
            });
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // make the picture visible to the rest of the device
        galleryAddPic(pictureFile);
    }
}

// make picture and save to a folder
private File getOutputMediaFile() {
    // make a new file directory inside the "sdcard" folder
    // File mediaStorageDir = new File("/sdcard/", "fela"); // private pic for app

    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), "fela");

    // if the directory does not exist
    if (!mediaStorageDir.exists()) {
        // if you cannot make this directory return
        if (!mediaStorageDir.mkdirs()) {
            return null;
        }
    }

    // take the current timeStamp
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;
    // and make a media file:
    mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");

    return mediaFile;
}

/**
 * makes the image visible for the device (gallery)
 * @param pic file
 */
private void galleryAddPic(File file) {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    Uri contentUri = Uri.fromFile(file);
    mediaScanIntent.setData(contentUri);
    getActivity().sendBroadcast(mediaScanIntent);
}

一直在看教程,这几乎就是他们的内容!

1 个答案:

答案 0 :(得分:0)

据我所知,您找到了图像质量的解决方案。实际上,您不能假设默认的PictureSize是设备上可用的最佳质量;您应该使用getSupportedPictureSizes(),然后使用setPictureSize()

关于轮换,情况更加繁琐。相机参数支持setRotation()方法

  

设置相对于摄像机方向的顺时针旋转角度(以度为单位)。这会影响从JPEG Camera.PictureCallback返回的图片。相机驱动程序可以在EXIF标题中设置方向而不旋转图片。或者驱动程序可能会旋转图片和EXIF缩略图。如果旋转Jpeg图片,则EXIF标题中的方向将丢失或为1(第0行为顶部,第0列为左侧)。

从描述中可以看出,某些设备实际上会正确保存JPEG图像,但其他设备只会保存EXIF标题。

不幸的是,对于许多图像查看器应用程序而言,方向标记是不够的 - 例如,对于Windows内置图像预览。可以以编程方式执行全尺寸图像的旋转,但这是一个时间和(更重要的)耗费内存的任务。最简单的方法是create a bitmap and rotate it

许多人使用缩放位图来更快地旋转并使用更少的内存。但这将不可避免地打败你获得最佳画质的目的。