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

这是我用来将图像保存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 ……

我的想法已经不多了……

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

这是此代码生成的位图

破碎的图像

编辑(24.03.2013):

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

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

编辑( 08.03.2013 ):致电拍摄图片:

 private class XyzAutoFocusCallback implements Camera.AutoFocusCallback { @Override public void onAutoFocus(boolean success, Camera camera) { if (takingPicture) { camera.takePicture(null, null, myPictureCallback); } else { ... } } 

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

尝试这个

 Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length); imv.setImageBitmap(bmp); ByteArrayOutputStream bos = new ByteArrayOutputStream(); bmp.compress(CompressFormat.JPEG, 70, bos); 

您是否尝试将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(); } } 

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

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

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

我还应该提一下,使用FileOutputStream直接保存数据就是创建一个合适的JPEG图像。 所以问题必须是BitmapFactory和我创建Bitmap的方式。

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

  1. 将文件转储到磁盘。
  2. 使用validation工具或PC上的某些图像编辑器检查该文件。
  3. 如果图像编辑器打开图像正常,请使用标准JPEG配置文件从该图像编辑器保存副本。
  4. BitmapFactory处理由Image编辑器保存的原始文件和文件,看看两者中是否得到了错误的位图。

如果图像有效JPEG并且BitmapFactory仍然产生错误的Bitmap,则问题在于BitmapFactory (不太可能),如果Camera输出的文件无效JPEG,则问题出在Camera(更有可能)。

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

首先你需要这个variables:

  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的质量。 它只适用于预览位图。 所以在ScaledBitmapvariables中,你可以看到,当我将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; } 

我希望这可以帮到你。