【问题标题】:Glide load into SimpleTarget<Bitmap> not honoring the specified width and height滑动加载到 SimpleTarget<Bitmap> 不遵守指定的宽度和高度
【发布时间】:2016-06-16 00:32:28
【问题描述】:

我正在使用 Glide 加载图像、调整大小并通过 SimpleTarget&lt;Bitmap&gt; 将其保存到文件中。这些图像将上传到 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&lt;Bitmap&gt;(350, 350)widthheight 参数,使用这些参数生成的图像尺寸为1040 x 585 像素。

我真的不知道该怎么做才能让 Glide 尊重传递的维度。事实上,我想按比例调整图像的大小,以便将较大的尺寸(宽度或高度)限制为 1024 像素,而较小的尺寸会相应调整(我相信我必须找到一种方法来获取原始图像尺寸,然后将宽度和高度传递给SimpleTarget,但要做到这一点,我需要 Glide 尊重传递的宽度和高度!)。

有人知道发生了什么吗?我正在使用 Glide 3.7.0。


由于这个问题本身可能对尝试使用 Glide 调整大小和保存图像的人有用,我相信提供我的实际“解决方案”符合每个人的利益,该解决方案依赖于自动保存调整大小的图像的新 SimpleTargetimplementation :

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 如果您阅读下面的“解决方案”(如上面的问题本身),您会发现这正是缺少的内容......您甚至在阅读答案之前就已经抓住了它!好的! :-)

标签: java android android-glide


【解决方案1】:

睡了一夜之后,我才想通了!我在 Glide 的 github 页面上偶然发现了一个问题,该问题有答案,但我没有意识到:我在解释中遗漏了一些东西,休息 10 小时后我现在完全理解了。你永远不应该低估睡眠的力量!但我离题了。这是Glide's Github issue tracker上的答案:

调整图像大小通常有两个阶段:

  • 解码/下采样器使用 inSampleSize 从流中读取图像
  • Transforming/BitmapTransformation 获取位图并精确匹配 目标大小

总是需要解码并包含在流程中, 默认情况是将目标大小与“至少”匹配 下采样器,因此当涉及到转换时,图像可以 在没有质量损失的情况下缩小更多尺寸(源中的每个像素都会 匹配至少 1.0 像素和最多 ~1.999 像素)这可以是 由 asBitmap() 控制。至少|atMost|asIs|decoder(with 下采样器)

默认情况下,转换和目标大小是自动的,但仅 使用 ViewTarget 时。当您加载到 ImageView 的大小 即使它具有 match_parent,也会被检测到。还有如果有 没有明确的转换,将会从 scaleType 应用一个。 因此会为该图像生成一个像素完美的位图,即 1 个像素 在位图中 = 屏幕上的 1 个像素,从而获得最佳质量 具有最佳内存使用率和快速渲染(因为没有 绘制图像时需要像素映射)。

使用 SimpleTarget,您可以通过提供 构造函数上的大小或通过 override() 或实现 getSize if 尺寸信息仅异步可用。

要修复您的负载,请添加一个转换:.fitCenter|centerCrop(),您的 当前应用的转换是 .dontTransform() (Róbert Papp回答)

因为这个原因,我被这个答案弄糊涂了:

使用 SimpleTarget,您可以通过提供 构造函数上的大小或通过 override() 或实现 getSize if 尺寸信息仅异步可用。

因为我通过了尺寸,所以我认为我已经涵盖了这个尺寸,并且应该尊重这样的尺寸。我错过了这个重要的概念:

  • 解码/下采样器使用 inSampleSize 从流中读取图像
  • Transforming/BitmapTransformation 获取位图并精确匹配 目标大小

还有这个:

要修复您的负载,请添加一个转换:.fitCenter|centerCrop(),您的 当前应用的转换是 .dontTransform()

现在我把它拼凑在一起,这是有道理的。 Glide 只是对图像进行下采样(Róbert 解释的大小图像流的第一步),它给出了具有近似尺寸的图像。不得不说,Glide 在这方面是非常聪明的。通过在调整大小之前使用下采样方法,它可以避免在内存中使用不必要的大位图并提高调整大小的质量,因为下采样到精确大小会损害太多“重要”像素!

由于我没有对此加载管道应用任何转换,因此尺寸调整流程在第一步(下采样)中停止,并且生成的图像只有我预期的目标尺寸的近似尺寸。

为了解决这个问题,我刚刚应用了.fitCenter() 变换,如下所示:

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 是一个非常酷的库!

【讨论】:

    猜你喜欢
    • 2021-03-08
    • 2015-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-24
    • 2023-03-24
    • 1970-01-01
    • 2015-07-11
    相关资源
    最近更新 更多