影象混合模式:Android Paint Xfermode 使用和demo
一、setXfermode(Xfermode xfermode)
Xfermode國外有大神稱之為過渡模式,這種翻譯比較貼切但恐怕不易理解,大家也可以直接稱之為影象混合模式,因為所謂的“過渡”其實就是影象混合的一種,這個方法跟我們上面講到的setColorFilter蠻相似的。檢視API文件發現其果然有三個子類:AvoidXfermode, PixelXorXfermode和PorterDuffXfermode,這三個子類實現的功能要比setColorFilter的三個子類複雜得多。
由於AvoidXfermode, PixelXorXfermode都已經被標註為過時了,所以這次主要研究的是仍然在使用的PorterDuffXfermode:
二、PorterDuffXfermode
該類同樣有且只有一個含參的構造方法PorterDuffXfermode(PorterDuff.Mode mode),雖說構造方法的簽名列表裡只有一個PorterDuff.Mode的引數,但是它可以實現很多酷斃的圖形效果!!而PorterDuffXfermode就是圖形混合模式的意思,其概念最早來自於SIGGRAPH的Tomas Proter和Tom Duff,混合圖形的概念極大地推動了圖形影象學的發展,延伸到計算機圖形影象學像Adobe和AutoDesk公司著名的多款設計軟體都可以說一定程度上受到影響,而我們PorterDuffXfermode的名字也來源於這倆人的人名組合PorterDuff,那PorterDuffXfermode能做些什麼呢?我們先來看一張API DEMO裡的圖片:
這張圖片從一定程度上形象地說明了圖形混合的作用,兩個圖形一圓一方通過一定的計算產生不同的組合效果,在API中Android為我們提供了18種(比上圖多了兩種ADD和OVERLAY)模式:
ADD:飽和相加,對影象飽和度進行相加,不常用
CLEAR:清除影象
DARKEN:變暗,較深的顏色覆蓋較淺的顏色,若兩者深淺程度相同則混合
DST:只顯示目標影象
DST_ATOP:在源影象和目標影象相交的地方繪製【目標影象】,在不相交的地方繪製【源影象】,相交處的效果受到源影象和目標影象alpha的影響
DST_IN:只在源影象和目標影象相交的地方繪製【目標影象】,繪製效果受到源影象對應地方透明度影響
DST_OUT:只在源影象和目標影象不相交的地方繪製【目標影象】,在相交的地方根據源影象的alpha進行過濾,源影象完全不透明則完全過濾,完全透明則不過濾
DST_OVER:將目標影象放在源影象上方
LIGHTEN:變亮,與DARKEN相反,DARKEN和LIGHTEN生成的影象結果與Android對顏色值深淺的定義有關
MULTIPLY:正片疊底,源影象素顏色值乘以目標影象素顏色值除以255得到混合後圖像畫素顏色值
OVERLAY:疊加
SCREEN:濾色,色調均和,保留兩個圖層中較白的部分,較暗的部分被遮蓋
SRC:只顯示源影象
SRC_ATOP:在源影象和目標影象相交的地方繪製【源影象】,在不相交的地方繪製【目標影象】,相交處的效果受到源影象和目標影象alpha的影響
SRC_IN:只在源影象和目標影象相交的地方繪製【源影象】
SRC_OUT:只在源影象和目標影象不相交的地方繪製【源影象】,相交的地方根據目標影象的對應地方的alpha進行過濾,目標影象完全不透明則完全過濾,完全透明則不過濾
SRC_OVER:將源影象放在目標影象上方
XOR:在源影象和目標影象相交的地方之外繪製它們,在相交的地方受到對應alpha和色值影響,如果完全不透明則相交處完全不繪製
public class sampleActivity extends AppCompatActivity {
// create a bitmap with a circle, used for the "dst" image
static Bitmap makeDst(int w, int h) {
Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bm);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(0xFFFFCC44);
c.drawOval(new RectF(0, 0, w*3/4, h*3/4), p);
return bm;
}
// create a bitmap with a rect, used for the "src" image
static Bitmap makeSrc(int w, int h) {
Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bm);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(0xFF66AAFF);
c.drawRect(w/3, h/3, w*19/20, h*19/20, p);
return bm;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SampleView(this));
}
private static class SampleView extends View {
private static final int W = 200;
private static final int H = 200;
private static final int ROW_MAX = 4; // number of samples per row
private Bitmap mSrcB;
private Bitmap mDstB;
private Shader mBG; // background checker-board pattern
private static final Xfermode[] sModes = {
new PorterDuffXfermode(PorterDuff.Mode.CLEAR),
new PorterDuffXfermode(PorterDuff.Mode.SRC),
new PorterDuffXfermode(PorterDuff.Mode.DST),
new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),
new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),
new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),
new PorterDuffXfermode(PorterDuff.Mode.DST_IN),
new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),
new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),
new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),
new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),
new PorterDuffXfermode(PorterDuff.Mode.XOR),
new PorterDuffXfermode(PorterDuff.Mode.DARKEN),
new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),
new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),
new PorterDuffXfermode(PorterDuff.Mode.SCREEN)
};
private static final String[] sLabels = {
"Clear", "Src", "Dst", "SrcOver",
"DstOver", "SrcIn", "DstIn", "SrcOut",
"DstOut", "SrcATop", "DstATop", "Xor",
"Darken", "Lighten", "Multiply", "Screen"
};
public SampleView(Context context) {
super(context);
mSrcB = makeSrc(W, H);
mDstB = makeDst(W, H);
// make a ckeckerboard pattern
Bitmap bm = Bitmap.createBitmap(new int[] { 0xFFFFFFFF, 0xFFCCCCCC,
0xFFCCCCCC, 0xFFFFFFFF }, 2, 2,
Bitmap.Config.RGB_565);
mBG = new BitmapShader(bm,
Shader.TileMode.REPEAT,
Shader.TileMode.REPEAT);
Matrix m = new Matrix();
m.setScale(6, 6);
mBG.setLocalMatrix(m);
}
@Override protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG);
labelP.setTextAlign(Paint.Align.CENTER);
Paint paint = new Paint();
paint.setFilterBitmap(false);
canvas.translate(15, 35);
int x = 0;
int y = 0;
for (int i = 0; i < sModes.length; i++) {
// draw the border
paint.setStyle(Paint.Style.STROKE);
paint.setShader(null);
canvas.drawRect(x - 0.5f, y - 0.5f,
x + W + 0.5f, y + H + 0.5f, paint);
// draw the checker-board pattern
paint.setStyle(Paint.Style.FILL);
paint.setShader(mBG);
canvas.drawRect(x, y, x + W, y + H, paint);
// draw the src/dst example into our offscreen bitmap
int sc = canvas.saveLayer(x, y, x + W, y + H, null,
Canvas.MATRIX_SAVE_FLAG |
Canvas.CLIP_SAVE_FLAG |
Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
Canvas.CLIP_TO_LAYER_SAVE_FLAG);
canvas.translate(x, y);
canvas.drawBitmap(mDstB, 0, 0, paint);
paint.setXfermode(sModes[i]);
canvas.drawBitmap(mSrcB, 0, 0, paint);
paint.setXfermode(null);
canvas.restoreToCount(sc);
// draw the label
canvas.drawText(sLabels[i],
x + W/2, y - labelP.getTextSize()/2, labelP);
x += W + 10;
// wrap around when we've drawn enough for one row
if ((i % ROW_MAX) == ROW_MAX - 1) {
x = 0;
y += H + 30;
}
}
}
}
}
對於上面這些mode的詳細介紹在GA_STUDIO的這篇文章和AIGESTUDIO的這篇文章都有非常詳盡的介紹
三、使用場景
以下是PorterDuffXfermode的一些使用場景:
1、自定義loading樣式:
程式碼如下:
public class LogoLoadingView extends View {
private int totalW,totalH;
private Paint paint;
private Bitmap bitmap;
private int currentTop;
private RectF rectF;
private PorterDuffXfermode xfermode;
public LogoLoadingView(Context context) {
super(context);
init();
}
public LogoLoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init(){
paint=new Paint();
paint.setAntiAlias(true);//設定抗鋸齒
paint.setStyle(Paint.Style.FILL);//設定填充樣式
paint.setDither(true);//設定是否使用影象抖動處理,會使繪製出來的圖片顏色更加平滑和飽滿,影象更加清晰
paint.setFilterBitmap(true);//加快顯示速度,本設定項依賴於dither和xfermode的設定
bitmap= BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);//從資原始檔中解析獲取Bitmap
xfermode=new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
/**
* 設定當前矩形的高度為0
*/
currentTop=bitmap.getHeight();
rectF=new RectF(0,currentTop,bitmap.getWidth(),bitmap.getHeight());
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(bitmap.getWidth(),bitmap.getHeight());
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
rectF.top=currentTop;
/**
* 設定View的離屏緩衝。在繪圖的時候新建一個“層”,所有的操作都在該層而不會影響該層以外的影象
* 必須設定,否則設定的PorterDuffXfermode會無效,具體原因不明
*/
int sc=canvas.saveLayer(0,0,totalW,totalH,paint,Canvas.ALL_SAVE_FLAG);
canvas.drawBitmap(bitmap,0,0,null);
paint.setXfermode(xfermode);
paint.setColor(Color.RED);
canvas.drawRect(rectF,paint);
paint.setXfermode(null);
/**
* 還原畫布,與canvas.saveLayer配套使用
*/
canvas.restoreToCount(sc);
if (currentTop>0){
currentTop--;
postInvalidate();
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
totalW=w;
totalH=h;
}
}
2、圓形圖片
程式碼如下:
public class CircleImageView extends View {
private int resId;
private Bitmap bitmap;
private Paint paint;
private int bitmapWidth,bitmapHeight;
private int size;
private PorterDuffXfermode xfermode;
public CircleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
resId=array.getResourceId(R.styleable.CircleImageView_imageRes,R.mipmap.ic_launcher);
array.recycle();
init();
}
private void init(){
paint=new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setDither(true);//設定是否使用影象抖動處理,會使繪製出來的圖片顏色更加平滑和飽滿,影象更加清晰
paint.setFilterBitmap(true);//加快顯示速度,本設定項依賴於dither和xfermode的設定
bitmap= BitmapFactory.decodeResource(getResources(),resId);
bitmapWidth=bitmap.getWidth();
bitmapHeight=bitmap.getHeight();
xfermode=new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP);
size=Math.min(bitmapWidth,bitmapHeight);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(size,size);
}
/**
* 生成圓形Bitmap
* @return
*/
private Bitmap makeCircle(){
Bitmap bitmap=Bitmap.createBitmap(size,size, Bitmap.Config.ARGB_8888);
Canvas canvas=new Canvas(bitmap);
Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.FILL);
int radius=size/2;
canvas.drawCircle(size/2,size/2,radius,paint);
return bitmap;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int sc=canvas.saveLayer(0,0,size,size,paint,Canvas.ALL_SAVE_FLAG);
Bitmap dst=makeCircle();
canvas.drawBitmap(dst,0,0,paint);
paint.setXfermode(xfermode);
canvas.drawBitmap(bitmap,0,0,paint);
paint.setXfermode(null);
canvas.restoreToCount(sc);
}
}
對應屬性定義:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircleImageView">
<attr name="imageRes" format="reference"/>
</declare-styleable>
</resources>
關於圓形圖片的詳細介紹可以看鴻洋大大的這篇博文,介紹的非常詳盡:
http://blog.csdn.net/lmj623565791/article/details/42094215
關於PorterDuffXfermode的應用還有非常多,這裡簡單介紹這幾個。
以上內容大部分參考自:
http://blog.csdn.net/tianjian4592/article/details/44783283 //詳解Xfermode
http://blog.csdn.net/aigestudio/article/details/41316141 //把api玩出了ps的效果,圖片處理大牛
http://www.cnblogs.com/tianzhijiexian/p/4297172.html //也是詳解
相關推薦
影象混合模式:Android Paint Xfermode 使用和demo
一、setXfermode(Xfermode xfermode) Xfermode國外有大神稱之為過渡模式,這種翻譯比較貼切但恐怕不易理解,大家也可以直接稱之為影象混合模式,因為所謂的“過渡”其實就是影象混合的一種,這個方法跟我們上面講到的setColorFilter蠻相似
Android Paint Xfermode 學習小結
一、setXfermode(Xfermode xfermode) Xfermode國外有大神稱之為過渡模式,這種翻譯比較貼切但恐怕不易理解,大家也可以直接稱之為影象混合模式,因為所謂的“過渡”其實就是影象混合的一種,這個方法跟我們上面講到的setColorFilter蠻相似的。檢視API文件發現其果然有三個子
畢業設計之android混合模式開發第一天--具有下拉重新整理和頁面載入等待的WebView搭建
第一次真正接觸android的混合模式開發,之前瞭解過如何進行混合模式的開發,常見的是通過WebView元件載入url,使用HTML5和CSS3構建手機端響應式佈局。 今天主要是搭建出一個可載入url,具有下拉重新整理和頁面等待的WebView。 2.頁面等待的實現主要是
VS2017下OpenCV 64位配置和ROI區域影象疊加&初級影象混合
VS2017配置 VS2017下載社群版地址:https://visualstudio.microsoft.com/zh-hans/downloads/ OpenCV下載地址:https://opencv.org/releases.html 設定包含目錄和庫目錄,我的OpenCV版本
Hybrid APP混合模式應用開發的經驗和總結
寫在前面: 由於業務需要,接觸到一個Hybrid APP混合開發的專案。當時是第一次接觸混合開發,有一些經驗和總結,歡迎各位一起交流學習~ 1、混合開發概述 Hybrid App主要以JS+Native兩者相互呼叫為主,從
影象處理、計算機視覺與模式識別“SCI期刊和頂級會議”總結
期刊: best (1) IEEE Transactions on Pattern Analysis and Machine Intelligence,IEEE模式分析與機器智慧彙刊,簡稱PAMI,是IEEE最重要的學術性彙刊之一。 (2) ACM Trans
【Android】startService和bindService混合使用總結
先自定義一個service: public class MyService extends Service { private Service startService; private Service bindService; @Nullable
Android Canvas類和Paint類(草稿版)
Canvas物件中可以繪製: 1) drawArc():繪製圓弧; 2) drawBitmap():繪製Bitmap影象; 3) drawCircle():繪製圓圈; 4) drawLine():繪製線條; 5) drawOval():繪製橢圓; 6) drawPath():繪
初學Android,圖形影象之使用Canvas,Paint繪圖(二十五
下面是一個畫各種圖形的例子,具體的畫圖方法不用特別解釋,看API就可以了先定義一個繼承自View的類DrawViewpackage WangLi.Graphics.MyView;import android.content.Context;import android.grap
網頁設計靈感:影象遮罩、混合模式、交錯排版
在這個資訊爆炸的時代,人們已然被大量、快速並且簡短的資訊所包圍。然而,我們相信:過多“快餐”式的閱讀只會令人“虛胖”,缺乏實質的內涵。伯樂線上內容團隊正試圖以我們微薄的力量,把優秀的原創文章和譯文分享給讀者,為“快餐”新增一些“營養”元素。
Android中Activity的啟動模式(LaunchMode)和使用場景
一、為什麼需要啟動模式 在Android開發中,我們都知道,在預設的情況下,如果我們啟動的是同一個Activity的話,系統會建立多個例項並把它們一一放入任務棧中。當我們點選返回(back)鍵,這些Activity例項又將從任務棧中一一移除,遵循的原則是“
android原生程式碼中的情景模式及提示音和通知
如下介紹的是5.1平臺中的設定應用中的情景模式及提示音和通知 設定的介面: 對應的java類:com.android.settings.SettingsActivity 對應的xml檔案:xml/d
android 中 Canvas和Paint
相關連結: ---------------正文---------------- Canvas類主要實現了螢幕的繪製過程,其中包含了很多實用的方法,比如繪製一條路徑、區域、貼圖、畫點、畫線、渲染文字,下面是Canvas類常用的方法: void drawRect(RectF rect, Pai
Android靈魂畫家的18種混合模式
⚠️️ Warning!Warning!前方高能,閱讀本文可能需要3分鐘哦! 有什麼料? 重新認識神祕的PorterDuffXfermode。 學會正確的使用PorterDuffXfermode。 收穫【兩張示例圖】,幫助你在實際中正確的運用各種混合模
Android 連線Wifi和建立Wifi熱點 demo
android的熱點功能不可見,用了反射的技術搞定之外。 Eclipse設定語言為utf-8才能檢視中文註釋 上程式碼: MainActivity.java package com.widget.hotspot; import android.os.Bundle; im
淺談Android開發中的MVVM模式及與MVP和MVC的區別
三種架構模式的演化: 什麼是MVVM? MVVM是Model-View-ViewModel的簡寫。微軟的WPF帶來了新的技術體驗,如Silverlight、音訊、視訊、3D、動畫……,這導致了軟體UI層更加細節化、可定製化。同時,在技術層面,WPF也帶來
Android App的三種架構模式MVC,MVP和MVVM
http://www.2cto.com/kf/201506/405766.html MVC使用總結 利用MVC設計模式,使得這個天氣預報小專案有了很好的可擴充套件和維護性,當需要改變UI顯示的時候,無需修改Contronller(控制器)Activity的程式
Android Launcher分析和修改13——實現Launcher編輯模式(1) 桌布更換
已經很久沒更新Launcher系列文章,今天不分析原始碼,講講如何在Launcher裡面新增桌面設定的功能。目前很多第三方Launcher或者定製Rom都有簡單易用的桌面設定功能。例如小米MIUI的Launcher就有很豐富編輯功能。今天開始會講一下如何實現桌面編輯功能。網上對於實現Launcher一些編
研究Android技術,以及和Android相關的任何盈利模式
索引: 1.fieldset,legend 具體解釋: 1.fieldset: fieldset是一個不常用的HTML標籤,很有意思,其語法如下:html 程式碼 <fieldset> <legend>fieldset名稱</lege
Android高階進階——繪圖篇(五)setXfermode 設定混合模式
一、GPU硬體加速 1、概述 GPU英文全稱Graphic Processing Unit,中文翻譯為“圖形處理器”。與CPU不同,GPU是專門為處理圖形任務而產生的晶片。 在GPU出現之前,CPU一直負責著所有的運算工作,CPU的架構是有利於X86