Cargue imágenes grandes con Picasso y el objeto personalizado Transform

Obtengo una excepción de falta de memoria al usar Picasso al cargar imágenes “grandes” (> 1.5MB) desde la Galería de Android (usando startActivityForResult).

Estoy usando un objeto Target personalizado porque necesito preprocesar el bitmap cuando está listo y también estoy usando un objeto Transform personalizado para escalar el bitmap.

El problema es que el método de public Bitmap transform(Bitmap source) en mi objeto Transformar nunca se llama debido a la excepción de falta de memoria, por lo que no tengo la oportunidad de volver a muestrear la imagen.

Pero, si uso el .resize(maxWidth, maxHeight) , entonces carga la imagen OK. Supuse que el objeto Transform también era para ese propósito, pero parece que se llama al método transform después del cambio de tamaño, y, si no llamo a resize, terminará en una memoria insuficiente.

El problema es que con el tamaño debo especificar tanto el ancho como la altura, pero necesito escalar y mantener la relación de aspecto.

Tenga en cuenta que las imágenes se seleccionarán de la galería del usuario, por lo que pueden ser más grandes o más pequeñas, verticales, cuadradas o horizontales, etc., así que necesito mi propio objeto Transformation para realizar la lógica que necesita mi aplicación.

Encontré una solución …

En mi objeto Transform necesitaba escalar la imagen (manteniendo la relación de aspecto) a 1024 x 768 máx.

El objeto de transformación nunca se llamó a menos que llame .resize(width, height) para volver a muestrear la imagen.

Para mantener la relación de aspecto y usar el tamaño, llamo a .centerInside() . De esta manera, la imagen se redimensionará para ajustarse al ancho, alto).

El valor que le doy a .resize (ancho, alto) es Math.ceil(Math.sqrt(1024 * 768)) . De esta forma, estoy seguro de tener una imagen lo suficientemente alta para mi objeto Transform personalizado, y también evitar la excepción Out Of Memory.

Actualización: ejemplo completo

Siguiendo este ejemplo, obtendrá una imagen que se ajusta dentro de los límites MAX_WIDTH y MAX_HEIGHT (manteniendo la relación de aspecto)

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

Y esta es mi clase BitmapTransform personalizada:

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

Hay un artículo muy bueno en el sitio web para desarrolladores de Android que me ayudó mucho cuando tuve el mismo problema al cargar imágenes grandes.

Este artículo explica muy bien qué causa el error y cómo resolverlo. También hay otros artículos (ver menú) para, por ejemplo, imágenes de caché.