Glide源碼分析之圖片變換

??首先,默認(rèn)情況下,ImageView的scaleType類型為FIT_CENTER.(scaleType有八種類型:FIT_XY,MATRIX,CENTER,CENTER_CROP,CENTER_INSIDE,FIT_START,FIT_CENTER,FIT_END)
??進入主題,當(dāng)Glide的into方法中的參數(shù)為ImageView的時候,Glide默認(rèn)會進行哪些圖形變換呢?
??我們可以查看into方法的源碼,它是在GenericRequestBuilder類當(dāng)中的,

public Target<TranscodeType> 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));
}

??那么現(xiàn)在我們就基本清楚了,由于ImageView默認(rèn)的scaleType是FIT_CENTER,因此會自動添加一個FitCenter的圖片變換,而在這個圖片變換過程中做了某些操作,導(dǎo)致圖片充滿了全屏。
??那我們應(yīng)該如何取消Glide自帶的圖形變換呢?實際上,Glide給我們提供了專門的API來添加和取消圖片變換,想要解決這個問題只需要使用如下代碼即可:

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

??可以看到,這里調(diào)用了一個dontTransform()方法,表示讓Glide在加載圖片的過程中不進行圖片變換,這樣剛才調(diào)用的applyCenterCrop()、applyFitCenter()就統(tǒng)統(tǒng)無效了。
??但是使用dontTransform()方法存在著一個問題,就是調(diào)用這個方法之后,所有的圖片變換操作就全部失效了,那如果我有一些圖片變換操作是必須要執(zhí)行的該怎么辦呢?不用擔(dān)心,總歸是有辦法的,這種情況下我們只需要借助override()方法強制將圖片尺寸指定成原始大小就可以了,代碼如下所示:

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

圖形變換的基本用法
??顧名思義,圖片變換的意思就是說,Glide從加載了原始圖片到最終展示給用戶之前,又進行了一些變換處理,從而能夠?qū)崿F(xiàn)一些更加豐富的圖片效果,如圖片圓角化、圓形化、模糊化等等。
??添加圖片變換的用法非常簡單,我們只需要調(diào)用transform()方法,并將想要執(zhí)行的圖片變換操作作為參數(shù)傳入transform()方法即可,如下所示:

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

至于具體要進行什么樣的圖片變換操作,這個通常都是需要我們自己來寫的。不過Glide已經(jīng)內(nèi)置了兩種圖片變換操作,我們可以直接拿來使用,一個是CenterCrop,一個是FitCenter。

但這兩種內(nèi)置的圖片變換操作其實都不需要使用transform()方法,Glide為了方便我們使用直接提供了現(xiàn)成的API:

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

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

當(dāng)然,centerCrop()和fitCenter()方法其實也只是對transform()方法進行了一層封裝而已,它們背后的源碼仍然還是借助transform()方法來實現(xiàn)的,如下所示:

public class DrawableRequestBuilder<ModelType>
        extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>
        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<ModelType> 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<ModelType> 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的,這個是重中之重,因為整個圖片變換功能都是建立在這個繼承結(jié)構(gòu)基礎(chǔ)上的。
??接下來CenterCrop中最重要的就是transform()方法,其他的方法我們可以暫時忽略。transform()方法中有四個參數(shù),每一個都很重要,我們來一一解讀下。第一個參數(shù)pool,這個是Glide中的一個Bitmap緩存池,用于對Bitmap對象進行重用,否則每次圖片變換都重新創(chuàng)建Bitmap對象將會非常消耗內(nèi)存。第二個參數(shù)toTransform,這個是原始圖片的Bitmap對象,我們就是要對它來進行圖片變換。第三和第四個參數(shù)比較簡單,分別代表圖片變換后的寬度和高度,其實也就是override()方法中傳入的寬和高的值了。
??下面我們來看一下transform()方法的細(xì)節(jié),首先第一行就從Bitmap緩存池中嘗試獲取一個可重用的Bitmap對象,然后把這個對象連同toTransform、outWidth、outHeight參數(shù)一起傳入到了TransformationUtils.centerCrop()方法當(dāng)中。那么我們就跟進去來看一下這個方法的源碼,如下所示:

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)實現(xiàn)的transformation有Crop,Color,Blur,Mask

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容