咱們在學畫畫的時候,首先須要買畫筆,而後再購買畫板,就能夠愉快的創做(瞎畫😄)啦!在安卓中也是這麼設計的,畢竟設計也是要符合實際生活規律的。OK,那麼本篇就是從畫筆的基礎開始講起。android
// 建立出一隻畫筆🖌️
Paint paint = new Paint()
複製代碼
mPaint.setColor(Color.parseColor("#ff00ff"));
mPaint.setColor(Color.argb(200, 200, 200,200));
// 或 setARGB 的方式
mPaint.setARGB(200, 200, 200, 200);
複製代碼
mPaint.setStrokeWidth(30);
複製代碼
// 有三種模式: FILL、STROKE、FILL_AND_STROKE
mPaint.setStyle(Paint.Style.STROKE);
複製代碼
mPaint.setAntiAlias(true);
複製代碼
來吧!看看效果左邊未設置抗鋸齒,右邊設置了抗鋸齒。git
你是否是想說,這不同嗎?這麼看確實看不出區別。畢竟是人的肉眼,確定沒辦法觀察到很細節的東西。那麼咱們經過放大後再觀察一下:github
這下你看到了吧!未開啓抗鋸齒算法優化的化,能夠看到邊緣有鋸齒形狀。而右側的就更加平順一些。那咱們有沒有必要開啓抗鋸齒呢? 其實大部分狀況下是能夠不開啓的,由於如今的手機分辨越來約高,只要不是對精細度追求極致的化,是能夠不用開啓的。算法
若是顆粒越小,是否是就會看起來是灰色啦,欺騙人的肉眼。 canvas
mPaint.setStrokeCap(Paint.Cap.ROUND);
複製代碼
線段與線段之間的形狀,可讓線段的鏈接看來更加圓潤仍是棱角分明。它也有三種: MITER、ROUND、BEVEL。從單詞的的翻譯來看,彷佛只知道 ROUND,直接來看效果圖。api
mPaint.setStrokeJoin(Paint.Join.ROUND);
複製代碼
仔細看的化能看出在四個頂點都有些不一樣,MITER 更加尖一些, ROUND 則圓潤一些,BEVEL 好像是切了一個角而來。ROUND 很好理解,說一些 MITER 和 BEVEl。它們二者都有類似之處,就是線段的末尾進行延長相交,對於 MITER 來講若是線段之間的夾角越小,那麼頂點就會越尖。再來看一張圖,這張圖就比剛纔矩形更加直觀了。數組
這個很簡單,就是從某一個建立好的畫筆複製一份使用bash
等同於分別設置 setAntiAlias(true) 和 setDither(true)
mPaint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
複製代碼
翻譯過來稱爲着色器,其實也是用來設置畫筆的顏色的。它有 5 個子類,依次是: LinearGradient、SweepGradient、RadialGradient、BitmapShader、ComposeShaderide
. LinearGradient 從名字能夠看出是線性漸變的意思,直接上效果圖優化
LinearGradient linearGradient = new LinearGradient(
300,
300,
700,
700,
Color.RED,
Color.YELLOW,
Shader.TileMode.CLAMP);
mPaint.setShader(linearGradient);
複製代碼
能夠看到接近最後一個點的地方設置成了藍色,這幾個參數的意思是: 起點的 x, y 左邊,終點的 x,y 座標,起點的顏色,終點的顏色, Shader.TileMode.CLAMP 在兩個端點以外延用端點的顏色。
再來看看其餘的用法,穩住別慌,堅持住。
LinearGradient linearGradient = new LinearGradient(
300,
300,
900,
900,
new int[] {
Color.RED,
Color.BLUE
},
new float[] {
0.5f,
0.5f
},
Shader.TileMode.CLAMP);
mPaint.setShader(linearGradient);
複製代碼
這回發現多了兩個參數,其實並無,只是用int[] 添加顏色,float[] 數組用來指定端點到某一個區域的填充的顏色,須要和前面的 int[] 數組長度一直,不然會 gg。
繼續來看 TileMode 的三種區別
MIRROR:
REPEAT
. SweepGradient 漸變,扇形漸變,也就是說某一個角度掃過的區域的漸變效果,能夠看到跟線性漸變的使用方式差很少。
SweepGradient sweepGradient = new SweepGradient(300, 300,
new int[]{Color.RED, Color.GREEN, Color.BLUE},
new float[]{
0.1f, 0.3f, 1.0f
});
mPaint.setShader(sweepGradient);
複製代碼
. RadialGradient 徑向漸變,根據圓的半徑進行漸變色
RadialGradient radialGradient = new RadialGradient(700, 700, 300,
new int[]{Color.RED, Color.GREEN, Color.BLUE},
new float[]{0.2f, 0.5f, 1.0f},
Shader.TileMode.CLAMP);
mPaint.setShader(radialGradient);
複製代碼
效果圖
它也有三種使用模式,其實跟線性漸變同樣。
RadialGradient radialGradient = new RadialGradient(700, 700, 100,
new int[]{Color.RED, Color.GREEN, Color.BLUE},
new float[]{0.2f, 0.5f, 1.0f},
Shader.TileMode.CLAMP); // 更換模式.
複製代碼
REPEAT:
RadialGradient radialGradient = new RadialGradient(700, 700, 150,
Color.RED, Color.BLUE, Shader.TileMode.MIRROR);
mPaint.setShader(radialGradient);
複製代碼
MIRROR:
. BitmapShader. Bitmap 是圖片,喲,圖片也能夠處理的哦!
BitmapShader bitmapShader = new BitmapShader(mBitmap,
Shader.TileMode.REPEAT,
Shader.TileMode.MIRROR);
mPaint.setShader(bitmapShader);
// 繪製一個矩形,填充 view 的寬高.
canvas.drawRect(0, 0, mWidth, mHeight, mPaint);
複製代碼
CLAMP: 以圖片的 x 軸的最後一個像素填充 x 軸和 y 軸
REPEAT:以相同的圖片進行填充.
MIRROR: 鏡像的方式填充,比如照鏡子同樣,原像和鏡像恰好相反
當前你也能夠混合,好比在 x 軸方向重複填充, y 軸方向鏡像填充
還能夠這樣:將圖片填充到圓裏
. ComposeShader 使用組合的方式,將前面的着色器配合來使用.
// 關閉硬件加速
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.beauty);
mHeartBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.heart);
BitmapShader bitmapShader1 = new BitmapShader(mBitmap,
Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
BitmapShader bitmapShader2 = new BitmapShader(mHeartBitmap,
Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
ComposeShader composeShader = new ComposeShader(bitmapShader1, bitmapShader2, PorterDuff.Mode.SRC_OUT);
mPaint.setShader(composeShader);
canvas.drawCircle(500, 500, 300, mPaint);
複製代碼
從名字就能夠看出,主要是對顏色進行過濾。就是在繪製以前先過濾點指定的顏色再進行顯示。也有三個子類供咱們使用: LightingColorFilter、PorterDuffColorFilter、ColorMatrixColorFilter
. LightingColorFilter 光照過濾,就比如咱們帶着太陽鏡過濾了太陽光中對眼睛有傷害的紫外線,而後眼睛看到了就是比較柔的。學到老活到老, 來看使用
LightingColorFilter colorFilter = new LightingColorFilter(
Color.parseColor("#ffffff"),
Color.parseColor("#000000"));
mPaint.setColorFilter(colorFilter);
複製代碼
經過看源碼,能夠看到它的計算規則是:
R' = R * colorMultiply.R + colorAdd.R G' = G * colorMultiply.G + colorAdd.G
B' = B * colorMultiply.B + colorAdd.B 複製代碼
不難發現,若是採起上面的方式設置 mul: #ffffff, add: #000000, 那麼計算以下:
R' = R * 0xff/0xff + 0x00 G' = G * 0xff/0xff + 0x00
B' = B * 0xff/0xff + 0x00 結果和原圖同樣. 複製代碼
如今若是要去掉原圖中紅色,只要將 mul 改成 0x00ffff, add 不變
LightingColorFilter colorFilter = new LightingColorFilter(
Color.parseColor("#00ffff"),
Color.parseColor("#000000"));
mPaint.setColorFilter(colorFilter);
複製代碼
加強紅色:mul 不變, add: 0x660000
LightingColorFilter colorFilter = new LightingColorFilter(
Color.parseColor("#ffffff"),
Color.parseColor("#660000"));
mPaint.setColorFilter(colorFilter);
複製代碼
. PorterDuffColorFilter
指定一種顏色爲源,採用圖形混合模式進行處理。
// 指定白色爲源,混合模式爲目標顯示 DST_OVER
PorterDuffColorFilter porterDuffColorFilter = new PorterDuffColorFilter(
Color.parseColor("#ffffff"),
PorterDuff.Mode.DST_OVER);
mPaint.setColorFilter(porterDuffColorFilter);
複製代碼
更改原圖顏色,並更改混合模式: SRC_OVER
PorterDuffColorFilter porterDuffColorFilter = new PorterDuffColorFilter(
Color.parseColor("#ED29AB"),
PorterDuff.Mode.SRC_OVER);
mPaint.setColorFilter(porterDuffColorFilter);
複製代碼
. ColorMatrixColorFilter
這個就比較兇殘了,由於是在是很是強大,內部是一個 4x5 的矩陣,經過變化矩陣中各通道的值,能夠實現各類效果。
[ a, b, c, d, e,
f, g, h, i, j,
k, l, m, n, o,
p, q, r, s, t ]
複製代碼
經過代碼搞搞事情,看看能玩出什麼花招出來。
float[] colorMatrix = new float[] {
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0
};
ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix);
mPaint.setColorFilter(colorMatrixColorFilter);
複製代碼
是否是沒啥變化,由於上面矩陣定義的是白色的矩陣。因此沒啥變化。再來看下面的矩陣會有什麼變化。
float[] colorMatrix = new float[] {
0.33F, 0.59F, 0.11F, 0, 0,
0.33F, 0.59F, 0.11F, 0, 0,
0.33F, 0.59F, 0.11F, 0, 0,
0, 0, 0, 1, 0,
};
ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix);
mPaint.setColorFilter(colorMatrixColorFilter);
ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(TECHNICOLOR);
mPaint.setColorFilter(colorMatrixColorFilter);
複製代碼
是否是發現變灰色了。繼續修改
private static final float[] INVERT = new float[] {
-1, 0, 0, 0, 255,
0, -1, 0, 0, 255,
0, 0, -1, 0, 255,
0, 0, 0, 1, 0,
};
ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(TECHNICOLOR);
mPaint.setColorFilter(colorMatrixColorFilter);
複製代碼
是否是有點想膠捲的的圖像顏色啦😄,繼續修改。
private static final float[] RGB_TO_BGR = new float[] {
0, 0, 1, 0, 0,
0, 1, 0, 0, 0,
1, 0, 0, 0, 0,
0, 0, 0, 1, 0,
};
ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(TECHNICOLOR);
mPaint.setColorFilter(colorMatrixColorFilter);
複製代碼
能夠看到這裏將 RGB 轉爲 BGR 的方式顯示效果。
在看,如何設置稱棕褐色。
private static final float[] SEPIA = new float[] {
0.393F, 0.769F, 0.189F, 0, 0,
0.349F, 0.686F, 0.168F, 0, 0,
0.272F, 0.534F, 0.131F, 0, 0,
0, 0, 0, 1, 0,
};
ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(TECHNICOLOR);
mPaint.setColorFilter(colorMatrixColorFilter);
複製代碼
黑白照片
private static final float[] BLACK_AND_WHITE = new float[] {
1.5F, 1.5F, 1.5F, 0, -255,
1.5F, 1.5F, 1.5F, 0, -255,
1.5F, 1.5F, 1.5F, 0, -255,
0, 0, 0, 1, 0,
};
ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(TECHNICOLOR);
mPaint.setColorFilter(colorMatrixColorFilter);
複製代碼
彩色照片
private static final float[] TECHNICOLOR = new float[] {
1.9125277891456083F, -0.8545344976951645F, -0.09155508482755585F, 0, 11.793603434377337F,
-0.3087833385928097F, 1.7658908555458428F, -0.10601743074722245F, 0, -70.35205161461398F,
-0.231103377548616F, -0.7501899197440212F, 1.847597816108189F, 0, 30.950940869491138F,
0, 0, 0, 1, 0
};
ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(TECHNICOLOR);
mPaint.setColorFilter(colorMatrixColorFilter);
複製代碼
經過不一樣的矩陣,能夠獲得不一樣轉換後的效果。
接下來討論一下濾鏡的原理,安卓系統使用一個顏色矩陣 ColorMatrix(下圖 A 表示) 來處理圖像的顏色,對於每個像素點都有一個顏色份量矩陣來保存的 RGBA 值(下圖 C)。
來看官方文檔的描述 ColorMatrix, 在安卓系統中經過維護一個 4 * 5 的覺得數組來表示。那對一個顏色的運算使用矩陣乘法以下:
// 運算的結果爲 R'G'B'A'
R’ = a*R + b*G + c*B + d*A + e;
G’ = f*R + g*G + h*B + i*A + j;
B’ = k*R + l*G + m*B + n*A + o;
A’ = p*R + q*G + r*B + s*A + t;
複製代碼
這個公式告訴咱們,第一行 abcde 決定紅色,第二行 fghij 決定綠色,第三行 klmno 決定藍色,最後一行 pqrst 決定透明度。
再根據文檔中可看出 reset 方法的顏色矩陣爲:
[ 1 0 0 0 0 - red vector
0 1 0 0 0 - green vector
0 0 1 0 0 - blue vector
0 0 0 1 0 ] - alpha vector
複製代碼
這個顏色也稱爲初始顏色,運用這個顏色矩陣做用在圖片的話,將會保持原來的顏色不變。下面來一個簡單的變化,矩陣取反,其實前面已經看到過效果了。
[ -1 0 0 0 255 - red vector
0 1- 0 0 255 - green vector
0 0 -1 0 255 - blue vector
0 0 0 -1 0 ] - alpha vector
複製代碼
這裏的最後一列,表示的是顏色的偏移量,下面的意思就是紅色和綠色偏移100。
[1,0,0,0,100,
0,1,0,0,100,
0,0,1,0,100,
0,0,0,1,0
]
複製代碼
下面是我寫的一個能夠經過設置參數來調節圖片的顏色過濾,代碼很簡單安卓碎片知識
若是開發中是這樣設置的話,我相信可能會累死。安卓 ColorMatrix 顏色矩陣中封裝了一些 API 來快速調整上面這三個顏色參數,能夠方便的使用。
. 色調
對色彩進行旋轉運算,至於如何旋轉的這個我也沒有研究。感興趣的能夠上網找找資料看看。
// 第一個參數: 0 表示繞紅色的旋轉, 1 表示繞綠色的旋轉, 2表示繞藍色的旋轉
// 至於第二個參數:能夠經過源碼大概能夠知道。它應該在 -180 ~ 180 之間。
colorMatrix.setRotate(0, 180);
colorMatrix.setRotate(1, 180);
colorMatrix.setRotate(2, 180);
複製代碼
/**
* Set the rotation on a color axis by the specified values.
* <p>
* <code>axis=0</code> correspond to a rotation around the RED color
* <code>axis=1</code> correspond to a rotation around the GREEN color
* <code>axis=2</code> correspond to a rotation around the BLUE color
* </p>
*/
public void setRotate(int axis, float degrees) {
reset();
// 週期是在 -180 到 180 之間
double radians = degrees * Math.PI / 180d;
float cosine = (float) Math.cos(radians);
float sine = (float) Math.sin(radians);
switch (axis) {
// Rotation around the red color
case 0:
mArray[6] = mArray[12] = cosine;
mArray[7] = sine;
mArray[11] = -sine;
break;
// Rotation around the green color
case 1:
mArray[0] = mArray[12] = cosine;
mArray[2] = -sine;
mArray[10] = sine;
break;
// Rotation around the blue color
case 2:
mArray[0] = mArray[6] = cosine;
mArray[1] = sine;
mArray[5] = -sine;
break;
default:
throw new RuntimeException();
}
}
複製代碼
. 飽和度 放大色彩飽和度,大於 1 色彩開始飽和,等於 1 不變,小於 1 過分到沒有色彩飽和,等於 0 爲黑白圖像。
colorMatrix1.setSaturation(3.0f);
複製代碼
就是將 RBGA 加上咱們指定的 sat。
/**
* Set the matrix to affect the saturation of colors.
*
* @param sat A value of 0 maps the color to gray-scale. 1 is identity.
*/
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;
}
複製代碼
. 亮度 以不一樣的顏色比列進行混合, 若是所有爲 0 爲黑色。所有爲 1 則爲圖片原有顏色。若是看源碼的話,能夠看到它其實設置的是 a[0],a[6],a[12], a[18] 的值,而後其餘的都置爲0。
colorMatrix1.setScale(0f, 0f, 0f,1.0f);
複製代碼
/**
* Set this colormatrix to scale by the specified values.
*/
public void setScale(float rScale, float gScale, float bScale,
float aScale) {
final float[] a = mArray;
for (int i = 19; i > 0; --i) {
a[i] = 0;
}
a[0] = rScale;
a[6] = gScale;
a[12] = bScale;
a[18] = aScale;
}
複製代碼
好吧! 寫到這兒就結束了。可是 Paint 的尚未說完,剩下的還有跟文字相關的、其餘的圖層混合模式。