Вращающиеся изображения на андроид.Есть ли способ лучше? - PullRequest
10 голосов
/ 28 ноября 2011

У меня есть приложение, которое отображает довольно много изображений для пользователя, и мы видели много сообщений об ошибках за исключением 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?

Ответы [ 3 ]

6 голосов
/ 14 января 2013

2 способа поворота большого изображения:

  1. с использованием JNI, например в этом сообщении .

  2. использование файла: это очень медленный способ (в зависимости от входа и устройства, но все еще очень медленный), который сначала помещает декодированное повернутое изображение на диск, а не помещает его в память.

код использования файла ниже:

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();
    }
  }
0 голосов
/ 28 ноября 2011

При работе с большим количеством растровых изображений обязательно вызывайте 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);
0 голосов
/ 28 ноября 2011

вы можете попробовать:

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;
...