android:照片涂画功能实现过程及原理详解

 更新时间:2014年02月19日 14:50:28   作者:  
这篇文章主要介绍了android:照片涂画功能实现过程及原理,需要的朋友可以参考下

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

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

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

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

UI层次简图

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

神奇的Matrix
ImageView控件是常用的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 多线程处理之多线程详解

    本文主要介绍Android 多线程处理的知识资料,这里整理下来详细的知识,和简单代码实现和实现效果图,有需要的朋友可以参考下
    2016-09-09
  • AndroidStudio 设置格式化断行宽度教程

    AndroidStudio 设置格式化断行宽度教程

    这篇文章主要介绍了AndroidStudio 设置格式化断行宽度教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-03-03
  • Android中利用zxing实现自己的二维码扫描识别详解

    Android中利用zxing实现自己的二维码扫描识别详解

    这篇文章主要给大家介绍了关于Android中利用zxing实现自己的二维码扫描识别的相关资料,文中通过图文介绍的非常详细,对大家学习或者使用zxing具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-09-09
  • 使用newInstance()来实例化fragment并传递数据操作

    使用newInstance()来实例化fragment并传递数据操作

    这篇文章主要介绍了使用newInstance()来实例化fragment并传递数据操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • Android开发之WebView组件的使用解析

    Android开发之WebView组件的使用解析

    WebView 类是 WebKit 模块 Java 层的视图类, 所有需要使用 Web 浏览功能的Android应用程序都要创建该视图对象显示和处理请求的网络资源,接下来将详细介绍,需要了解的朋友可以参考下
    2012-12-12
  • 五分了解Android Progress Bar进度条加载

    五分了解Android Progress Bar进度条加载

    这篇文章主要为大家介绍了Android Progress Bar进度条加载的实现及属性示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • Android开启新线程播放背景音乐

    Android开启新线程播放背景音乐

    这篇文章主要为大家详细介绍了Android开启新线程播放背景音乐,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • Android移动应用开发指南之六种布局详解

    Android移动应用开发指南之六种布局详解

    Android应用界面要美观好看,就需要运用到一定的布局技术,Android布局是不可忽视的,是android应用界面开发的重要一环,这篇文章主要给大家介绍了关于Android移动应用开发指南之六种布局的相关资料,需要的朋友可以参考下
    2022-09-09
  • Android 通知的基本用法示例代码

    Android 通知的基本用法示例代码

    本文主要介绍Android 通知栏,这里整理了相关的知识资料,并附示例代码和详解,有需要的小伙伴可以参考下
    2016-08-08
  • Android不使用自定义布局情况下实现自定义通知栏图标的方法

    Android不使用自定义布局情况下实现自定义通知栏图标的方法

    这篇文章主要介绍了Android不使用自定义布局情况下实现自定义通知栏图标的方法,实例分析了Android通知栏图标的创建技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-12-12

最新评论