我的问题
我用我的Android设备拍照。然后我从文件中解码该图片。
Bitmap photo = BitmapFactory.decodeFile(EXTERNAL_IMAGE_PATH+File.separator+this._currentPhotoName+JPEG_FILE_SUFFIX);
if (photo == null && data != null)
photo = (Bitmap) data.getExtras().get("data");
else if (data == null && photo == null)
Log.e("CCPhotoManager","Can't find image from file or from intent data.");
然后我检查那张照片,看看它是否需要旋转到正确的方向。
try {
ExifInterface exif = new ExifInterface(EXTERNAL_IMAGE_PATH+File.separator+this._currentPhotoName+JPEG_FILE_SUFFIX);
int rotation = CCDataUtils.exifToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_NORMAL));
Log.v("CCPhotoManager", "Rotation:"+rotation);
if (rotation > 0) {
photo = this.convertSavedImageToCorrectOrientation(EXTERNAL_IMAGE_PATH+File.separator+this._currentPhotoName+JPEG_FILE_SUFFIX, photo, rotation);
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
如果确实需要旋转,我会调用此方法。
public Bitmap convertSavedImageToCorrectOrientation(String filePath,Bitmap photo,int rotation) {
Log.d("CCPhotoManager", "Changing Orientation of photo located at: "+filePath+" Rotating by:"+rotation);
int width = photo.getWidth();
int height = photo.getHeight();
Matrix matrix = new Matrix();
matrix.preRotate(rotation);
Bitmap adjusted = Bitmap.createBitmap(photo, 0, 0, width, height, matrix, true);
try {
FileOutputStream out = new FileOutputStream(filePath);
adjusted.compress(Bitmap.CompressFormat.JPEG, 100, out);
} catch (Exception e) {
e.printStackTrace();
}
return adjusted;
}
如果在convertSavedImageToCorrectOrientation
行调用Bitmap adjusted = Bitmap.createBitmap(photo,0,0,width,height,matrix,true);
这只是Samsung Galaxy S3
的情况。它适用于Samsung Galaxy Ace
,HTC Hero
和Sony Xperia U
。
这是错误。
10-17 14:33:33.950: E/AndroidRuntime(12556): java.lang.OutOfMemoryError
10-17 14:33:33.950: E/AndroidRuntime(12556): at android.graphics.Bitmap.nativeCreate(Native Method)
10-17 14:33:33.950: E/AndroidRuntime(12556): at android.graphics.Bitmap.createBitmap(Bitmap.java:605)
10-17 14:33:33.950: E/AndroidRuntime(12556): at android.graphics.Bitmap.createBitmap(Bitmap.java:551)
这也是一大笔记忆。
10-17 14:33:33.945: E/dalvikvm-heap(12556): Out of memory on a 31961104-byte allocation.
我认为它与Bitmaps的数量有关,但我不确定如何阻止此错误的发生。
我知道你可以给他们打电话.recycle();
,但似乎不起作用。
我的问题
如何正确处理我的位图,以便我没有这个OOM问题?
提前致谢
答案 0 :(得分:4)
内存不足问题
//对图像进行解码并对其进行缩放以减少内存消耗
private Bitmap decodeFile(File f){
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_SIZE=70;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
scale*=2;
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
答案 1 :(得分:4)
我有完全相同的问题,在完全相同的设备上做同样的事情!不幸的是,在我的情况下,需要使用完整尺寸的原始图像将图像提交给Web服务。对我有用的是在清单的应用程序元素中打开largeHeap。
这不会永久解决问题 - 设备可能会配备更大的相机,即使启用了largeHeap,图像也不适合内存。为了捕捉这种极端边缘的情况,我还试着围绕旋转图像的代码,并向用户显示一个很好的错误。
更全面的解决方案是编写自己的jpeg操作代码,该代码可以使用基于流的方法旋转jpeg,这样就不需要将图像加载到内存中。
答案 2 :(得分:3)
以下是有关如何调整大小/旋转的更完整示例,部分取自Android开发人员指南(更改REQ_WIDTH和REQ_HEIGHT):
private static final int REQ_WIDTH = 450;
private static final int REQ_HEIGHT = 450;
/**
* Resize, crop, rotate and Inserts the picture on the layout.
*
* @param mImageView to insert the bitmap.
* @param imageURI from wich to obtain the bitmap.
*
*/
private void setPic(ImageView mImageView, String imageURI) {
// Get the original bitmap dimensions
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageURI, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, REQ_HEIGHT, REQ_WIDTH);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(imageURI, options);
//need rotation?
float rotation = rotationForImage(getActivity(), Uri.fromFile(new File(imageURI)));
if (rotation != 0) {
//rotate
Matrix matrix = new Matrix();
matrix.preRotate(rotation);
mImageView.setImageBitmap(Bitmap.createBitmap(bitmap, 0, 0, REQ_HEIGHT, REQ_WIDTH, matrix, true));
} else {
//use the original
mImageView.setImageBitmap(BitmapFactory.decodeFile(imageURI, options));
}
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
public static float rotationForImage(Context context, Uri uri) {
try {
if (uri.getScheme().equals("content")) {
String[] projection = { Images.ImageColumns.ORIENTATION };
Cursor c = context.getContentResolver().query(uri, projection, null, null, null);
if (c.moveToFirst()) {
return c.getInt(0);
}
} else if (uri.getScheme().equals("file")) {
ExifInterface exif = new ExifInterface(uri.getPath());
int rotation = (int) exifOrientationToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL));
return rotation;
}
return 0;
} catch (IOException e) {
Log.e(TAG, "Error checking exif", e);
return 0;
}
}
private static float exifOrientationToDegrees(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;
}