我有一个应用程序,为用户显示了不少图像,我们看到很多错误报告都有OutOfMemoryError
例外。
我们目前的工作是:
// Check if image is a landscape image
if (bmp.getWidth() > bmp.getHeight()) {
// Rotate it to show as a landscape
Matrix m = image.getImageMatrix();
m.postRotate(90);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true);
}
image.setImageBitmap(bmp);
显而易见的问题是我们必须从内存中的图像重新创建位图并旋转矩阵,这对内存来说非常昂贵。
我的问题很简单:
有没有更好的方法来旋转图像而不会导致OutOfMemoryError
?
答案 0 :(得分:6)
旋转大图像的两种方法:
使用JNI,例如on this post。
使用文件:这是一种非常慢的方式(取决于输入和设备,但仍然非常慢),它将解码后的旋转图像放入磁盘,而不是将其放入内存。 / p>
使用文件的代码如下:
private void rotateCw90Degrees()
{
Bitmap bitmap=BitmapFactory.decodeResource(getResources(),INPUT_IMAGE_RES_ID);
// 12 => 7531
// 34 => 8642
// 56 =>
// 78 =>
final int height=bitmap.getHeight();
final int width=bitmap.getWidth();
try
{
final DataOutputStream outputStream=new DataOutputStream(new BufferedOutputStream(openFileOutput(ROTATED_IMAGE_FILENAME,Context.MODE_PRIVATE)));
for(int x=0;x<width;++x)
for(int y=height-1;y>=0;--y)
{
final int pixel=bitmap.getPixel(x,y);
outputStream.writeInt(pixel);
}
outputStream.flush();
outputStream.close();
bitmap.recycle();
final int newWidth=height;
final int newHeight=width;
bitmap=Bitmap.createBitmap(newWidth,newHeight,bitmap.getConfig());
final DataInputStream inputStream=new DataInputStream(new BufferedInputStream(openFileInput(ROTATED_IMAGE_FILENAME)));
for(int y=0;y<newHeight;++y)
for(int x=0;x<newWidth;++x)
{
final int pixel=inputStream.readInt();
bitmap.setPixel(x,y,pixel);
}
inputStream.close();
new File(getFilesDir(),ROTATED_IMAGE_FILENAME).delete();
saveBitmapToFile(bitmap); //for checking the output
}
catch(final IOException e)
{
e.printStackTrace();
}
}
答案 1 :(得分:0)
你可以尝试:
image.setImageBitmap(null);
// Check if image is a landscape image
if (bmp.getWidth() > bmp.getHeight()) {
// Rotate it to show as a landscape
Matrix m = image.getImageMatrix();
m.postRotate(90);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true);
}
BitmapDrawable bd = new BitmapDrawable(mContext.getResources(), bmp);
bmp.recycle();
bmp = null;
setImageDrawable(bd);
bd = null;
答案 2 :(得分:0)
使用大量位图时,请务必在不需要时立即调用recycle()。此调用将立即释放与特定位图关联的内存。
在您的情况下,如果您在旋转后不需要原始位图,则将其回收。有点像:
Bitmap result = bmp;
// Check if image is a landscape image
if (bmp.getWidth() > bmp.getHeight()) {
// Rotate it to show as a landscape
Matrix m = image.getImageMatrix();
m.postRotate(90);
result = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true);
// rotating done, original not needed => recycle()
bmp.recycle();
}
image.setImageBitmap(result);