Glide加载图片缩放模式

Glide加载图片缩放模式

前不久做一个水平图片滑动列表选择,效果类似于QQ发送图片。因为图片的长宽比不一致,而高度是固定的,所以就要对图片进行特殊拉伸。所以就看了下Glide拉伸这一块的源码。废话不多说了,下面开始总结。

平时我们用BitmapFactory进行加载较大图片时候,往往先通过inJustDecodeBounds方式解析出图片宽高,再结合ImageView宽高计算inSampleSize(即缩放比例),然后再“按需”加载bitmap,并显示出来。

那在Glide中是如何实现拉伸的呢?

其实Glide中实现也是上述思路,只是封装起来了。Glide负责计算缩放比例并decode的类是Downsampler,其中的getRoundedSampleSize 就负责计算缩放比例的。

public abstract class Downsampler implements BitmapDecoder<InputStream>{
    //这个方法decode图片得到bitmap,其实最终也会调用BitmapFactory.decode()方法
    @Override
    public Bitmap decode(InputStream is, BitmapPool pool, int outWidth, int outHeight, DecodeFormat decodeFormat) {

        ...省略...

        //这里计算缩放比例
        final int sampleSize = getRoundedSampleSize(degreesToRotate, inWidth, inHeight, outWidth, outHeight);
      //正式解析
       final Bitmap downsampled = downsampleWithSize(invalidatingStream, bufferedStream, options, pool, inWidth, inHeight, sampleSize,decodeFormat);

         ...省略...
    }

   ...

  //计算缩放比例
   private int getRoundedSampleSize(int degreesToRotate, int inWidth, int inHeight, int outWidth, int outHeight) {
        int targetHeight = outHeight == Target.SIZE_ORIGINAL ? inHeight : outHeight;
        int targetWidth = outWidth == Target.SIZE_ORIGINAL ? inWidth : outWidth;

        final int exactSampleSize;
        //注意下面的getSampleSize(),这个才是根据图片和Taget宽高计算缩放比例的。这个方法在下面有
        if (degreesToRotate == 90 || degreesToRotate == 270) {
            exactSampleSize = getSampleSize(inHeight, inWidth, targetWidth, targetHeight);
        } else {
            exactSampleSize = getSampleSize(inWidth, inHeight, targetWidth, targetHeight);
        }

        final int powerOfTwoSampleSize = exactSampleSize == 0 ? 0 : Integer.highestOneBit(exactSampleSize);

        // Although functionally equivalent to 0 for BitmapFactory, 1 is a safer default for our code than 0.
        return Math.max(1, powerOfTwoSampleSize);
    }

     //getSampleSize,这个核心方法是抽象方法,根据图片宽高(inWith和inHeight)和
     // Target宽高(outWidth和outHeight)来计算缩放比例
    protected abstract int getSampleSize(int inWidth, int inHeight, int outWidth, int outHeight);
}

如上代码展示,最核心的抽象方法getSampleSize才是决定如何缩放的,而Downsampler目前仅提供3种实现,分别是:

  • AT_LEAT:这个是默认方式,用比例差距小的边作为缩放基准
public static final Downsampler AT_LEAST = new Downsampler() {
        @Override
        protected int getSampleSize(int inWidth, int inHeight, int outWidth, int outHeight) {
            return Math.min(inHeight / outHeight, inWidth / outWidth);
        }
     ...
    };
  • AT_MOST:用比例差距大的边作为缩放基准
public static final Downsampler AT_MOST = new Downsampler() {
        @Override
        protected int getSampleSize(int inWidth, int inHeight, int outWidth, int outHeight) {
            int maxIntegerFactor = (int) Math.ceil(Math.max(inHeight / (float) outHeight,
                inWidth / (float) outWidth));
            int lesserOrEqualSampleSize = Math.max(1, Integer.highestOneBit(maxIntegerFactor));
            return lesserOrEqualSampleSize << (lesserOrEqualSampleSize < maxIntegerFactor ? 1 : 0);
        }
        ...
    };
  • NONE不缩放,采用原始比例。即当我们使用Target.SIZE_ORIGINAL作为Target宽高的时候
public static final Downsampler NONE = new Downsampler() {
    @Override
    protected int getSampleSize(int inWidth, int inHeight, int outWidth, int outHeight) {
        return 0;
    }
    ...
};

​ 这三种方式,在Glide加载图片时如何应用的呢? 我们在Glide.with(context).load(path).asBitmap() 时会得到BitmapRequestBuilder,下面是它的部分代码。可以得知调用它的approximate() 、atMost() 、asIs()分别对应上面的AT_LEAST、ATMOST、以及None

public class BitmapRequestBuilder<ModelType, TranscodeType>
        extends GenericRequestBuilder<ModelType, ImageVideoWrapper, Bitmap, TranscodeType> implements BitmapOptions {

    public BitmapRequestBuilder approximate() {
        return downsample(Downsampler.AT_LEAST);
    }

    //指定不缩放  
    public BitmapRequestBuilder asIs() {
        return downsample(Downsampler.NONE);
    }

    public BitmapRequestBuilder atMost() {
        return downsample(Downsampler.AT_MOST);
    }
    //遗憾这个是私有方法,不能自定义
    private BitmapRequestBuilder downsample(Downsampler downsampler) {
        this.downsampler = downsampler;
        imageDecoder = new StreamBitmapDecoder(downsampler, bitmapPool, decodeFormat);
        super.decoder(new ImageVideoBitmapDecoder(imageDecoder, videoDecoder));
        return this;
    }
 }

到此, Glide的缩放原理就比较清楚了。遗憾的是,downsample是私有方法,这就意味着我们不能自定义一个Downsampler。不知是否还有其他地方可以设置

你可能感兴趣的:(Android基础技术笔记)