使用Picasso和自定义Transform对象加载大图像

edr*_*ian 23 android picasso

当从Android Gallery(使用startActivityForResult)加载"大"图像(> 1.5MB)时,我使用Picasso获得Out Of Memory异常.

我正在使用自定义Target对象,因为我需要在Bitmap准备好时对其进行预处理,并且我还使用自定义Transform对象来缩放Bitmap.

问题是public Bitmap transform(Bitmap source)我的Transform对象上的方法永远不会被调用,因为Out Of Memory Exception,所以我没有机会重新采样图像.

但是,如果我使用该.resize(maxWidth, maxHeight)方法,那么它加载图像确定.我认为Transform对象也是出于这个目的,但似乎在调整大小后调用transform方法,如果我不调用resize,那么它将以Out of Memory结束.

问题是,使用resize我需要指定宽度和高度,但我需要缩放并保持纵横比.

考虑到图像将从用户图库中选择,因此它们可以更大或更小,纵向,平方或横向等,因此我需要自己的Transformation对象来执行需要我的应用程序的逻辑.

edr*_*ian 59

我找到了解决方案..

在我的Transform对象中,我需要将图像(保持纵横比)缩放到1024 x 768 max.

除非我调用.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);
Run Code Online (Sandbox Code Playgroud)

这是我的自定义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;
    }

}
Run Code Online (Sandbox Code Playgroud)