Android Camera为一些用户提供了多行的错误图片

时间:2011-06-24 14:12:38

标签: android android-camera

1)我的应用的一些用户正在拍摄一些看起来像这样的图片:

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

我唯一能做的就是jpegCallback中的标准位图API:

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

然后将其写在磁盘上

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

2)编辑:我已经删除了对setPreviewSize的调用,如下所示: Android: Jpeg saved from camera looks corrupted

我认为这对一些用户(Desire HD)有帮助,但我可以告诉其他人仍然有问题(Desire S)。

我真的希望有人能够解释为什么pics首先看起来像distorded。

3 个答案:

答案 0 :(得分:1)

嗯,看起来你在从字节数组解码位图时犯了一些图像大小的错误。 你可以发布你用于的代码:    - 设置相机    - 设置解码参数    - 检索图像数据

答案 1 :(得分:1)

我无法告诉您为什么您从某些设备而不是其他设备获取乱码数据,但我可以建议一种似乎可以成功应用于我的应用的解决方法。

您的示例代码会将相机的JPEG缩小至640x480,然后再将其保存到SD卡。所以我猜你不需要全尺寸的相机图像。

如果这个假设成立,您可以完全跳过Camera的takePicture() API,只需将预览帧保存到SD卡即可。最简单的方法是使用setOneShotPreviewCallback()

mCamera.setOneShotPreviewCallback( new StillPictureCallback() );

这将调用一次,然后从摄像机返回数据缓冲区:

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

回调调用后台任务来压缩数据并将其保存到文件中。我遗漏的唯一代码是通过getCameraInfo()查询相机的预览帧格式,宽度和高度的部分。另请注意,Android YUVImage类是随Froyo引入的,因此如果您需要支持早期版本的Android,则需要使用自己的转换代码(StackOverflow上有示例)。

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

答案 2 :(得分:1)

我在HTC Desire S上遇到了完全相同的问题。

我根据设置更新了移动系统 - &gt;关于手机 - &gt;软件更新

我还实现了以下代码:

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

为我工作。