装载大图像毕加索和自定义转换对象毕加索、自定义、图像、对象

2023-09-04 06:57:15 作者:个性的

我发现了一个用出毕加索内存异常从Android的画廊(使用startActivityForResult)装载大的图像(> 1.5MB)时。

I'm getting an Out Of Memory exception using Picasso when loading "large" images (> 1.5MB) from Android Gallery (using startActivityForResult).

我使用的是自定义的目标对象,因为我需要preprocess位图时,它已准备就绪,也是我使用的是自定义转换对象缩放位图。

I'm using a custom Target object because I need to preprocess the Bitmap when it is ready and also I'm using a custom Transform object to scale the Bitmap.

问题是,公共位图转换(位图源)我的Transform对象的方法不会被调用,因为内存不够的异常,所以我没有得到的oportunity重新采样的图像。

The problem is that the method public Bitmap transform(Bitmap source) on my Transform object is never called because the Out Of Memory Exception, so I don't get the oportunity to resample the image.

但是,如果我用 .resize(了maxWidth,了maxHeight)的方法,然后将其加载图像确定。我supossed该Transform对象是用于这一目的也一样,但似乎变换方法调整大小后调用,而且,如果我不叫调整,那么它会在内存中结束。

But, if I use the .resize(maxWidth, maxHeight) method, then it loads the image OK. I supossed that the Transform object was for that purpose too, but it seems that the transform method is called after the resize, and, if I don't call resize, then it will end in an Out of Memory..

现在的问题是,随着调整大小我需要指定宽度和高度,但我需要扩展,并保持宽高比。

The problem is that with resize I need to specify both width and height, but I need to scale and keep the aspect ratio.

考虑到图像将从用户库中选择,这样他们就可以更大或更小,肖像,平方或风景等,所以我需要我自己的转型目标来执行,需要我的应用程序的逻辑。

Consider that the images will be selected from user Gallery, so they can be bigger or smaller, portrait, squared or landscape, etc, so I need my own Transformation object to perform the logic that needs my application.

推荐答案

我找到了解决办法。

在我的Transform对象,我需要将图像缩放(保持纵横比)为1024 x 768最大。

In my Transform object I needed to scale the image (keeping aspect ratio) to 1024 x 768 max.

变换对象从来没有被执行,除非我称之为 .resize(宽,高)重新取样下来的图像。

Transform object was never called unless I call .resize(width, height) to resample down the image.

有关保持纵横比和使用调整我称之为 .centerInside()。这样图像进行调整重新取样,以适应宽,高)。

For keeping aspect ratio and using resize I call .centerInside(). This way image will be scaled resample to fit width, height).

这是我给.resize(宽,高)的值是 Math.ceil(的Math.sqrt(1024 * 768))。 这样,我敢肯定有一个形象的我的自定义不够高Transform对象,又可以避免内存溢出异常

The value that I give to .resize(width, height) is Math.ceil(Math.sqrt(1024 * 768)). This way I'm sure to have an image higher enough for my custom Transform object, and also avoid Out Of Memory exception

更新:完整的示例

下面这个例子,你会得到一个适合MAX_WIDTH和MAX_HEIGHT范围内的图像(保持纵横比)

Following this example you will get a image that fits inside MAX_WIDTH and MAX_HEIGHT bounds (keeping aspect ratio)

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类:

And this is my custom BitmapTransform class:

import android.graphics.Bitmap;
import com.squareup.picasso.Transformation;

/**
 * Transformate the loaded image to avoid OutOfMemoryException
 */
public class BitmapTransform implements Transformation {

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

};