这个功能可以帮你实现,在图片上进行随意的涂抹,可以用于SNS产品。

绘图本身很简单,但是要实现在图片上指定的部分精确(位置,缩放)的绘图,就有点麻烦了。

下面讲讲实现过程及原理:

UI构图这个UI,看似简单,还是有点复杂的,下面需要一个底图,上面再来一个透明的图片控件,画图的时候要同步两个控件的变形。

UI层次简图

为什么,需要上面一个Canvas Image与Back保持一致?因为,Canvas Image会被画到Canvas上,它是Canvas的宿主,即ImageView被变成了一块画布,原来ImageView上的内容会被擦除。如果只有Back Image那么一旦开启画布,你什么也看不到。

神奇的MatrixImageView控件是常用的Android控件之一,主要用于图片展示。基本上所有的高级语言中,都有类似控件。但是,有一样东西让他化腐朽为神奇,那就是Matrix。有了Matrix我们就可以实现图片平移、放大、旋转、扭曲等常用的特效。Matrix本身是一个9*9的矩阵,里面存放的是平移坐标、放大系数、sin/cos角度值。我们可以通过getMatrix()来获取一个IV的矩阵,或者通过setMatrix()来设置它的值。

上面的东西拿来有什么用?试想一下,当我们打开相册,查看一张照片的时候,可以通过触摸,平移或者放大图片。我们,要在上面绘图,先把Canvas Image 变为Canvas,但是,Canvas Image没有经过变化。必须,至少确保两个Img控件拥有相同的变形,否则无法对齐画的坐标点。这个时候,要么当Back Image变的时候,Canvas Image立即同步操作,要么,最画到canvas上的时候,同步变形。前一种方案是没有必要的,果断使用后一种。这个时候你就要问,怎么得到IV的变形参数?IV提供了一些方法来单独的获取和设置某种变形,当时折腾了很久,不但繁琐,而且达不到效果。这时候,上面的Matrix就派上用场了。当时,可没人这么愉快的告诉我这个。

坐标映射上面完成了图形的变换,现在终于可以再上面作画了。但是一画,你就会发现一个问题,画不到指定位置上。这是什么问题呢?坐标系偏移。(0,0)点默认为屏幕的左上角。但是,想一下当我们的图片不满一个屏幕,很小的时候,Canvas的坐标系在什么位置?我在屏幕(0,0)坐标画一个点,canvas上就会出现一个点,即使两者的位置相差很远。

这个时候,我们需要将两个坐标系进行映射,通过偏移对齐坐标系。偏移多少?这时候该使用矩阵的translate值了。这样我们就可以知道图片在坐标系上的偏移了,随边你怎么移动坐标都能准确对齐。

private HashMap getImageViewIneerSize(ImageView iv){

HashMap size=new HashMap();

//获得ImageView中Image的变换矩阵

Matrix m = iv.getImageMatrix();

float[] values = new float[10];

m.getValues(values);

//Image在绘制过程中的变换矩阵,从中获得x和y方向的缩放系数

float sx = values[0];

float sy = values[4];

//计算Image在屏幕上实际绘制的宽高

size.put("scaleX",  1/sx);

size.put("scaleY",  1/sy);

size.put("offsetX", values[2]); //X轴的translate的值

size.put("offsetY",values[5]);

return size;

}

其中width=backImage.getDrawable().getBounds().width();

你会发现有个scaleX,这是干什么的?我们假设现在图片经过缩放后的宽度恰好等于屏幕宽度,图片的实际宽度是960px。但是我们在X=480px的地方画一个点,这个点应该显示在图片的什么地方呢?我们的意图是要在图片的最后面,即X=960px的地方画一个点,但是现在却跑到了480处,明显不满足要求。这时,就需要乘上上面的scaleX了。

画线的最终代码:

/*根据两点坐标,绘制连线

*startX、stopX 为触摸事件开始、结束的地方

*offsetX,为图片在X轴的位移值

*scaleX,为图片在X轴的缩放值的倒数

*/

if((startY-offsetY)>=0&&(stopY-offsetY)>=0)

canvas.drawLine((startX-offsetX)*scaleX, (startY-offsetY)*scaleY, (stopX-offsetX)*scaleX, (stopY-offsetY)*scaleY, pen);

【注】

ImageView的实际大小等于屏幕的大小,Canvas的实际大小由图片实际大小决定。

ImageView的宽高很容易取得,但是它里面的图片是变过形的,怎么获取它的当前大小呢?用(原始大小*缩放系数)。

合并最后一步就是将两个图层合并为一张图片。参考代码如下:

/**

* 合并两张bitmap为一张

* @param background

* @param foreground

* @return Bitmap

*/

public static Bitmap combineBitmap(Bitmap background, Bitmap foreground) {

if (background == null) {

return null;

}

int bgWidth = background.getWidth();

int bgHeight = background.getHeight();

int fgWidth = foreground.getWidth();

int fgHeight = foreground.getHeight();

Bitmap newmap = Bitmap.createBitmap(bgWidth, bgHeight, Config.ARGB_8888);

Canvas canvas = new Canvas(newmap);

canvas.drawBitmap(background, 0, 0, null);

canvas.drawBitmap(foreground, (bgWidth - fgWidth) / 2,

(bgHeight - fgHeight) / 2, null);

canvas.save(Canvas.ALL_SAVE_FLAG);

canvas.restore();

return newmap;

} //end of combineBitmap

通过Canvas来合并和改变Bitmap的大小,由于两个图层的大小、位置完全一致,故坐标对齐(0,0)点就可以了。

如果,没有前面的工作,你是很难精确的进行图片合并的。

android照片涂抹功能,android:照片涂画功能实现过程及原理详解相关推荐

  1. html+js+canvas实现画板涂画功能和vue+canvas实现画板涂画功能

    1,html+js+canvas实现画板涂画功能 效果如下: <!DOCTYPE HTML> <html> <head><meta charset=" ...

  2. Android涂鸦画板原理详解——从初级到高级(二)

    前言 前面写了<Android涂鸦画板原理详解--从初级到高级(一)>,讲了涂鸦原理初级和中级的应用,现在讲解高级应用.如果没有看过前面一篇文章的同学,建议先去看看哈. 准备 高级涂鸦涉及 ...

  3. 【Android架构师java原理详解】二;反射原理及动态代理模式

    前言: 本篇为Android架构师java原理专题二:反射原理及动态代理模式 大公司面试都要求我们有扎实的Java语言基础.而很多Android开发朋友这一块并不是很熟练,甚至半路初级底子很薄,这给我 ...

  4. Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(下)

       本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning 上篇文章<<Android中measure过程.WRAP_CONTENT详解以及xml布局文 ...

  5. Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验

    Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高 ...

  6. 【胖虎的逆向之路】02——Android整体加壳原理详解实现

    [胖虎的逆向之路](02)--Android整体加壳原理详解&实现 Android Apk的加壳原理流程及详解 文章目录 [胖虎的逆向之路](02)--Android整体加壳原理详解& ...

  7. android禁止下拉刷新,Android开发之无痕过渡下拉刷新控件的实现思路详解

    相信大家已经对下拉刷新熟悉得不能再熟悉了,市面上的下拉刷新琳琅满目,然而有很多在我看来略有缺陷,接下来我将说明一下存在的缺陷问题,然后提供一种思路来解决这一缺陷,废话不多说!往下看嘞! 1.市面一些下 ...

  8. Android基础入门教程——8.3.5 Paint API之—— Xfermode与PorterDuff详解(二)

    Android基础入门教程--8.3.5 Paint API之-- Xfermode与PorterDuff详解(二) 标签(空格分隔): Android基础入门教程 本节引言: 上一节,我们学习了Xf ...

  9. Android面试Hash原理详解二

    Hash系列目录 Android面试Hash原理详解一 Android面试Hash原理详解二 Android面试Hash常见算法 Android面试Hash算法案例 Android面试Hash原理详解 ...

最新文章

  1. Nginx源码分析:惊群处理与负载均衡
  2. android异常(2)
  3. 概率编程库Pymc3案例之神经网络
  4. 几何画板自定义工具_用好神奇的数学工具--几何画板,轻松作出复杂的几何图形...
  5. c#开发-基础知识及有用技巧(一)
  6. caffe学习笔记教程
  7. Centos 5 手动安装yum
  8. shell学习笔记 (9.1)
  9. Windows Server 2003成员服务器基准用户权限分配策略
  10. BLUES吉他学习笔记007 bluesrv[11]
  11. 国产操作系统Deepin的安装
  12. MTK6762 Helio P22 安卓核心板模块应用
  13. 数据分析基础——数据规整
  14. http请求时返回的304是干什么的
  15. 五洲20国政商代表团到访全球蜂集团
  16. 华米手表2 是android,手表 | 续航怪兽 华米AMAZFIT智能运动手表2代深度评测(二)...
  17. 西游记中孙悟空为什么总是欺负捉弄嘲笑猪八戒?
  18. 七彩虹colorful SL500 360G开卡(量产)rts5732dl教程+量产工具
  19. ug10后处理安装步骤 ug后处理论坛网 ug后处理在什么位置 ug后处理报警大全 ug法兰克后处理下载 ug后处理器如何设置 ug三轴后处理制作教程 法兰克ug后处理文件 ug后处理构造器
  20. linux ps w,Linux监控命令—who,w,ps

热门文章

  1. 龙蜥社区技术委员会主席杨勇:下一代操作系统展望
  2. ios 模拟器沙盒_查看iOS模拟器应用的沙箱文件
  3. STM32F103C8T6使用RTC实现日历读取、设置和输出
  4. 学习笔记二:IBIS模型编辑报错纠正
  5. Codeforces 1106F Lunar New Year and a Recursive Sequence 矩阵快速幂,原根转化模意义下对数,BSGS
  6. android-帧动画(原地不动人再走路)
  7. 酒店无线产品认证靠谱吗
  8. 微博实时话题和搜索微博实时抓取
  9. python if main_python if __name__ == 'main' 的作用和原理()
  10. EPUB转为PDF和书籍pdf下载