ImageEditor库详解—————StickerView详解

来源:互联网 发布:可以打电话的软件 编辑:程序博客网 时间:2024/06/16 19:23

ImageEditorLibrary是安卓中一款图形编辑的开源控件,支持自定义贴图,图片滤镜,图片旋转以及图片裁剪的操作,正好由于最近项目中也需要使用到一些这样的功能,最近就将这个库中的一些代码进行分析一下。
首先作者的项目地址如下:
https://github.com/siwangqishiq/ImageEditor-Android
今儿就来分析下他其中核心部件之一的StickerView及StickerItem的内容。首先介绍一下这两个类实现的功能:通过这两个类可以实现添加多张图片,并提供对这其中的每张图片进行缩放,旋转及移动的功能,具体的功能可以通过下图有个大致的了解:
这里写图片描述
从图中就可以看出可以添加好几张图片,所以就需要对每张图片进行一下封装处理,这就促成了StickerItem的生成,同时,我们又能看到这个图片的外边框带有四个功能键,所以这就需要我们在这个item中将这几个功能图标给画出来,画的画就是canvas的drawbitmap方法了,没什么好说的,主要的还是这几行功能图的位置,所以我们定义了几个矩形:

public RectF desRectF;//内容区域public RectF deleteRectF;//删除public RectF rotateRectF;//旋转public RectF editRectF;//编辑public RectF scaleRectF;//缩放public RectF helpBoxRectF;//辅助线

通过这些矩阵,对于接下来的需要操作的图片平移,缩放以及旋转还是很好操作的,对于平移操作,就只需要传入x和y的偏移量dx,dy:

 //位置移动    public void updatePos(float dx,float dy){        matrix.postTranslate(dx,dy);        desRectF.offset(dx,dy);        helpBoxRectF.offset(dx,dy);        deleteRectF.offset(dx,dy);        editRectF.offset(dx,dy);        scaleRectF.offset(dx,dy);        rotateRectF.offset(dx,dy);        deleteRealRect.offset(dx,dy);        editRealRect.offset(dx,dy);        scaleRealRect.offset(dx,dy);        rotateRealRect.offset(dx,dy);    }

之后关于缩放,就需要计算一下缩放比,其中需要使用到以前学过的三角函数的知识:

float c_x=desRectF.centerX();float c_y=desRectF.centerY();float x=scaleRealRect.centerX();float y=scaleRealRect.centerY();float n_x=x+dx;float n_y=y+dy;float xa=x-c_x;float ya=y-c_y;float xb=n_x-c_x;float yb=n_y-c_y;float srcLen= (float) Math.sqrt(xa*xa+ya*ya);float curLen= (float) Math.sqrt(xb*xb+yb*yb);float scale = curLen/srcLen;

其中scaleRealRect只图形的右下角缩放按钮的位置矩形,计算出缩放比就可以比较容易的进行缩放操作,矩形的话就是它们的各边乘上改缩放比,其中他的写法中需要注意的一点是我们需要在额外写四个矩阵一记录这四个按钮的真实坐标,具体原因后面他在进行旋转绘制的时候是将整个画布进行了旋转的操作,所以如果还是拿原始的矩形坐标会出现问题。
对于之后的旋转操作,需要注意的是其中计算旋转角度的固定公式:

 double cos = (xa * xb + ya * yb) / (srcLen * curLen); if (cos > 1 || cos < -1)     return; float angle = (float) Math.toDegrees(Math.acos(cos)); // 定理 float calMatrix = xa * yb - xb * ya;// 行列式计算 确定转动方向 int flag = calMatrix > 0 ? 1 : -1; angle = flag * angle;

之后对这些矩形进行相应的旋转操作,主要还是用到三角函数来计算,具体的方式可以自己去推导一下:

 float x = rect.centerX(); float y = rect.centerY(); float sinA = (float) Math.sin(Math.toRadians(roatetAngle)); float cosA = (float) Math.cos(Math.toRadians(roatetAngle)); float newX = center_x + (x - center_x) * cosA - (y - center_y) * sinA; float newY = center_y + (y - center_y) * cosA + (x - center_x) * sinA; float dx = newX - x; float dy = newY - y; rect.offset(dx, dy);

至此,图形的缩放,旋转和平移的功能都已写完,之后就是处理何时调用这些相应的方法了,这就是StickerView的作用了,就是重写它的onTouchEvent方法,并在其中对我们所接触的点坐标与那四个功能按钮坐标的比较了,其中主要的一个方法就是矩形RectF具有一个contains(float x,float y)方法用来判断该点是否在这个矩形范围之内,让后就是在对应的范围内进行对应的操作就可以了。
突然这么回顾一下,发现这个功能也不是特别的繁琐嘛,其实对看个几遍代码也就能搞懂了他的操作逻辑,需要注意的是他库中提供出来的将缩放和旋转集中到了一起去了,而我们的项目需要把这两个功能分开,所以以上内容其实是按照我改了一点逻辑后来总结的。