使用 Glide,是不是可以在实际解码并保存到位图之前获得输出图像分辨率?

Posted

技术标签:

【中文标题】使用 Glide,是不是可以在实际解码并保存到位图之前获得输出图像分辨率?【英文标题】:Using Glide, is it possible to get output image resolution, before the actual decoding and saving into a bitmap?使用 Glide,是否可以在实际解码并保存到位图之前获得输出图像分辨率? 【发布时间】:2019-01-01 18:03:04 【问题描述】:

背景

我正在尝试对动态壁纸应用中的任何给定图像文件产生水平滚动效果。

为此,我应该按照这些规则工作,我认为:

输入是任意分辨率的图像文件 我应该缩放/裁剪,以便高度具有特定值。 宽度至少应为特定值 输出位图应该有一定的宽度,因为我不想做太大的位图,占用大量内存 无论如何保持纵横比。

问题

我发现很难找到正确的函数和参数以使其生成输出位图的正确宽度和高度。

我尝试过的

我尝试过各种变换(例如:centerCropTransform,fitCenterTransform),但没有一个达到我想要的,所以我认为除非我在决定做什么之前做一些特殊的数学运算,否则没有一个可以工作与滑翔。

目前我所做的是这样的:

val result = Glide.with(context).asBitmap()
                           .load(imageFile)
                           .apply(RequestOptions.noTransformation()
                           .skipMemoryCache(true)
                           .diskCacheStrategy(DiskCacheStrategy.NONE))
                           .submit(reqWidth, reqHeight).get()

这很有效,因为它生成(至少根据我的测试)一个位图,该位图至少是我要求的大小。但是,这意味着我有高度不需要的额外像素。它也不能防止我生成太大的位图。

但我认为也许让 Glide 为上述目的使用各种技术会更容易,然后决定可能的输出分辨率,这是最好的使用。

问题

    是否可以在实际解码和存储为位图之前获得输出分辨率,然后再决定应该使用哪种技术?

    是否有更好的选择我应该考虑?也许在我这边做计算,然后决定用 Glide 做什么?如果有,怎么做?

【问题讨论】:

您是从本地存储中读取图像吗?如果是,那么我认为您可以从文件本身获取信息,即要加载的宽度和高度 @Gautam 我已经知道如何在不解码的情况下获得图像文件的分辨率(使用inJustDecodeBounds=true 用于发送到BitmapFactory.decodeFileBitmapFactory.Options)。问题是关于 Glide 的输出文件,在它实际解码输入文件并创建输出图像之前。我不想执行不必要的操作... 【参考方案1】:
我应该缩放/裁剪,以便高度具有特定值。 宽度至少应为特定值 无论如何保持纵横比。

你不能真的把所有这些都认为是真的,因为如果你有一个保证的最小高度和一个保证的最小宽度,那么你可能不得不扭曲纵横比,这违反了第三个条件。

我建议改为使用以下三个条件:

    将输出的最大高度设置为设备屏幕的高度(纵向) 设置输出位图的最大分配内存 无论如何保持原始纵横比

Glide 可以为您执行 1 和 3,但 2 您可能需要先解码位图而不分配内存(查看BitmapFactory.Options.inJustDecodeBounds)以获得源纵横比,然后使用数学计算出要设置的高度和宽度您不会超出每个位图的内存上限。

最后,根据您的用例(如果您需要在短时间内渲染多个位图),您可能需要考虑裁剪为标准输出纵横比,以便您可以利用 Glide 的位图回收功能,这有助于避免 OOM 崩溃。

【讨论】:

为什么我必须“扭曲纵横比”?我刚刚写过它可以被裁剪(“缩放/裁剪”)。裁剪意味着您仍然可以看到原始纵横比的图像,但只是看不到图像的某些部分。使用中心裁剪,我实际上可以将任何图像适合任何分辨率。但是,只有在缩放不起作用时才应该进行裁剪。我不明白你的建议,但是看到你减少了我写的内容,我不想使用它。我编写的代码似乎工作正常,但它没有被裁剪或受到宽度的限制。【参考方案2】:

好吧,我想我明白了。

我计算如果我适合宽度和高度会发生什么,并相应地在计算结果上使用中心裁剪:

                    val bitmapOptions = Utils.getBitmapOptions(savedImageFileForWallpaperBackground.absolutePath)
                    //newWidth/newHeight=oldWidth/oldHeight
                    val widthIfScaledToHeight = reqHeight * bitmapOptions.outWidth / bitmapOptions.outHeight
                    val heightIfScaledToWidth = reqWidth * bitmapOptions.outHeight / bitmapOptions.outWidth

                    val result: Bitmap
                    if (widthIfScaledToHeight >= reqWidth) 
                        result = Glide.with(wallpaperService).asBitmap()
                                .load(savedImageFileForWallpaperBackground)
                                .apply(RequestOptions.centerCropTransform().skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.NONE))
                                .submit(widthIfScaledToHeight, reqHeight).get()
                     else 
                        result = Glide.with(wallpaperService).asBitmap()
                                .load(savedImageFileForWallpaperBackground)
                                .apply(RequestOptions.centerCropTransform().skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.NONE))
                                .submit(reqWidth, heightIfScaledToWidth).get()
                    

【讨论】:

以上是关于使用 Glide,是不是可以在实际解码并保存到位图之前获得输出图像分辨率?的主要内容,如果未能解决你的问题,请参考以下文章

Glide:DecodeJob

将任何文件加载到位并保存

Android实战——Glide的使用,加载图片只要一句话

将Surface保存到位图并在C#中优化DirectX屏幕捕获

mfc做的一个程序,如何将绘画的矩形、圆形保存到位图?保存成.bmp格式?

如何使用 Glide 将图像保存到内部存储?