Xfermodes的扩展应用- 图像擦除和还原效果
2011-10-12 15:53
316 查看
最近在学习Android图形API,看到sdk中demo里的Xfermodes实例,于是结合之前学的做了一个简单的图像擦除和还原的效果,感觉比较好玩,分享下作为TestRoid第一篇^^。
Sdk中自带的例子如图所示,
是几种不同的Xfermodes效果,这些效果很显而易见,无非是一个黄色圆(Dst)和蓝色矩形(Src)的显示。比如SrcOver就是蓝色矩形显示在黄色圆前面;
SrcIn就是两个图形交集显示为Src也就是蓝色矩形的那部分。我主要是用里面的Xor效果来实现这里的例子,PorterDuff.Mode.XOR,即两块非透明区域重叠部分显示为透明。
如果单是做图像擦除的效果也就用不到这个东西咯,所以嘛,重点是在还原的效果。因此这个例子的思路是,建立一块与原图大小相同的mask bitmap,然后在这块mask上进行操作,这样就不会影响原图,这里我用了触摸画线的例子在mask上画点东西,然后通过Xermodes中的XOR模式与原图进行合成,得到我们想要看到的效果。是不是有点Photoshop的味道啦,hoho。
原理图在这,随手画的,呵呵
废话不多说直接上效果图(OK,这个是用模拟器截得,有点卡=.=):
下面是一些代码片段:
初始化mask
view plaincopy to clipboardprint?
private void initBmpMask()
{
if(mImgDesRect
!= null)
{
int w = (int)
mImgDesRect.width();
int h = (int)
mImgDesRect.height();
if(mEraseMaskBitmap
== null)
{
mEraseMaskBitmap
= Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); //初始化一块和显示图片大小相同的bitmap
mEraseMaskBitmap.eraseColor(Color.TRANSPARENT);//设置为透明
}
}
if(mEraseMaskBitmap
!= null)
mCanvas =
new Canvas(mEraseMaskBitmap); //得到要操作的mask
}
复制代码
初始
化画笔样式等:
view plaincopy to clipboardprint?
private void initErasePaint(){
mErasePaint = new Paint();
mErasePaint.setAntiAlias(true);
mErasePaint.setDither(true);
mErasePaint.setColor(0xFF000000);
mErasePaint.setStyle(Paint.Style.STROKE);
mErasePaint.setStrokeJoin(Paint.Join.ROUND);
mErasePaint.setStrokeCap(Paint.Cap.ROUND);
mErasePaint.setStrokeWidth(20);
}
复制代码
响应触屏消息在mask上画图:
view plaincopy to clipboardprint?
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
float x = event.getX() - mImgDesRect.left;
float y = event.getY() - mImgDesRect.top;
switch (action) {
case MotionEvent.ACTION_DOWN:
mErasePath.reset();
mErasePath.moveTo(x, y);
mX = x;
mY = y;
invalidate();
break;
case MotionEvent.ACTION_MOVE:
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mErasePath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
// commit the path to offscreen
mCanvas.drawPath(mErasePath, mErasePaint);
}
invalidate(); //refresh
break;
case MotionEvent.ACTION_UP:
mErasePath.lineTo(mX, mY);
mCanvas.drawPath(mErasePath, mErasePaint);
mErasePath.reset();
invalidate();
break;
}
return true;
}
复制代码
切换擦除(erase)和还原(unerase)功能,只要改变Paint的Xfermode:
view plaincopy to clipboardprint?
public void switchEraseMode(boolean bErase){
if(mErasePaint == null)
initErasePaint();
if(bErase)
mErasePaint.setXfermode(null);
else
mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));//清除样式
}
复制代码
在OnDraw中,把原图和mask通过XOR样式画到canvas上,就可以看到擦除的效果啦:
view plaincopy to clipboardprint?
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mImgBitmap != null)
{
Paint paint = new Paint();
int sc = canvas.saveLayer(mImgDesRect.left, mImgDesRect.top, mImgDesRect.right, mImgDesRect.bottom, 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);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
canvas.drawBitmap(mImgBitmap, new Rect(0, 0, mImgBitmap.getWidth(), mImgBitmap.getHeight()), mImgDesRect, null);
canvas.drawBitmap(mEraseMaskBitmap, new Rect(0, 0, mEraseMaskBitmap.getWidth(), mEraseMaskBitmap.getHeight()), mImgDesRect, paint);
paint.setXfermode(null);
canvas.restoreToCount(sc);
}
}
复制代码
好了,显示上擦除和“反擦”效果就完成了。
例程上传了,可以这里下载:http://download.csdn.net/source/3240693
里面顺便加上了把擦除效果保存下来的,/sdcard/out.png
注:为了视觉效果,例子里加上了一张背景图,让擦除后透明效果明显点。不过保存时这背景图是不会和原图一起保存的。(太懒了。。。)
Sdk中自带的例子如图所示,
是几种不同的Xfermodes效果,这些效果很显而易见,无非是一个黄色圆(Dst)和蓝色矩形(Src)的显示。比如SrcOver就是蓝色矩形显示在黄色圆前面;
SrcIn就是两个图形交集显示为Src也就是蓝色矩形的那部分。我主要是用里面的Xor效果来实现这里的例子,PorterDuff.Mode.XOR,即两块非透明区域重叠部分显示为透明。
如果单是做图像擦除的效果也就用不到这个东西咯,所以嘛,重点是在还原的效果。因此这个例子的思路是,建立一块与原图大小相同的mask bitmap,然后在这块mask上进行操作,这样就不会影响原图,这里我用了触摸画线的例子在mask上画点东西,然后通过Xermodes中的XOR模式与原图进行合成,得到我们想要看到的效果。是不是有点Photoshop的味道啦,hoho。
原理图在这,随手画的,呵呵
废话不多说直接上效果图(OK,这个是用模拟器截得,有点卡=.=):
下面是一些代码片段:
初始化mask
view plaincopy to clipboardprint?
private void initBmpMask()
{
if(mImgDesRect
!= null)
{
int w = (int)
mImgDesRect.width();
int h = (int)
mImgDesRect.height();
if(mEraseMaskBitmap
== null)
{
mEraseMaskBitmap
= Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); //初始化一块和显示图片大小相同的bitmap
mEraseMaskBitmap.eraseColor(Color.TRANSPARENT);//设置为透明
}
}
if(mEraseMaskBitmap
!= null)
mCanvas =
new Canvas(mEraseMaskBitmap); //得到要操作的mask
}
复制代码
初始
化画笔样式等:
view plaincopy to clipboardprint?
private void initErasePaint(){
mErasePaint = new Paint();
mErasePaint.setAntiAlias(true);
mErasePaint.setDither(true);
mErasePaint.setColor(0xFF000000);
mErasePaint.setStyle(Paint.Style.STROKE);
mErasePaint.setStrokeJoin(Paint.Join.ROUND);
mErasePaint.setStrokeCap(Paint.Cap.ROUND);
mErasePaint.setStrokeWidth(20);
}
复制代码
响应触屏消息在mask上画图:
view plaincopy to clipboardprint?
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
float x = event.getX() - mImgDesRect.left;
float y = event.getY() - mImgDesRect.top;
switch (action) {
case MotionEvent.ACTION_DOWN:
mErasePath.reset();
mErasePath.moveTo(x, y);
mX = x;
mY = y;
invalidate();
break;
case MotionEvent.ACTION_MOVE:
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mErasePath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
// commit the path to offscreen
mCanvas.drawPath(mErasePath, mErasePaint);
}
invalidate(); //refresh
break;
case MotionEvent.ACTION_UP:
mErasePath.lineTo(mX, mY);
mCanvas.drawPath(mErasePath, mErasePaint);
mErasePath.reset();
invalidate();
break;
}
return true;
}
复制代码
切换擦除(erase)和还原(unerase)功能,只要改变Paint的Xfermode:
view plaincopy to clipboardprint?
public void switchEraseMode(boolean bErase){
if(mErasePaint == null)
initErasePaint();
if(bErase)
mErasePaint.setXfermode(null);
else
mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));//清除样式
}
复制代码
在OnDraw中,把原图和mask通过XOR样式画到canvas上,就可以看到擦除的效果啦:
view plaincopy to clipboardprint?
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mImgBitmap != null)
{
Paint paint = new Paint();
int sc = canvas.saveLayer(mImgDesRect.left, mImgDesRect.top, mImgDesRect.right, mImgDesRect.bottom, 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);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
canvas.drawBitmap(mImgBitmap, new Rect(0, 0, mImgBitmap.getWidth(), mImgBitmap.getHeight()), mImgDesRect, null);
canvas.drawBitmap(mEraseMaskBitmap, new Rect(0, 0, mEraseMaskBitmap.getWidth(), mEraseMaskBitmap.getHeight()), mImgDesRect, paint);
paint.setXfermode(null);
canvas.restoreToCount(sc);
}
}
复制代码
好了,显示上擦除和“反擦”效果就完成了。
例程上传了,可以这里下载:http://download.csdn.net/source/3240693
里面顺便加上了把擦除效果保存下来的,/sdcard/out.png
注:为了视觉效果,例子里加上了一张背景图,让擦除后透明效果明显点。不过保存时这背景图是不会和原图一起保存的。(太懒了。。。)
相关文章推荐
- (转载)Xfermodes的扩展应用- 图像擦除和还原效果
- Xfermodes的扩展应用- 图像擦除和还原效果
- 将CSS CLIP属性应用在:扩展覆盖效果
- 将CSS CLIP属性应用在:扩展覆盖效果
- 图像滤波函数imfilter函数的应用及其扩展
- 使用Equalizer扩展Ogre应用的画面效果展示
- iOS 8出色的跨应用通信效果:解读Action扩展
- vs2013在图像处理中的应用(7):开发Python扩展
- 将CSS CLIP属性应用在:扩展覆盖效果
- 将CSS CLIP属性应用在:扩展覆盖效果
- 将CSS CLIP属性应用在:扩展覆盖效果
- CSS基础应用学习系列(3)——图像的CSS阴影效果
- PorterDuffXfermode 图像混合技术在漫画APP中的应用
- 无插件纯web 3D机房 (第四季:大型园区、地球仪效果和其他扩展应用)
- Symbian学习笔记(4):在GUI应用中使用图像
- jQuery通过扩展实现抖动效果的方法
- 【opencv+python】图像处理之二、几何变换(仿射与投影)的应用
- 【python】还原二进制图像(可视化):mnist,cifar10,cifar100
- 提升Android应用视觉效果的10个UI设计技巧
- 图像处理之像素格效果