Загружать большие изображения с помощью Picasso и настраиваемого объекта Transform

Я получаю исключение Out Of Memory, используя Picasso при загрузке «больших» изображений (> 1,5 МБ) из галереи Android (с использованием startActivityForResult).

Я использую целевой объект Target, потому что мне нужно предварительно обработать битмап, когда он будет готов, а также я использую настраиваемый объект Transform для масштабирования растрового изображения.

Проблема в том, что метод public Bitmap transform(Bitmap source) на моем объекте Transform никогда не вызывается из-за исключения Out Of Memory, поэтому я не получаю возможности перепрограммировать изображение.

Но, если я использую метод .resize(maxWidth, maxHeight) , тогда он загружает изображение ОК. Я утверждал, что объект Transform тоже был для этой цели, но кажется, что метод преобразования вызывается после изменения размера, и, если я не вызываю изменение размера, то он закончится нехваткой памяти.

Проблема в том, что при изменении размера мне нужно указать ширину и высоту, но мне нужно масштабировать и сохранять соотношение сторон.

Подумайте, что изображения будут выбраны из галереи пользователя, поэтому они могут быть больше или меньше, портретные, квадратные или ландшафтные и т. Д., Поэтому мне нужен мой собственный объект Transformation для выполнения логики, которая нуждается в моем приложении.

Я нашел решение ..

В моем объекте Transform мне нужно было масштабировать изображение (поддерживая пропорции) до макс. 1024 x 768.

Объект Transform никогда не вызывался, если я не назову .resize(width, height) чтобы перепрограммировать изображение.

Для сохранения соотношения сторон и изменения размера я вызываю .centerInside() . Таким образом, изображение будет масштабироваться в соответствии с шириной, высотой).

Значение, которое я даю .resize (ширина, высота), – Math.ceil(Math.sqrt(1024 * 768)) . Таким образом, я уверен, что у меня есть изображение, достаточно высокое для моего настраиваемого объекта Transform, а также исключение Out Of Memory

Обновление: полный пример

После этого примера вы получите изображение, которое соответствует границам MAX_WIDTH и MAX_HEIGHT (поддерживая соотношение сторон)

 private static final int MAX_WIDTH = 1024; private static final int MAX_HEIGHT = 768; int size = (int) Math.ceil(Math.sqrt(MAX_WIDTH * MAX_HEIGHT)); // Loads given image Picasso.with(imageView.getContext()) .load(imagePath) .transform(new BitmapTransform(MAX_WIDTH, MAX_HEIGHT)) .skipMemoryCache() .resize(size, size) .centerInside() .into(imageView); 

И это мой собственный класс BitmapTransform:

 import android.graphics.Bitmap; import com.squareup.picasso.Transformation; /** * Transformate the loaded image to avoid OutOfMemoryException */ public class BitmapTransform implements Transformation { private final int maxWidth; private final int maxHeight; public BitmapTransform(int maxWidth, int maxHeight) { this.maxWidth = maxWidth; this.maxHeight = maxHeight; } @Override public Bitmap transform(Bitmap source) { int targetWidth, targetHeight; double aspectRatio; if (source.getWidth() > source.getHeight()) { targetWidth = maxWidth; aspectRatio = (double) source.getHeight() / (double) source.getWidth(); targetHeight = (int) (targetWidth * aspectRatio); } else { targetHeight = maxHeight; aspectRatio = (double) source.getWidth() / (double) source.getHeight(); targetWidth = (int) (targetHeight * aspectRatio); } Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false); if (result != source) { source.recycle(); } return result; } @Override public String key() { return maxWidth + "x" + maxHeight; } } 

На веб-сайте разработчика Android очень хорошая статья, которая очень помогла мне, когда у меня возникла такая же проблема с загрузкой больших изображений.

В этой статье очень хорошо объясняется, что вызывает ошибку и как ее решить. Существуют также другие статьи (см. Меню), например, изображения кеша.