Glide源码分析之图片变换

  首先,默认情况下,ImageView的scaleType类型为FIT_CENTER.(scaleType有八种类型:FIT_XY,MATRIX,CENTER,CENTER_CROP,CENTER_INSIDE,FIT_START,FIT_CENTER,FIT_END)
  进入主题,当Glide的into方法中的参数为ImageView的时候,Glide默认会进行哪些图形变换呢?
  我们可以查看into方法的源码,它是在GenericRequestBuilder类当中的,

public Target into(ImageView view) {
    Util.assertMainThread();
    if (view == null) {
        throw new IllegalArgumentException("You must pass in a non null View");
    }
    if (!isTransformationSet && view.getScaleType() != null) {
        switch (view.getScaleType()) {
            case CENTER_CROP:
                applyCenterCrop();
                break;
            case FIT_CENTER:
            case FIT_START:
            case FIT_END:
                applyFitCenter();
                break;
            //$CASES-OMITTED$
            default:
                // Do nothing.
        }
    }
    return into(glide.buildImageViewTarget(view, transcodeClass));
}

  那么现在我们就基本清楚了,由于ImageView默认的scaleType是FIT_CENTER,因此会自动添加一个FitCenter的图片变换,而在这个图片变换过程中做了某些操作,导致图片充满了全屏。
  那我们应该如何取消Glide自带的图形变换呢?实际上,Glide给我们提供了专门的API来添加和取消图片变换,想要解决这个问题只需要使用如下代码即可:

Glide.with(this)
     .load(url)
     .dontTransform()
     .into(imageView);

  可以看到,这里调用了一个dontTransform()方法,表示让Glide在加载图片的过程中不进行图片变换,这样刚才调用的applyCenterCrop()、applyFitCenter()就统统无效了。
  但是使用dontTransform()方法存在着一个问题,就是调用这个方法之后,所有的图片变换操作就全部失效了,那如果我有一些图片变换操作是必须要执行的该怎么办呢?不用担心,总归是有办法的,这种情况下我们只需要借助override()方法强制将图片尺寸指定成原始大小就可以了,代码如下所示:

Glide.with(this)
     .load(url)
     .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
     .into(imageView);

图形变换的基本用法
  顾名思义,图片变换的意思就是说,Glide从加载了原始图片到最终展示给用户之前,又进行了一些变换处理,从而能够实现一些更加丰富的图片效果,如图片圆角化、圆形化、模糊化等等。
  添加图片变换的用法非常简单,我们只需要调用transform()方法,并将想要执行的图片变换操作作为参数传入transform()方法即可,如下所示:

Glide.with(this)
     .load(url)
     .transform(...)
     .into(imageView);

至于具体要进行什么样的图片变换操作,这个通常都是需要我们自己来写的。不过Glide已经内置了两种图片变换操作,我们可以直接拿来使用,一个是CenterCrop,一个是FitCenter。

但这两种内置的图片变换操作其实都不需要使用transform()方法,Glide为了方便我们使用直接提供了现成的API:

Glide.with(this)
     .load(url)
     .centerCrop()
     .into(imageView);

Glide.with(this)
     .load(url)
     .fitCenter()
     .into(imageView);

当然,centerCrop()和fitCenter()方法其实也只是对transform()方法进行了一层封装而已,它们背后的源码仍然还是借助transform()方法来实现的,如下所示:

public class DrawableRequestBuilder
        extends GenericRequestBuilder
        implements BitmapOptions, DrawableOptions {
    ...

    /**
     * Transform {@link GlideDrawable}s using {@link com.bumptech.glide.load.resource.bitmap.CenterCrop}.
     *
     * @see #fitCenter()
     * @see #transform(BitmapTransformation...)
     * @see #bitmapTransform(Transformation[])
     * @see #transform(Transformation[])
     *
     * @return This request builder.
     */
    @SuppressWarnings("unchecked")
    public DrawableRequestBuilder centerCrop() {
        return transform(glide.getDrawableCenterCrop());
    }

    /**
     * Transform {@link GlideDrawable}s using {@link com.bumptech.glide.load.resource.bitmap.FitCenter}.
     *
     * @see #centerCrop()
     * @see #transform(BitmapTransformation...)
     * @see #bitmapTransform(Transformation[])
     * @see #transform(Transformation[])
     *
     * @return This request builder.
     */
    @SuppressWarnings("unchecked")
    public DrawableRequestBuilder fitCenter() {
        return transform(glide.getDrawableFitCenter());
    }

    ...
}

自定义图片变换
先看一下centerCrop的源码

public class CenterCrop extends BitmapTransformation {

    public CenterCrop(Context context) {
        super(context);
    }

    public CenterCrop(BitmapPool bitmapPool) {
        super(bitmapPool);
    }

    // Bitmap doesn't implement equals, so == and .equals are equivalent here.
    @SuppressWarnings("PMD.CompareObjectsWithEquals")
    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        final Bitmap toReuse = pool.get(outWidth, outHeight, toTransform.getConfig() != null
                ? toTransform.getConfig() : Bitmap.Config.ARGB_8888);
        Bitmap transformed = TransformationUtils.centerCrop(toReuse, toTransform, outWidth, outHeight);
        if (toReuse != null && toReuse != transformed && !pool.put(toReuse)) {
            toReuse.recycle();
        }
        return transformed;
    }

    @Override
    public String getId() {
        return "CenterCrop.com.bumptech.glide.load.resource.bitmap";
    }
}

  首先,CenterCrop是继承自BitmapTransformation的,这个是重中之重,因为整个图片变换功能都是建立在这个继承结构基础上的。
  接下来CenterCrop中最重要的就是transform()方法,其他的方法我们可以暂时忽略。transform()方法中有四个参数,每一个都很重要,我们来一一解读下。第一个参数pool,这个是Glide中的一个Bitmap缓存池,用于对Bitmap对象进行重用,否则每次图片变换都重新创建Bitmap对象将会非常消耗内存。第二个参数toTransform,这个是原始图片的Bitmap对象,我们就是要对它来进行图片变换。第三和第四个参数比较简单,分别代表图片变换后的宽度和高度,其实也就是override()方法中传入的宽和高的值了。
  下面我们来看一下transform()方法的细节,首先第一行就从Bitmap缓存池中尝试获取一个可重用的Bitmap对象,然后把这个对象连同toTransform、outWidth、outHeight参数一起传入到了TransformationUtils.centerCrop()方法当中。那么我们就跟进去来看一下这个方法的源码,如下所示:

public final class TransformationUtils {
    ...

    public static Bitmap centerCrop(Bitmap recycled, Bitmap toCrop, int width, int height) {
        if (toCrop == null) {
            return null;
        } else if (toCrop.getWidth() == width && toCrop.getHeight() == height) {
            return toCrop;
        }
        // From ImageView/Bitmap.createScaledBitmap.
        final float scale;
        float dx = 0, dy = 0;
        Matrix m = new Matrix();
        if (toCrop.getWidth() * height > width * toCrop.getHeight()) {
            scale = (float) height / (float) toCrop.getHeight();
            dx = (width - toCrop.getWidth() * scale) * 0.5f;
        } else {
            scale = (float) width / (float) toCrop.getWidth();
            dy = (height - toCrop.getHeight() * scale) * 0.5f;
        }
        m.setScale(scale, scale);
        m.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));

        final Bitmap result;
        if (recycled != null) {
            result = recycled;
        } else {
            result = Bitmap.createBitmap(width, height, getSafeConfig(toCrop));
        }

        // We don't add or remove alpha, so keep the alpha setting of the Bitmap we were given.
        TransformationUtils.setAlpha(toCrop, result);

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint(PAINT_FLAGS);
        canvas.drawBitmap(toCrop, m, paint);
        return result;
    }

    ...
}

自定义图片变换之图片圆形化
包括圆角化、圆形化、黑白化、模糊化等等,甚至你将原图片完全替换成另外一张图都是可以的

public class CircleCrop extends BitmapTransformation {

    public CircleCrop(Context context) {
        super(context);
    }

    public CircleCrop(BitmapPool bitmapPool) {
        super(bitmapPool);
    }

    @Override
    public String getId() {
        return "com.example.glidetest.CircleCrop";
    }

    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        int diameter = Math.min(toTransform.getWidth(), toTransform.getHeight());

        final Bitmap toReuse = pool.get(outWidth, outHeight, Bitmap.Config.ARGB_8888);
        final Bitmap result;
        if (toReuse != null) {
            result = toReuse;
        } else {
            result = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888);
        }

        int dx = (toTransform.getWidth() - diameter) / 2;
        int dy = (toTransform.getHeight() - diameter) / 2;
        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        BitmapShader shader = new BitmapShader(toTransform, BitmapShader.TileMode.CLAMP, 
                                            BitmapShader.TileMode.CLAMP);
        if (dx != 0 || dy != 0) {
            Matrix matrix = new Matrix();
            matrix.setTranslate(-dx, -dy);
            shader.setLocalMatrix(matrix);
        }
        paint.setShader(shader);
        paint.setAntiAlias(true);
        float radius = diameter / 2f;
        canvas.drawCircle(radius, radius, radius, paint);

        if (toReuse != null && !pool.put(toReuse)) {
            toReuse.recycle();
        }
        return result;
    }
}

使用CircleCrop

Glide.with(this)
     .load(url)
     .transform(new CircleCrop(this))
     .into(imageView);

自定义图片开源库
glide-transformations
(version:3.1.1)实现的transformation有Crop,Color,Blur,Mask

你可能感兴趣的:(Glide源码分析之图片变换)