我使用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)
}
}
答案 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是一个非常酷的图书馆!