Android 编辑图片 Canvas画图,涂鸦,马赛克等(三)
需求功能详解
单纯的编辑图片的功能,能够在界面上进行图形的绘制,线条的涂鸦,和画马赛克的绘制,并且有撤销的功能。
画马赛克
相对于涂鸦和画图形,马赛克的绘制可能会比较复杂,但是明白了马赛克的绘制原理之后,他与涂鸦也并无二致,下面让我们来揭开马赛克绘制的神秘面纱!
Paint Xfermode
在画马赛克之前,先要大概了解下Android 画笔Paint
的Xfermode
,那么什么是Xfermode,Xfermode国外有大神称之为过渡模式,这种翻译比较贴切但恐怕不易理解,大家也可以直接称之为图像混合模式,因为所谓的“过渡”其实就是图像混合的一种。查看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图解
这张图片从一定程度上形象地说明了图形混合的作用,两个图形一圆一方通过一定的计算产生不同的组合效果,在API中Android为我们提供了18种(比上图多了两种ADD和OVERLAY)模式。
我们的马赛克效果,就是用这种图像混合的方式来实现的~
实现思路
实现的思路很简单,首先我们要获得一张基于原图的马赛克图像,然后做类似涂鸦功能的操作,最后再将图像组合起来,就能得到最终的马赛克路径了!
- 获得马赛克位图
如何获得马赛克位图呢,只要使用Bitmap自带的创建缩放图的API,并且使其不保真缩放,就能得到一张马赛克位图啦:
生成马赛克图
关键代码
/**
* 获取马赛克的bitmap
*/
private Bitmap makeMosaicBitmap() {
if (mMoasicBitmap != null) {
return mMoasicBitmap;
}
int w = Math.round(mViewWidth / 16f);
int h = Math.round(mViewHeight / 16f);
if (mOriginBitmap != null) {
// 先创建小图
mMoasicBitmap = Bitmap.createScaledBitmap(mOriginBitmap, w, h, false);
// 再把小图放大
mMoasicBitmap = Bitmap.createScaledBitmap(mMoasicBitmap, mViewWidth, mViewHeight, false);
}
return mMoasicBitmap;
}
接下来,就是我们的重头戏了,使用我们上面介绍的Xfermode,将图像组合起来,就能得到如下图的效果:
关键代码
首先创建设置了Xfermode的马赛克专用画笔:
mMosaicPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mMosaicPaint.setFilterBitmap(false);
mMosaicPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
然后根据涂鸦的路径,合并图层,就得到了马赛克效果:
/**
* 画马赛克内容
*/
private void drawMosaicPath(Canvas canvas) {
if (mMosaicPath.size() > 0 && mMoasicBitmap != null) {
// 保存图层
int layerCount = canvas.saveLayer(0, 0, mViewWidth, mViewHeight, null, Canvas.ALL_SAVE_FLAG);
for (DrawPathBean mosaicPath : mMosaicPath) {
canvas.drawPath(mosaicPath.path, mosaicPath.paint);
}
// 进行图层的合并
canvas.drawBitmap(mMoasicBitmap, 0, 0, mMosaicPaint);
canvas.restoreToCount(layerCount);
}
}
总结
至此,马赛克的绘制也结束了,其他操作也不再赘述,和第一篇的涂鸦功能可以说是一模一样的,除了最后在onDraw()
中的绘制,多了图层的绘制合并。最后多谢看到这里的看官~
参考
Android Paint Xfermode 学习小结
Android 图片编辑的原理与实现——涂鸦与马赛克
前篇
Android 编辑图片 Canvas画图,涂鸦,马赛克等(一)
Android 编辑图片 Canvas画图,涂鸦,马赛克等(二)
项目代码
最后奉上完整的项目代码,欢迎clone和star和意见提交:
https://github.com/wx9265661/SmallDemos2