Glide将图片加载到SimpleTarget<Bitmap>中,但未遵守指定的宽度和高度

10

我正在使用Glide来加载并调整图像大小,并通过SimpleTarget<Bitmap>将其保存到文件中。这些图像将上传到Amazon S3,但这并不重要。在上传之前,我调整图像大小以尽可能节省用户带宽。对于我的应用程序,1024像素宽的图像已经足够,因此我使用以下代码实现:

final String to = getMyImageUrl();
final Context appCtx = context.getApplicationContext();

Glide.with(appCtx)
        .load(sourceImageUri)
        .asBitmap()
        .into(new SimpleTarget<Bitmap>(1024, 768) {
            @Override
            public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
                try {
                    FileOutputStream out = new FileOutputStream(to);
                    resource.compress(Bitmap.CompressFormat.JPEG, 70, out);
                    out.flush();
                    out.close();
                    MediaScannerConnection.scanFile(appCtx, new String[]{to}, null, null);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
它基本上运行得很完美,但生成的图像尺寸不是1024像素宽。使用4160 x 2340像素的源图像测试时,保存图像的尺寸为2080 x 1170像素。
我已经尝试了使用传递给new SimpleTarget(350, 350)的width和height参数进行调整,但是结果图像的尺寸为1040 x 585像素。
我真的不知道该怎么做才能使Glide遵守传递的尺寸。实际上,我希望按比例调整图像大小,以便较大的尺寸(宽度或高度)将限制为1024像素,并相应地调整较小的尺寸(我相信我必须找到一种方法来获取原始图像尺寸,然后将宽度和高度传递给SimpleTarget,但要做到这一点,我需要Glide遵守传递的宽度和高度!)。
有人知道发生了什么吗?我正在使用Glide 3.7.0。
由于这个问题本身可能对试图使用Glide调整大小和保存图像的人有用,因此我认为提供我的实际“解决方案”对每个人都有利,它依赖于一个新的SimpleTarget实现,它会自动保存调整大小的图像:
import android.graphics.Bitmap;

import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;

import java.io.FileOutputStream;
import java.io.IOException;

public class FileTarget extends SimpleTarget<Bitmap> {
    public FileTarget(String fileName, int width, int height) {
        this(fileName, width, height, Bitmap.CompressFormat.JPEG, 70);
    }
    public FileTarget(String fileName, int width, int height, Bitmap.CompressFormat format, int quality) {
        super(width, height);
        this.fileName = fileName;
        this.format = format;
        this.quality = quality;
    }
    String fileName;
    Bitmap.CompressFormat format;
    int quality;
    public void onResourceReady(Bitmap bitmap, GlideAnimation anim) {
            try {
                FileOutputStream out = new FileOutputStream(fileName);
                bitmap.compress(format, quality, out);
                out.flush();
                out.close();
                onFileSaved();
            } catch (IOException e) {
                e.printStackTrace();
                onSaveException(e);
            }
    }
    public void onFileSaved() {
        // do nothing, should be overriden (optional)
    }
    public void onSaveException(Exception e) {
        // do nothing, should be overriden (optional)
    }

}

使用它就像这样简单:

Glide.with(appCtx)
        .load(sourceImageUri)
        .asBitmap()
        .into(new FileTarget(to, 1024, 768) {
            @Override
            public void onFileSaved() {
                // do anything, or omit this override if you want
            }
        });

你在上面的实际解决方案中不是缺少了.fitCenter()吗? - Wess
@Wess 如果你读了下面的“解决方案”(因为问题本身在上面),你会发现那正是缺失的部分... 你甚至在阅读答案之前就注意到了!太棒了! :-) - Loudenvier
1个回答

13
经过一个美好的夜晚睡眠,我终于明白了!我在Glide的Github页面上遇到了一个问题,答案就在那里,但我没有意识到:在解释中我错过了一些东西,但休息了10个小时后现在已经完全明白了。永远不要低估睡眠的力量!但我跑题了。以下是在Glide的Github问题跟踪器上找到的答案: > 调整图像大小通常有两个阶段: > > 1. 解码/降采样器使用inSampleSize从流中读取图像 > 2. 变换/BitmapTransformation获取位图并匹配精确目标大小 > > 解码始终是必需的且已包含在流程中,默认情况下使用“至少”降采样器与目标大小匹配,因此当涉及到变换时,可以更多地缩小图像而不会失去质量(源中的每个像素都将匹配至少1.0个像素,最多约1.999个像素),这可以通过asBitmap()、atLeast|atMost|asIs|decoder(带降采样器)进行控制。 > > 默认情况下,变换和目标大小是自动完成的,但仅在使用ViewTarget时才会执行此操作。当您加载到ImageView中时,即使其具有match_parent,也将检测到其大小。而且,如果没有显式变换,则会从scaleType应用一个变换。结果是原始图像的像素完美匹配位图,这意味着位图中的1个像素=屏幕上的1个像素,从而实现了最佳的质量,最佳的内存使用和快速渲染(因为在绘制图像时不需要像素映射)。 > > 通过SimpleTarget,您可以通过构造函数或通过override()或者如果只有异步可用的大小信息,则可以实现getSize来承担这些责任。 > > 要解决您的加载问题,请添加转换:.fitCenter|centerCrop(),您当前应用的转换是.dontTransform()。(答案由Róbert Papp提供)
我对这个答案感到困惑,因为它说: > 通过SimpleTarget,您可以通过构造函数或通过override()或者如果只有异步可用的大小信息,则可以实现getSize来承担这些责任。
既然我已经传递了大小信息,我认为我已经涵盖了这个问题,应该已经得到了处理。然而,我错过了这个重要概念: > 调整图像大小通常有两个阶段: > > 1. 解码/降采样器使用inSampleSize从流中读取图像 > 2. 变换/BitmapTransformation获取位图并匹配精确目标大小
还有: > 要解决您的加载问题,请添加转换:.fitCenter|centerCrop(),您当前应用的转换是.dontTransform()
现在我把它拼凑在一起,这就有意义了。Glide只进行了图像的降采样(根据Róbert所解释的调整图像大小的第一步),从而得到一个具有近似尺寸的图像。让我说一下,在这方面,Glide非常聪明。通过在调整大小之前使用降采样方法,它避免了在内存中处理不
Glide.with(appCtx)
        .load(sourceImageUri)
        .asBitmap()
        .fitCenter()
        .into(new FileTarget(to, 1024, 768) {
            @Override
            public void onFileSaved() {
                // do anything, or omit this override if you want
            }
        });

结果图像现在具有1024 x 576像素的尺寸,这正是我所期望的。

Glide是一个非常酷的库!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接