滑动加载到SimpleTarget <bitmap>不符合指定的宽度和高度

时间:2016-06-16 00:32:28

标签: java android android-glide

我使用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像素。

我尝试使用传递给width的{​​{1}}和height参数进行游戏,并使用这些参数生成的图像尺寸为1040 x 585像素。

我真的不知道如何让Glide尊重传递的尺寸。事实上,我想按比例调整图像大小,以便将较大的尺寸(宽度或高度)限制为1024像素,较小的尺寸相应调整大小(我相信我必须找到一种方法得到原始图像尺寸,然后将宽度和高度传递给new SimpleTarget<Bitmap>(350, 350),但要做到这一点,我需要Glide来尊重传递的宽度和高度!)。

有没有人知道发生了什么?我使用的是Glide 3.7.0。

由于这个问题本身可能对尝试使用Glide调整大小和保存图像的人有用,我相信提供我的实际解决方案并不符合每个人的兴趣。它依赖于一个自动保存已调整大小的图像的新SimpleTarget实现:

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

}

1 个答案:

答案 0 :(得分:7)

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

  

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

     
      
  • 解码/下采样器使用inSampleSize
  • 从流中读取图像   
  • 转换/ BitmapTransformation取位图并匹配完全匹配   目标规模
  •   
     

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

     

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

     

使用SimpleTarget,您可以通过提供一个来承担这些责任   构造函数上的大小或通过override()或实现getSize if   大小调整信息仅供同步使用。

     

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

由于这个原因,我对这个答案感到困惑:

  

使用SimpleTarget,您可以通过提供一个来承担这些责任   构造函数上的大小或通过override()或实现getSize if   大小调整信息仅供同步使用。

由于我通过了尺寸,我认为我已经覆盖了这个尺寸,这样的尺寸应该得到尊重。我错过了这个重要的概念:

  
      
  • 解码/下采样器使用inSampleSize
  • 从流中读取图像   
  • 转换/ 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是一个非常酷的图书馆!