零、前言
1.做安卓的大多應該對顏色不太敏感,畢竟我們是敲程式碼的,顏色有設計師呢。
2.不過作為一名在大學被顏色薰(陶)過四年的人,對顏色多少還是挺親切的(雖然當時挺討厭的)
3.紀念也好,記錄也罷,為它寫篇總結也理所應當
4.如果你覺得並不需要了解關於顏色的知識,那你可以將本文當做一篇科普文(出去跟人家吹吹牛還是夠用的)
一、顏色知識科普:
這一切都要從光開始:
有個叫牛頓的人拿一塊三稜鏡將太陽光折射出了彩色產生色散現象:
----色散現象說明光在介質中的速度v=c/n(或折射率n)隨光的頻率f而變,從而:證明了光具有波動性
複製程式碼
光的色散 | 光的色散圖示 |
---|---|
關於黑與白
問:如果把所有非黑的顏料混合,會得到什麼?----感覺一團糟,應該是黑色吧
問:如果把所有非白的光混合,會得到什麼?----感覺越來越亮,應該是白色吧
複製程式碼
為何光的疊加和顏料的疊加會產生相反的效果?
從一開始,這個問題就困擾著我,也將一直困擾這我...
如果說[肉眼所見到的光線,是由波長範圍很窄的電磁波產生的,不同波長的電磁波表現為不同的顏色],
那光的疊加也就是波的疊加,貌似有個[波動方程]吧...只能這樣說服自己:
光色疊加是減色模式:會越來約"淡"
顏料色疊加是加色模式:會越來約"濃"
複製程式碼
色彩模式
1.RGB:裝置相關的顏色模型
安卓敲程式碼的多少都用過
#ffff00
表示黃色吧,這是RGB的一種表現形式
你也可以用"R:255,G:255,B:0"來表示黃色,其實兩者是一個意思,只不過是10進位制和16進位制的轉化
RGB的位數:
RGB還有位數的區別,也就是一個顏色佔幾位,一般是8位,
也就是用1個位元組表示一種顏色(一個位元組8位)
1個位元組(8位)每種顏色有0~255共256種中顏色,三色共表達:256*256*256=16,777,216種顏色
所以RGB並不能代表所有顏色,它只是一個子集,自然界的顏色是無窮的。人類只能模擬
16位是2個位元組代表一種顏色,每種顏色有0~65535共65536中顏色,
三色共表達:65536*65536*65536=279213318656種顏色
複製程式碼
2.ARGB:裝置相關的顏色模型(加透明度)
即在RGB的基礎上新增新增透明度
顏色通道的概念(自己的理解,僅供參考):
大學那會學ps,動不動紅色通道,Alpha通道的,搞得雲裡霧裡,現在想想
拿ARGB_8888(八位)來說,就相當有四道牆,每道牆上有256扇門分別標上0~255數字
第一道牆叫Alpha(透明度)牆,第二道牆叫R(紅)牆,第二道牆叫G(綠)牆,第二道牆叫B(藍)牆
現在你要從這四道牆的門走到終點,每次進門拿著門牌號,當你走到終點時,門牌號加起來就是顏色
那門,就是通道,如果進紅色的0門(俗稱:紅色通道關閉),從表現上來看最終顏色不帶紅色,如下下圖
複製程式碼
為什麼程式設計裡用
int
作為顏色?
眾所周知:一個int佔4個位元組,也就是4*8個位,剛好用來盛放ARGB_8888。
複製程式碼
3.CMYK:C(青)M(品紅)Y(黃)K(黑色)
作為程式設計師對CMYK瞭解估計不多,畢竟都在螢幕上,是ARGB的的天下
對於列印使用CMYK,符號是%,以不同顏色的百分比調色,理論上只應該有CMY就行了
但實際黑色(K)的要比其他三色更容易生產,用三張一百塊合成為一張十塊錢估計沒人會這麼做
至於為什麼叫K...也許是RGB先出來的,然後不能叫B,只能叫K了
複製程式碼
4.HSV:
看到值就能想到大概的顏色
顏色有三個維度屬性:色相、明度和飽和度
HSV模型對應於:
圓柱座標系中的一個圓錐形子集,圓錐的頂面對應於V=1。
它包含RGB模型中的R=1,G=1,B=1三個面,所代表的顏色較亮。
色彩H由繞V軸的旋轉角給定。紅色對應於角度0°,綠色對應於角度120°,藍色對應於角度240°。
在HSV顏色模型中,每一種顏色和它的補色相差180°。飽和度S取值從0到1,所以圓錐頂面的半徑為1。
複製程式碼
5.看一下黃色的幾種表達方式:
RGB:R:255 G:255 B:0 #ffff00
CMYK:C:10% M:0 Y:83% K:0
HSV:H:60° S:100% V:100%
複製程式碼
好了,科普結束,下面進入正題
一、Android中的Color
顏色使用場景:
1.基本使用:背景、陰影、文字顏色
2.基於Color建立的Bitmap以及疊合模式:Xfermode
3.paint中的著色、顏色過濾器 4.ColorMatrix的使用
1.常量:
2.建構函式
可見只有無引數構造可以用
3.常用方法:
int blue = Color.BLUE;//第一種獲取藍色方法
blue = Color.parseColor("#0000FF");//第二種獲取藍色方法
blue = Color.rgb(0, 0, 255);//第三種獲取藍色方法
blue = Color.argb(255, 0, 0, 255);//第四種獲取藍色方法
blue = Color.HSVToColor(new float[]{240.0f, 1.0f, 1.0f});//第五種獲取藍色方法
blue = 0xff0000FF;//第六種獲取藍色方法
//(吐槽:怎麼有種孔乙己說茴香豆的茴字有多少種寫法一樣...,看哪個順手就用哪個吧)
float[] hsv = {0, 0, 0};//hsv陣列
Color.RGBToHSV(0, 0, 255, hsv);//將RGB轉為hsv
Log.e(TAG, "onDraw: " + hsv[0]+","+hsv[1]+","+hsv[2]);
//onDraw: 240.0,1.01.0
複製程式碼
其實Color的本身並沒有太多的知識點,畢竟就是一個int而已,難點在於顏色的拼合與變換
二、Android點陣圖封裝類:Bitmap
什麼是點陣圖,前面講過顏色是按位儲存的,ARGB_8888每種顏色佔8位
相信大家都知道一張jpg或png放大後會是一個個小格子,稱為一個畫素(px),而且一個小格子是一種顏色
也就是一張jpg或png圖片就是很多顏色的合集,而這些合集資訊都被封裝到了Bitmap類中
你可以使用Bitmap獲取任意畫素點,並修改它,對與某畫素點而言,顏色資訊是其主要的部分
1.重新認識Bitmap
我們一般使用Bitmap是都是用BitmapFactory來decode資源,所以並未設計太多Bitmap的操作,以致認為Bitmap=圖片
Bitmap實際是一個封裝圖片畫素資訊的類,它能顯示出來是因為View及手機的硬體
1).建立一個Bitmap:
注意區別bitmapCanvas和View中OnDraw中Canvas的區別:
這裡:bitmapCanvas是負責在點陣圖(Bitmap)上繪製,讓點陣圖記錄影素點位資訊的
OnDraw中Canvas是用來在View上繪製,顯示在螢幕上的。
打個不恰當的比方:
你是bitmapCanvas,負責畫一張圖(Bitmap),你畫完後不能直接交給印刷人員(View)去印
需要交給審稿員(OnDraw中canvas),經過他允許才能給印刷人員
/**
* 建立一個Bitmap
*
* @param color 背景色
* @return bitmap
*/
private Bitmap createBitmap(int color) {
//建立一個ARGB_8888,寬高200的bitmap
Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
//使用Bitmap建立一個canvas畫板,畫板上的一切都會保留在bitmap上
Canvas bitmapCanvas = new Canvas(bitmap);
//接下來就是在畫板上操作
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(color);
Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
bitmapCanvas.drawRect(rect, p);
p.setColor(Color.GRAY);
p.setStrokeWidth(3);
bitmapCanvas.drawLine(0, 0, 200, 200, p);
bitmapCanvas.drawLine(200, 0, 0, 200, p);
return bitmap;
}
複製程式碼
OnDraw中使用Bitmap,使用Bitmap,使用Bitmap...
//審稿人統一,印刷到View上
canvas.drawBitmap(mBitmap, 100, 100, mMainPaint);
複製程式碼
三、Xfermode:圖片疊合時的處理方式
終於寫到這裡了,總算與Xfermode相遇了,最喜歡分析很多的情況,這裡有18種模式,想想都激動...。
做開發的,我們應該知道src和dst吧src是源,dst是目標,在react裡就有src的原始檔,和dest的輸出檔案
圖片疊合顧名思義,必須有兩個圖片才行,這裡原圖src用藍色正方形,目標dst用綠色圓形
1.src和dst圖片
/**
* 建立源圖片
*
* @return bitmap
*/
private Bitmap createSrcBitmap() {
//建立一個ARGB_8888,寬高200的bitmap
Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
//使用Bitmap建立一個canvas畫板,畫板上的一切都會保留在bitmap上
Canvas bitmapCanvas = new Canvas(bitmap);
//接下來就是在畫板上操作
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(0x882045F3);
Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
bitmapCanvas.drawRect(rect, p);
return bitmap;
}
/**
* 建立目標
*
* @return bitmap
*/
private Bitmap createDstBitmap() {
//建立一個ARGB_8888,寬高200的bitmap
Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
//使用Bitmap建立一個canvas畫板,畫板上的一切都會保留在bitmap上
Canvas bitmapCanvas = new Canvas(bitmap);
//接下來就是在畫板上操作
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(0xff43F41D);
bitmapCanvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getHeight() / 2,p);
return bitmap;
}
複製程式碼
2.疊合模式18種:android.graphics.PorterDuff.Mode
別怕,別怕,一幅圖展示一下:
public enum Mode {
CLEAR (0),
SRC (1),
DST (2),
SRC_OVER (3),
DST_OVER (4),
SRC_IN (5),
DST_IN (6),
SRC_OUT (7),
DST_OUT (8),
SRC_ATOP (9),
DST_ATOP (10),
XOR (11),
DARKEN (16),
LIGHTEN (17),
MULTIPLY (13),
SCREEN (14),
ADD (12),
OVERLAY (15);
Mode(int nativeInt) {
this.nativeInt = nativeInt;
}
public final int nativeInt;
}
複製程式碼
3.如何優雅地繪製下面一幅圖:
注意:測試了一下,開不開硬體加速對這東西有影響,下面在無有硬體加速:
android:hardwareAccelerated="false"
mMainPaint.setXfermode(XXX);放置的順序也很重要,在下面的是疊合的源
網上有一組圖,不過沒有透明度,我對源(藍色)加了88的透明度,顯示的更清楚些
注意:看正方形框裡的內容,看正方形框裡的內容,看正方形框裡的內容!因為它是被疊合的物件
private void init() {
mMainPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mMainPaint.setStyle(Paint.Style.FILL);
mMainPaint.setStrokeCap(Paint.Cap.ROUND);
src = createSrcBitmap();
dst = createDstBitmap();
//背景圖層的筆
mLayerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mLayerPaint.setStyle(Paint.Style.FILL);
mLayerPaint.setFilterBitmap(false);
//文字的筆
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setTextSize(45);
Typeface typeface = Typeface.create(Typeface.MONOSPACE, Typeface.BOLD);
mTextPaint.setTypeface(typeface);
mTextPaint.setColor(0xffF98D1F);
//虛線畫筆
mDashPaint = new Paint();
mDashPaint.setStrokeWidth(3);
mDashPaint.setColor(Color.RED);
mDashPaint.setStyle(Paint.Style.STROKE);
//設定虛線效果new float[]{可見長度, 不可見長度},偏移值
mDashPaint.setPathEffect(new DashPathEffect(new float[]{10, 5}, 0));
mModes = new PorterDuffXfermode[]{
new PorterDuffXfermode(PorterDuff.Mode.CLEAR),//0
new PorterDuffXfermode(PorterDuff.Mode.SRC),//1
new PorterDuffXfermode(PorterDuff.Mode.DST),//2
new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),//3
new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),//4
new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),//5
new PorterDuffXfermode(PorterDuff.Mode.DST_IN),//6
new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),//7
new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),//8
new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),//9
new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),//10
new PorterDuffXfermode(PorterDuff.Mode.XOR),//11
new PorterDuffXfermode(PorterDuff.Mode.DARKEN),//12
new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),//13
new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),//14
new PorterDuffXfermode(PorterDuff.Mode.SCREEN),//15
new PorterDuffXfermode(PorterDuff.Mode.ADD),//16
new PorterDuffXfermode(PorterDuff.Mode.OVERLAY),//17
};
mModeText = new String[]{"CLEAR", "SRC", "DST", "SRC_OVER", "DST_OVER", "SRC_IN",
"DST_IN", "SRC_OUT", "DST_OUT", "SRC_ATOP", "DST_ATOP", "XOR", "DARKEN",
"LIGHTEN", "MULTIPLY", "SCREEN", "ADD", "OVERLAY"
};
}
複製程式碼
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//建立一個圖層,在圖層上演示圖形混合後的效果
int sc = 0;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
sc = canvas.saveLayer(new RectF(0, 0, 2500, 2500), mLayerPaint);
}
for (int i = 0; i < 18; i++) {
int line = i % 6;
int row = i / 6;
canvas.drawBitmap(dst, 350 * line, row * 350, mMainPaint);//目標圖象
mMainPaint.setXfermode(mModes[i]);//設定對源的疊合模式
canvas.drawBitmap(src, 100 + 350 * line, 100 + row * 350, mMainPaint);
//輔助資訊
canvas.drawText(mModeText[i],100 + 350 * line, 300 + row * 350,mTextPaint);
canvas.drawCircle(100 + 350 * line, 100 + row * 350, 100, mDashPaint);
canvas.drawRect(100 + 350 * line, 100 + row * 350, 100 + 200 + 350 * line, 100 + 200 + row * 350, mDashPaint);
}
canvas.restoreToCount(sc);
}
複製程式碼
四、著色器:Shader(本節在Paint篇也有,為保全Color篇的完整性,這裡cv了一下)
一個很簡單的類,有5個子類:
1.線性漸變:
1).new LinearGradient(漸變起點x,y,漸變終點x,y,漸變色1,漸變色2,漸變模式)
漸變模式:
Shader.TileMode.
[MIRROR
|CLAMP
|REPEAT
] (圖中很形象,就不解釋了)
int colorStart = Color.parseColor("#84F125");
int colorEnd = Color.parseColor("#5825F1");
canvas.save();
canvas.translate(mCoo.x, mCoo.y);
mRedPaint.setStyle(Paint.Style.FILL);
mRedPaint.setShader(
new LinearGradient(
-200, 0, 200, 0,
colorStart, colorEnd,
Shader.TileMode.MIRROR
));
canvas.drawRect(-400,-200,400,-100,mRedPaint);
canvas.translate(0, 150);
mRedPaint.setShader(
new LinearGradient(
-100, 0, 100, 0,
colorStart, colorEnd,
Shader.TileMode.CLAMP
));
canvas.drawRect(-400,-200,400,-100,mRedPaint);
canvas.translate(0, 150);
mRedPaint.setShader(
new LinearGradient(
-100, 0, 100, 0,
colorStart, colorEnd,
Shader.TileMode.REPEAT
));
canvas.drawRect(-400,-200,400,-100,mRedPaint);
複製程式碼
2).多色多點漸變:LinearGradient(漸變起點x,y,漸變終點x,y,顏色陣列,位置百分點陣列0~1,漸變模式)
int[] colors = new int[]{
Color.parseColor("#F60C0C"),//紅
Color.parseColor("#F3B913"),//橙
Color.parseColor("#E7F716"),//黃
Color.parseColor("#3DF30B"),//綠
Color.parseColor("#0DF6EF"),//青
Color.parseColor("#0829FB"),//藍
Color.parseColor("#B709F4"),//紫
};
float[] pos = new float[]{
1.f / 7, 2.f / 7, 3.f / 7, 4.f / 7, 5.f / 7, 6.f / 7, 1
};
canvas.translate(0, 150);
mRedPaint.setShader(
new LinearGradient(
-300, 0, 300, 0,
colors, pos,
Shader.TileMode.CLAMP
));
canvas.drawRect(-400, -200, 400, -100, mRedPaint);
複製程式碼
2.徑向漸變:RadialGradient
1).兩色漸變:RadialGradient(漸變中心,漸變半徑,顏色1,顏色2,漸變模式)
canvas.translate(mCoo.x, mCoo.y);
int colorStart = Color.parseColor("#84F125");
int colorEnd = Color.parseColor("#5825F1");
mRedPaint.setStyle(Paint.Style.FILL);
mRedPaint.setShader(
new RadialGradient(
0,0,50,
colorStart, colorEnd,
Shader.TileMode.MIRROR
));
canvas.drawCircle(0, 0, 150, mRedPaint);
canvas.translate(350, 0);
mRedPaint.setShader(
new RadialGradient(
0,0,50,
colorStart, colorEnd,
Shader.TileMode.CLAMP
));
canvas.drawCircle(0, 0, 150, mRedPaint);
canvas.translate(350, 0);
mRedPaint.setShader(
new RadialGradient(
0,0,50,
colorStart, colorEnd,
Shader.TileMode.REPEAT
));
canvas.drawCircle(0, 0, 150, mRedPaint);
複製程式碼
2).多色多點徑向漸變:
RadialGradient(漸變中心,漸變半徑,漸變模式,顏色陣列,位置百分點陣列0~1,漸變模式)
int[] colors = new int[]{
Color.parseColor("#F60C0C"),//紅
Color.parseColor("#F3B913"),//橙
Color.parseColor("#E7F716"),//黃
Color.parseColor("#3DF30B"),//綠
Color.parseColor("#0DF6EF"),//青
Color.parseColor("#0829FB"),//藍
Color.parseColor("#B709F4"),//紫
};
float[] pos = new float[]{
1.f / 7, 2.f / 7, 3.f / 7, 4.f / 7, 5.f / 7, 6.f / 7, 1
};
mRedPaint.setStyle(Paint.Style.FILL);
mRedPaint.setShader(
new RadialGradient(
0, 0, 200,
colors, pos,
Shader.TileMode.CLAMP
));
canvas.drawCircle(0, 0, 250, mRedPaint);
複製程式碼
3.掃描漸變:SweepGradient
這個要比上面的簡單一點,沒有漸變的模式 雙色掃描漸變:SweepGradient(中心點x,y,顏色1,顏色2) 多色掃描漸變:SweepGradient(中心點x,y,顏色陣列,位置百分點陣列0~1)
int colorStart = Color.parseColor("#84F125");
int colorEnd = Color.parseColor("#5825F1");
mRedPaint.setStyle(Paint.Style.FILL);
mRedPaint.setShader(
new SweepGradient(0, 0, colorStart, colorEnd));
canvas.drawCircle(0, 0, 150, mRedPaint);
canvas.translate(400, 0);
int[] colors = new int[]{
Color.parseColor("#F60C0C"),//紅
Color.parseColor("#F3B913"),//橙
Color.parseColor("#E7F716"),//黃
Color.parseColor("#3DF30B"),//綠
Color.parseColor("#0DF6EF"),//青
Color.parseColor("#0829FB"),//藍
Color.parseColor("#B709F4"),//紫
};
float[] pos = new float[]{
1.f / 7, 2.f / 7, 3.f / 7, 4.f / 7, 5.f / 7, 6.f / 7, 1
};
mRedPaint.setShader(
new SweepGradient(0, 0, colors, pos));
canvas.drawCircle(0, 0, 150, mRedPaint);
複製程式碼
4.圖片著色器:BitmapShader(圖片,著色模式x,著色模式y)
用圖片的所有畫素點作為畫筆的顏色
1).文字的圖片底色:
//載入圖片,生成圖片著色器
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.menu_bg);
BitmapShader bs = new BitmapShader(bitmap, Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
mRedPaint.setShader(bs);
mRedPaint.setTextSize(150);
mRedPaint.setStrokeWidth(10);
mRedPaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawText("張風捷特烈", 0, 500, mRedPaint);
複製程式碼
2)路徑+圖片著色器實現裁剪圖片:路徑Path相關知識見上一篇:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.menu_bg);
BitmapShader bs = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mRedPaint.setShader(bs);
mRedPaint.setStyle(Paint.Style.FILL);
Path path = CommonPath.nStarPath(8, 500, 250);
canvas.drawPath(path, mRedPaint);
複製程式碼
還有一個ComposeShader比較複雜,以後有需求會專門寫一篇
七、顏色過濾器:(Paint篇有,但本篇更加深入)
ColorFilter只有三個子類
1.LightingColorFilter(顏色1,顏色2):
Bitmap mainBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.menu_bg);
mRedPaint.setStyle(Paint.Style.FILL);
mRedPaint.setColorFilter(new LightingColorFilter(
Color.parseColor("#F00000"),//紅
Color.parseColor("#0000ff")//藍
));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);
canvas.translate(350, 0);
mRedPaint.setColorFilter(new LightingColorFilter(
Color.parseColor("#FF0000"),//紅
Color.parseColor("#00ff00")//綠
));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);
canvas.translate(350, 0);
mRedPaint.setColorFilter(new LightingColorFilter(
Color.parseColor("#FF0000"),//紅
Color.parseColor("#000000")//黑
));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);
canvas.restore();
複製程式碼
下面分析一下紅藍配的結果:開啟LightingColorFilter原始碼:
/**
* Create a colorfilter that multiplies the RGB channels by one color,
* and then adds a second color. The alpha components of the mul and add
* arguments are ignored.
建立一個顏色過濾器:用mul顏色乘以RGB通道的顏色,再加上add顏色,mul和add的透明度將被忽略
*/
public LightingColorFilter(@ColorInt int mul, @ColorInt int add) {
mMul = mul;
mAdd = add;
}
//看了沒什麼感覺,又是native的方法,往上一看,有註釋
* Given a source color RGB, the resulting R'G'B' color is computed thusly:
* R' = R * colorMultiply.R + colorAdd.R
* G' = G * colorMultiply.G + colorAdd.G
* B' = B * colorMultiply.B + colorAdd.B
複製程式碼
這下明白了,就是顏色變換嘛----草稿紙準備好,要演算了:
注意:當相乘數大於255時,便會溢位,相當於8位容不下那麼多數,後面再進來,前面的就被推出來了
這裡為了區別,特意用#F00000來測試,結果有一點點偏差,畢竟兩次選點的點位可能有偏差
活了這麼大,第一次對顏色進行乘法和加法,對於一張圖片,加上綠色就是對每個畫素點進行這樣的運算
2.PorterDuffColorFilter(顏色,模式--PorterDuff.Mode):
PorterDuff.Mode是不是很熟悉,看上面的疊加模式吧
Bitmap mainBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.menu_bg);
mRedPaint.setStyle(Paint.Style.FILL);
mRedPaint.setColorFilter(new PorterDuffColorFilter(
Color.parseColor("#0000ff"), PorterDuff.Mode.DARKEN));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);
canvas.translate(350, 0);
mRedPaint.setColorFilter(new PorterDuffColorFilter(
Color.parseColor("#0000ff"),PorterDuff.Mode.LIGHTEN
));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);
canvas.translate(350, 0);
mRedPaint.setColorFilter(new PorterDuffColorFilter(
Color.parseColor("#0000ff"),PorterDuff.Mode.SCREEN
));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);
canvas.translate(350, 0);
mRedPaint.setColorFilter(new PorterDuffColorFilter(
Color.parseColor("#0000ff"),PorterDuff.Mode.OVERLAY
));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);
複製程式碼
3.ColorMatrixColorFilter(顏色變換矩陣或20個float數)
本文的重中之重便是ColorMatrix:
它是有一個5*4的矩陣對某個顏色進行運算,是不是有種眾星捧月的但覺,沒錯,20個數,是不是很開心
1.關閉RGB顏色通道(變為黑色)
顏色ARBG佔了int的四個位元組,所以不可能是負數,至於如何處理負數,要看ColorMatrix的處理
測試了一下,應該是0,ARGB都沒了
設為1後,結果[-R,-G,-B,A],黑色,符合預期:
2.關閉RGB顏色通道(變為黑色),後偏移紅色255
由於只有G、B不通,所以顯示是不同的紅色
3.關閉RGB顏色通道(變為黑色),後偏移藍色255
-1,0,0,0,0
0,-1,0,0,0
0,0,-1,0,255
0,0,0,1,0
複製程式碼
4.關閉RGB顏色通道(變為黑色),後偏移三色255
-1,0,0,0,255
0,-1,0,0,255
0,0,-1,0,255
0,0,0,1,0
複製程式碼
5.調節亮度:增加RGB的偏移顏色(-255~255)
6.灰度
//只要把RGB三通道的色彩資訊設定成一樣:即:R=G=B,
//為了保證影像亮度不變,同一個通道中的R+G+B=1
0.3086, 0.6094, 0.0820, 0, 0
0.3086, 0.6094, 0.0820, 0, 0
0.3086, 0.6094, 0.0820, 0, 0
0 , 0 , 0 , 1, 0
複製程式碼
7.飽和度:(這裡我亂調的,可參考色彩方面的書)
(R-1)*X + 1, G*X , B*X , 0, 0,
R*X , (G-1)*X + 1, B*X , 0, 0,
R*X , G*X , (B-1)*X + 1, 0, 0,
0 , 0 , 0 , 1, 0
R=0.3086,G=0.6094,B=0.0820
複製程式碼
/**
* 飽和度調節
* @param R 紅色保留比
* @param G 綠色保留比
* @param B 藍色保留比
* @param X 值越小越飽和----0為原圖
* @return
*/
private float[] colorM(float R, float G, float B, float X) {
float[] array= new float[]{
(R - 1) * X + 1, G * X, B * X, 0, 0,
R * X, (G - 1) * X + 1, B * X, 0, 0,
R * X, G * X, (B - 1) * X + 1, 0, 0,
0, 0, 0, 1, 0
};
return array;
}
複製程式碼
8.對比度:
X,0,0,0,128*(1-X) R X*R+128*(1-X)
0,X,0,0,128*(1-X) * G G*R+128*(1-X)
0,0,X,0,128*(1-X) B = B*R+128*(1-X)
0,0,0,1,0 A A
1
複製程式碼
private float[] colorM(float X) {
float[] array = new float[]{
X, 0, 0, 0, 128 * (1 - X),
0, X, 0, 0, 128 * (1 - X),
0, 0, X, 0, 128 * (1 - X),
0, 0, 0, 1, 0
};
return array;
}
複製程式碼
安卓自帶的圖片處理API
public void setSaturation(float sat) {
reset();
float[] m = mArray;
final float invSat = 1 - sat;
final float R = 0.213f * invSat;
final float G = 0.715f * invSat;
final float B = 0.072f * invSat;
m[0] = R + sat; m[1] = G; m[2] = B;
m[5] = R; m[6] = G + sat; m[7] = B;
m[10] = R; m[11] = G; m[12] = B + sat;
}
複製程式碼
mCmx.setSaturation(folat );
複製程式碼
終於寫完了,完結散花。
後記:捷文規範
1.本文成長記錄及勘誤表
專案原始碼 | 日期 | 備註 |
---|---|---|
V0.1--無 | 2018-11-10 | Android關於Color你所知道的和不知道的一切 |
2.更多關於我
筆名 | 微信 | 愛好 | |
---|---|---|---|
張風捷特烈 | 1981462002 | zdl1994328 | 語言 |
我的github | 我的簡書 | 我的CSDN | 個人網站 |
3.宣告
1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大程式設計愛好者共同交流
3----個人能力有限,如有不正之處歡迎大家批評指證,必定虛心改正
4----看到這裡,我在此感謝你的喜歡與支援