Camera for Android has several aligned images for some users

1) Some users of my application take some distorted images that look like this:

http://lh3.ggpht.com/i_VKS_Z1Ike5V8gEySiscQRRNkLwZMvv1a6u9diJrkWWGgYXUS-kqqxvAylhLIEJ1gs3MMZSEYIJJ4hX

The only thing I do is the standard bitmap API in jpegCallback:

BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inSampleSize = 4; bm = BitmapFactory.decodeByteArray(data, 0, data.length, opts); bm = Bitmap.createScaledBitmap(bm , 640, 480, true); 

and then burn it to disk

  imageFile = new File("/sdcard/app_dir/upload.jpg"); FileOutputStream outStream = new FileOutputStream(imageFile); bm.compress(CompressFormat.JPEG, 75, outStream); outStream.flush(); outStream.close(); 

2) edit: I deleted the setPreviewSize call, as explained there: Android: Jpeg saved from the camera is damaged

I think this helped some users (Desire HD), but I can say that others still have a problem (Desire S).

I really want someone to explain the reason why photos look distorted in the first place.

+7
source share
3 answers

I canโ€™t tell you why you are getting corrupted data from some devices and not others, but I can offer a workaround that seems to work successfully for my application.

Your sample code scales a JPEG camera to 640x480 before saving it to an SD card. Therefore, I assume that you do not need a full-sized image of the camera.

If this assumption is correct, you can completely skip Camera takePicture() API and just save the preview frame to the SD card. The easiest way to do this is setOneShotPreviewCallback() :

 mCamera.setOneShotPreviewCallback( new StillPictureCallback() ); 

This will be called once and send you a data buffer from the camera:

 private class StillPictureCallback implements Camera.PreviewCallback { @Override public void onPreviewFrame(byte[] data, Camera camera) { mPictureTask = new SaveStillPictureTask(); byte[] myData = null; if ( data != null ) { myData = data.clone(); } mPictureTask.execute(myData); } } 

The callback invokes a background task to compress the data and save it to a file. The only bit of code that I leave is the part that asks the camera for the preview frame format, width and height using getCameraInfo() . Also note that the Android class YUVImage was introduced with Froyo, so if you need to support earlier versions of Android, you will need to roll your own conversion code (there are examples on StackOverflow here).

 /** * Background task to compress captured image data and save to JPEG file. * */ private class SaveStillPictureTask extends AsyncTask<byte[], Void, Void> { private static final String TAG="VideoRecorder.SaveStillPictureTask"; @Override protected Void doInBackground(byte[]... params) { byte[] data = params[0]; FileOutputStream out = null; Bitmap bitmap = null; if ( data == null ) { Log.e(TAG, "doInBackground: data is null"); return null; } try { out = new FileOutputStream(mSnapshotFilePath); // Use the preview image format, as documented in Android SDK javadoc if ( (mPreviewImageFormat == ImageFormat.NV21) || (mPreviewImageFormat == ImageFormat.YUY2) ) { saveYUVToJPEG( mCamera, out, data ); } else if (mPreviewImageFormat == ImageFormat.JPEG) { Log.d(TAG, "directly write JPEG to storage"); out.write(data); } else { Log.d(TAG, "try decoding to byte array"); bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); if ( bitmap != null ) { bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); } else { Log.e(TAG, "decodeByteArray failed, no decoded data"); } } } catch (FileNotFoundException ignore) {;} catch (IOException ignore) {;} finally { if ( out != null ) { try { out.close(); } catch (IOException ignore) {;} out = null; } if ( bitmap != null ) { bitmap.recycle(); bitmap = null; } data = null; } return null; } } /** * Save YUV image data (aka NV21 or YUV420sp) data to JPEG file. * * @param camera * @param out * @param data */ protected void saveYUVToJPEG( Camera camera, FileOutputStream out, byte[] data ) { YuvImage yuvimg = null; try { int width = mPreviewWidth; int height = mPreviewHeight; Rect rect = new Rect(); rect.left = 0; rect.top = 0; rect.right = width - 1; rect.bottom = height - 1; // The -1 is required, otherwise a buffer overrun occurs yuvimg = new YuvImage(data, mPreviewImageFormat, width, height, null); yuvimg.compressToJpeg(rect, 90, out); } finally { yuvimg = null; } } 
+1
source

Well, it looks like you made a mistake with the image size when decoding a bitmap from an array of bytes. Can you publish the code that you use for: - setting up the camera - setting up decoding parameters - receiving image data

+1
source

I had the same issue on HTC Desire S.

I updated the mobile system in settings โ†’ About phone โ†’ software updates

I also executed the following code:

  Camera.Parameters parameters = mCamera.getParameters(); parameters.setPictureFormat(PixelFormat.JPEG); mCamera.setParameters(parameters); 

Worked for me.

+1
source

All Articles