相机图片到位图会导致图像混乱

时间:2013-03-14 08:41:17

标签: android bitmap android-camera

这是我用来将图片保存到Bitmap的代码。这段代码是基于CyanogenMod的相机应用程序的代码,所以我认为它会正常工作,但不是。关于此问题最重要的一点是,在Nexus 4上进行测试时, Bitmap正在为使用后置摄像头拍摄的照片正确创建,但使用前置摄像头会产生下面的内容。

我用来创建Bitmap的代码:

private class XyzPictureCallback implements Camera.PictureCallback {

    @Override
    public void onPictureTaken (byte [] data, Camera camera) {
        Options options = new Options();
        options.inDither = false;
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;

        Bitmap image = BitmapFactory.decodeByteArray(data, 0, data.length, options);
    }
}

我尝试使用不同的Options(根本没有),但没有帮助。它可能是两个不同相机返回的像素格式,但当我运行getSupportedPictureFormats()时,它们都返回ImageFormat.JPEG ...

我的想法已经不多了......

我还应该提一下,使用data直接保存FileOutputStream正在创建一个合适的JPEG图像。所以问题必须与BitmapFactory以及我创建Bitmap

的方式有关

这是此代码生成的位图:

Broken image

编辑(24.03.2013):

花了几个小时试图解决这个问题后,我仍然没有真正的解决方法。 我发现只有当我将图片大小(使用Camera.Parameters.setPictureSize(int width, int height))设置为可通过调用{{1}获得的前置摄像头可用的最高分辨率时,才会出现此问题。 }。

导致问题的分辨率为1280x960。正如我之前提到的那样,这是最高分辨率。第二个最高的是1280x720,当我使用这个时,输出图片很好。我确实检查了相机吐出的格式,并且它一直是ImageFormat.JPEG所以我不认为像素格式是这里的问题......

编辑(08.03.2013): 打电话给拍照:

Camera.Parameters.getSupportedPictureSizes()

7 个答案:

答案 0 :(得分:3)

该相机不支持高度和宽度。这就是为什么它看起来像1280x720设置有效的原因。就像你将星际飞行设置为以你的显示器不支持的分辨率运行一样。

答案 1 :(得分:0)

试试这个

Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
imv.setImageBitmap(bmp);

ByteArrayOutputStream bos = new ByteArrayOutputStream();
bmp.compress(CompressFormat.JPEG, 70, bos);

答案 2 :(得分:0)

您是否尝试将null置于您的选项中?试试这个:

@Override
public void onPictureTaken(final byte[] data, Camera camera) {
    Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length, null);
    try {
        FileOutputStream out = new FileOutputStream(Environment.getExternalStorageDirectory().getAbsolutePath()+"/image.jpg");
        bm.compress(Bitmap.CompressFormat.JPEG, 95, out);
        out.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

答案 3 :(得分:0)

我建议不要在代码中设置图片大小,让相机返回可捕获的最佳图片。检查答案中给出的代码。 https://stackoverflow.com/a/9745780/2107118

答案 4 :(得分:0)

您是否正在设置从后置摄像头到前置摄像头的参数? 要测试的另一件事是前置摄像头,首先尝试不设置任何参数,只需使用默认设置来查看它是否可行。我在三星设备上遇到了类似的问题,但那是后置摄像头。 此外,您可能需要旋转使用前置摄像头拍摄的图像(对于三星设备,后置摄像头也需要)

public static Bitmap rotate(Bitmap bitmap, int degree) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        Matrix mtx = new Matrix();
        mtx.postRotate(degree);

        return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
    }

答案 5 :(得分:0)

  

我可能还应该提到使用a直接保存数据   FileOutputStream正在创建一个合适的JPEG图像。所以问题必须如此   使用BitmapFactory和我创建Bitmap的方式。

相机输出完全处理过的JPEG数据(希望如此),您可以将其写入磁盘。现在你应该尝试一下:

  1. 将文件转储到磁盘。
  2. 使用validation tool或PC上的某个图像编辑器检查该文件。
  3. 如果图像编辑器打开图像正常,请使用标准JPEG配置文件从该图像编辑器保存副本。
  4. BitmapFactory处理由图像编辑器保存的原始文件和文件,看看两者中是否有错误的位图。
  5. 如果图像有效且BitmapFactory仍然产生错误的位图,则问题出在BitmapFactory(不太可能),如果Camera输出的文件无效,则问题出在Camera(更有可能)

答案 6 :(得分:0)

这是我的代码,用于拍照,并将其保存在数据库中,而不会改变其质量。

首先你需要这个变量:

 private static final int CAMERA_PIC_REQUEST = 2500;
private Rect Padding = new Rect(-1,-1,-1,-1);
private Matrix matrix = new Matrix();
private Bitmap rotatedBitmap = null;
private Bitmap bm = null;
private Bitmap scaledBitmap= null;
private ExifInterface exif ;
private int rotation=0;
private final BitmapFactory.Options options = new BitmapFactory.Options();

然后根据您的应用(我使用按钮)从按钮,活动或片段设置请求

btn_camera.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View view) {

              Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
              startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST);

          }
    }
    );

现在我正在请求CAMERA 来自片段的_PIC_REQUEST我在OnActivityResult()

上实现了这个代码
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == CAMERA_PIC_REQUEST)
        if (data != null) {
        imageuri = data.getData();
        //Bitmap image = (Bitmap) data.getExtras().get("data");

        try {
            options.inSampleSize = 2;
            exif = new ExifInterface(getRealPathFromURI(imageuri));
            rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            rotation = exifToDegrees(rotation);

            bm = BitmapFactory.decodeStream(
                    getActivity().getContentResolver().openInputStream(imageuri),Padding,options);

            scaledBitmap = Bitmap.createScaledBitmap(bm, 400,400, true);

            if (rotation != 0)
            {matrix.postRotate(rotation);}
            //matrix.postRotate(180);
            rotatedBitmap = Bitmap.createBitmap(scaledBitmap , 0, 0, scaledBitmap .getWidth(), scaledBitmap .getHeight(), matrix, true);

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

        mIvFoto.setImageBitmap(rotatedBitmap);


     }
 }

旋转和矩阵用于将拍摄的照片缩放到ImageView,因此我可以在保存之前预览照片。这不会影响pic的质量。它只适用于预览位图。所以在ScaledBitmap变量中,你可以看到,当我将PIC的尺寸放到400,400时,你可以放置你想要的图片的尺寸,一定要旋转位图,这样你就可以正确地拍照了即使您以纵向模式拍摄照片。

最后是从相机保存它的路径旋转和获取图片的方法。

private static int exifToDegrees(int exifOrientation) {
    if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { return 90; }
    else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {  return 180; }
    else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {  return 270; }
    return 0;
}

private String getRealPathFromURI(Uri contentURI) {
    String result;
    Cursor cursor =getActivity().getContentResolver().query(contentURI, null, null, null, null);
    if (cursor == null) { // Source is Dropbox or other similar local file path
        result = contentURI.getPath();
    } else {
        cursor.moveToFirst();
        int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
        result = cursor.getString(idx);
        cursor.close();
    }
    return result;
}

我希望这对你有所帮助。