Android高級渲染 - 用ColorMatrix做美圖小軟件

隔了一年多去看這篇文章,發(fā)現(xiàn)很多地方會有問題,比如7.0后拍照的問題,當(dāng)時用的6.0的系統(tǒng),所以7.0以上的系統(tǒng)一定會崩潰。還有就是加完濾鏡之后無法修改模糊效果。
源碼等可能暫時不維護(hù),存在不少問題。

1、效果展示

用ColorMatrix可以調(diào)節(jié)圖片顏色比例,做到濾鏡的效果。這里用ColorMatrix基本使用寫了一個小的APP,源碼地址:https://github.com/AxeChen/ColorFilter
先上一波效果圖:

效果圖一

效果圖二

利用安卓自帶的API即可完成一些簡單的圖片濾鏡,調(diào)整圖片的對比度亮度等屬性。

2、實現(xiàn)思路

主要思路:選擇相冊圖片或者拍照獲取圖片,然后通過修改ColorMatrix來實現(xiàn)各種不同的濾鏡效果或者通過修改BlurMaskFilter來實現(xiàn)邊框的虛化等效果。

3、主要技術(shù)

3.1、主要技術(shù)點

(1)顏色矩陣ColorMatrix的應(yīng)用(濾鏡,調(diào)整亮度等主要用到的技術(shù))。
(3)BlurMaskFilter邊框虛化。
(4)6.0相機相冊權(quán)限處理。
(5)Bitmap的一些處理:壓縮,生成新的bitmap等。
(6)其他的一些技術(shù)點:一些控件的簡單使用,例如(RecyclerView,Toobar)、分享圖片等。

3.2 顏色矩陣ColorMatrix

應(yīng)用ColorMatrix可以調(diào)節(jié)圖片顏色比例,實現(xiàn)一些濾鏡,調(diào)節(jié)圖片亮度、對比度等效果。

3.2.1 ColorMatrix簡單介紹

在Android中使用顏色矩陣ColorMatrix,來處理圖像的色彩效果。對于圖像的每個像素點,都有一個顏色矩陣A用來保存顏色的RGBA值。在處理圖像是將顏色矩陣和顏色矩陣分量C相乘。

顏色矩陣

顏色處理

在安卓中使用一個一維數(shù)組表示顏色矩陣:

    public static final float[] src = {
            1f, 0, 0, 0, 0,    
            0, 1f, 0, 0, 0,
            0, 0, 1f, 0, 0,
            0, 0, 0, 1f, 0,
    };

如果對顏色矩陣基本知識有些難理解??梢圆患m結(jié)這些基本的知識,只抓住重點:只要改變顏色矩陣對應(yīng)的數(shù)組中元素的值,就可以改變圖片中顏色的比例!

對應(yīng)一維數(shù)組控制的顏色屬性:
第一行決定新的顏色值中的紅色R。
第二行決定新的顏色值中的綠色G。
第三行決定新的顏色值中的藍(lán)色B。
第四行決定新的顏色值中的透明度A。
第五列表示每個顏色的偏移量。

因此只要合理改變這個數(shù)組中不同元素的值就可以實現(xiàn)不同顏色效果了。

3.2.1 ColorMatrix使用

直接上關(guān)鍵代碼:

public class FilterImageView extends FilterView {

     // ... 省略若干代碼

    private Paint paint;
    private ColorMatrixColorFilter colorMatrixColorFilter;
    private ColorMatrix colorMatrix;


    @Override
    protected void onDraw(Canvas canvas) {
        paint.reset();
        paint.setAntiAlias(true);
        if (colorMatrixColorFilter != null) {
               paint.setColorFilter(colorMatrixColorFilter);
         }
        canvas.drawBitmap(bitmap, null, rectF, paint);
        canvas.save();
    }

    @Override
    public void setFloat(float[] floats) {
        colorMatrix = new ColorMatrix();
        colorMatrix.set(floats);
        colorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix);
        invalidate();
    }


   // ... 省略若干代碼
}

代碼步驟:
1、初始化ColorMatrixColorFilter 和 ColorMatrix 。
2、在onDraw()方法中通過paint.setColorFilter()方法將ColorMatrixColorFilter設(shè)置給paint。
3通過 canvas.drawBitmap()將Bitmap畫出來即可。(不僅僅是drawBitmap只要drawXX方法中傳入了設(shè)置過ColorMatrixColorFilter的paint都可實現(xiàn)顏色改變的效果)。

3.2.2 修改顏色矩陣對應(yīng)的數(shù)組

改變顏色矩陣對應(yīng)的數(shù)組的數(shù)組元素值,可以展示不同的顏色效果。
一些簡單的修改:
1、改變顏色的偏移量的值(下面的r、g、b、a);
2、改變對應(yīng) RGBA(下面的R、G、B、A) 值的系數(shù)。
如下說明:

 public static final float[] src = {
            R, 0, 0, 0, r,          
            0, G, 0, 0, g,          
            0, 0, B, 0, b,          
            0, 0, 0, A, a,          
    };

以上:
R、G、B的值可以增大或者變小。
A的范圍為0f-1f(可以設(shè)置比1f更大,但是效果和1f是一樣的)
而偏移量r、g、b、a的范圍是0f-255f(可以設(shè)置比255f更大,但是效果和255f是一樣的)
改變R、G、B、A或者r、g、b、a的值都可以改變圖片的顏色的比例和透明度。
這些值越大,圖片中對應(yīng)顏色所占的比例就越大或者越不透明。
例如:

    public static final float[] green = {
            1f, 0, 0, 0, 0,
            0, 1.2f, 0, 0, 0,
            0, 0, 1f, 0, 0,
            0, 0, 0, 1f, 0,
    };

以上把G值調(diào)整成1.2f 。就能增加圖片中綠色的比例。

綠色加強

一些復(fù)雜的修改:
通過調(diào)節(jié)數(shù)組中多個元素來做出不同的效果。
例如灰度效果:

    /**
     * 灰度效果
     */
    public static final float[] gray = {
            0.213f, 0.715f, 0.072f, 0, 0,
            0.213f, 0.715f, 0.072f, 0, 0,
            0.213f, 0.715f, 0.072f, 0, 0,
            0, 0, 0, 1, 0,
    };
灰度效果

修改數(shù)組中多個元素的值來改變圖片中顏色的比例,從而達(dá)到灰度的效果。

3.2.2 調(diào)節(jié)亮度和對比度

ColorMatrix提供了多個方法來修改圖片,例如:

直接將R、G、B、A傳入,修改顏色所占比重:

public void setScale(float rScale, float gScale, float bScale,
                         float aScale) 

調(diào)節(jié)圖片的對比度:

public void setSaturation(float sat)

顏色旋轉(zhuǎn)(可以做色調(diào)效果):

public void setRotate(int axis, float degrees)

修改對比度和亮度代碼如下:


     // ... 省略若干代碼

    private Paint paint;
    private ColorMatrixColorFilter colorMatrixColorFilter;
    private ColorMatrix colorMatrix;


    @Override
    protected void onDraw(Canvas canvas) {
        paint.reset();
        paint.setAntiAlias(true);
        if (colorMatrixColorFilter != null) {
               paint.setColorFilter(colorMatrixColorFilter);
         }
        canvas.drawBitmap(bitmap, null, rectF, paint);
        canvas.save();
    }
    /**
     * @param light 0f -2f
     */
    public void changeLight(float light) {
        colorMatrix = new ColorMatrix();
        colorMatrix.setScale(light, light, light, 1f);
        colorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix);
        invalidate();
    }

    /**
     * @param saturaction 0f - 2f
     */
    public void changeSaturation(float saturaction) {
        colorMatrix = new ColorMatrix();
        colorMatrix.setSaturation(saturaction);
        colorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix);
        invalidate();
    }

其中修改亮度的修改,就是將R、G、B三種顏色的比例不斷增大。

調(diào)節(jié)對比度和亮度

3.3 BlurMaskFilter虛化邊框

MaskFilter

MaskFilter有兩個子類:
BlurMaskFilter :可實現(xiàn)模糊效果。
EmbossMaskFilter:可實現(xiàn)凸起效果。
這里用到了BlurMaskFilter 做虛化邊框的效果:
BlurMaskFilter 的構(gòu)造函數(shù):

public BlurMaskFilter(float radius, Blur style)

radius:模糊的寬度。
style:枚舉變量,提供不同的效果:

public enum Blur {
        /**
         * Blur inside and outside the original border.
         */
        NORMAL(0),

        /**
         * Draw solid inside the border, blur outside.
         */
        SOLID(1),

        /**
         * Draw nothing inside the border, blur outside.
         */
        OUTER(2),

        /**
         * Blur inside the border, draw nothing outside.
         */
        INNER(3);
        
        Blur(int value) {
            native_int = value;
        }
        final int native_int;
    }

使用模糊效果會用到幾個關(guān)鍵類:BlurMaskFilter、Paint 、canvas。
代碼步驟:
1、初始化BlurMaskFilter。
2、然后通過paint.setMaskFilter()法將BlurMaskFilter設(shè)置給paint。
3、通過canvas.drawBitmap()方法即可實現(xiàn)圖片的模糊效果。(不僅僅是drawBitmap只要drawXX方法中傳入了設(shè)置過BlurMaskFilter的paint都可實現(xiàn)模糊效果)


虛化邊框效果

不過BlurMaskFilter遇到幾個問題:

1、 虛化的顏色由背景由圖片的邊緣顏色決定的,如果圖片邊緣的顏色為白色,那么虛化部分的顏色是白色的。
2、 虛化寬度的最大值并沒有找到。這個類調(diào)用的是native的方法,我不知道怎么去處理。
3、保存圖片之后有點失真。

3.4 其他需要注意的問題

3.4.1、選擇相冊圖片和使用相機的6.0權(quán)限處理

第一步:AndroidManifest.xml文件中申明權(quán)限:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />

動態(tài)申請權(quán)限:

    //申請相機權(quán)限
    protected boolean requestCameraPermiss() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERMISSION_CAMERA);
            return false;
        }
        return true;
    }

    //申請讀取文件權(quán)限
    protected boolean requestAlbumPermiss() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_CAMERA);
            return false;
        }
        return true;

    }
3.4.2、Bitmap的壓縮、生成新的bitmap等
3.4.2.1 生成新的Bitmap

如果需要通過一個Bitmap生成一個新的Bitmap,需要將Bitmap畫在一個新的Bitmap畫布上??创a注釋。

    @Override
    public Bitmap getChangeBitmap() {
        //初始化一個Bitmap
        Bitmap bitmapAltered = Bitmap.createBitmap((int) rectF.right, (int) rectF.bottom, bitmap.getConfig());
        //將初始化的Bitmap當(dāng)作畫布
        Canvas canvas = new Canvas(bitmapAltered);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColorFilter(colorMatrixColorFilter);
        if (drawType == DRAW_TYPE_MASK) {
            if (blurMaskFilter != null) {
                paint.setMaskFilter(blurMaskFilter);
            }
        }
      //將一個bitmap畫在畫布上(注:這里的bitmap是一個全局的變量,它就是一個普通的Bitmap)
        canvas.drawBitmap(bitmap, null, rectF, paint);
     //返回第一個Bitmap即可
        return bitmapAltered;
    }
3.4.2.2 圖片壓縮的方法:

防止圖片過大導(dǎo)致OOM,這里通過 BitmapFactory.Options 對圖片進(jìn)行壓縮之后再展示。

  /**
     * 讀取圖片,按照縮放比保持長寬比例返回bitmap對象
     * <p>
     *
     * @param path  圖片全路徑
     * @param scale 縮放比例(1到10, 為2時,長和寬均縮放至原來的2分之1,為3時縮放至3分之1,以此類推)
     * @return Bitmap
     */
    public synchronized static Bitmap readBitmap(String path, int scale) {
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            // 設(shè)置縮放比例
            options.inSampleSize = scale;
            // 設(shè)置為false,解析Bitmap對象加入到內(nèi)存中
            options.inJustDecodeBounds = false;
            // 設(shè)置內(nèi)存不足時,比bitmap對象可以被回收
            options.inPurgeable = true;
            options.inInputShareable = true;
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            Bitmap bitmap = BitmapFactory.decodeFile(path, options);
            return bitmap;
        } catch (Exception e) {
            return null;
        }
    }
3.4.3、圖片的分享

這里通過安卓自帶的方法來做分享:

    Intent sendIntent = new Intent();
    sendIntent.setAction(Intent.ACTION_SEND);
    sendIntent.putExtra(Intent.EXTRA_STREAM, imageUrl);
    sendIntent.setType("image/");
    startActivity(Intent.createChooser(sendIntent, "分享圖片"));
分享圖片

3.5、推薦的鏈接

colorMatrx :
http://www.itdecent.cn/p/9a44d04f39fc
http://www.itdecent.cn/p/a870fb9684d5
6.0權(quán)限:
http://www.itdecent.cn/p/5e05691d9c76
http://blog.csdn.net/yanzhenjie1003/article/details/52503533/
分享圖片:
http://www.itdecent.cn/p/f790833e669d
http://www.itdecent.cn/p/25c84ed9046d

源碼地址:https://github.com/AxeChen/ColorFilter

原創(chuàng)不易,如果大佬對這篇文章感興趣,還望點個贊,給點鼓勵!

最后編輯于
?著作權(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)容