1)我的应用的一些用户正在拍摄一些看起来像这样的图片:
我唯一能做的就是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。
答案 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);
为我工作。