Android之matrix类控制图片的旋转、缩放、移动
在Android中,对图片的处理需要使用到Matrix类,Matrix是一个3 x 3的矩阵,他对图片的处理分为四个基本类型:
1、Translate————平移变换
2、Scale————缩放变换
3、Rotate————旋转变换
4、Skew————错切变换
在Android的API里对于每一种变换都提供了三种操作方式:set(用于设置Matrix中的值)、post(后乘,根据矩阵的原理,相当于左乘)、pre(先乘,相当于矩阵中的右乘)。默认时,这四种变换都是围绕(0,0)点变换的,当然可以自定义围绕的中心点,通常围绕中心点。
首先说说平移,在对图片处理的过程中,最常用的就是对图片进行平移操作,该方法为setTranslate(),平移意味着在x轴和y轴上简单地移动图像。setTranslate方法采用两个浮点数作为参数,表示在每个轴上移动的数量。第一个参数是图像将在x轴上移动的数量,而第二个参数是图像将在y轴上移动的数量。在x轴上使用正数进行平移将向右移动图像,而使用负数将向左移动图像。在y轴上使用正数进行平移将向下移动图像,而使用负数将向上移动图像。
再看缩放,Matrix类中另一个有用的方法是setScale方法。它采用两个浮点数作为参数,分别表示在每个轴上所产生的缩放量。第一个参数是x轴的缩放比例,而第二个参数是y轴的缩放比例。如:matrix.setScale(1.5f,1);
比较复杂的就是图片的旋转了,内置的方法之一是setRotate方法。它采用一个浮点数表示旋转的角度。围绕默认点(0,0),正数将顺时针旋转图像,而负数将逆时针旋转图像,其中默认点是图像的左上角,如:
Matrix matrix = new Matrix();
matrix.setRotate(15);
另外,也可以使用旋转的角度及围绕的旋转点作为参数调用setRotate方法。选择图像的中心点作为旋转点,如:
matrix.setRotate(15,bmp.getWidth()/2,bmp.getHeight()/2);
对于错切变换,在数学上又称为Shear mapping(可译为“剪切变换”)或者Transvection(缩并),它是一种比较特殊的线性变换。错切变换的效果就是让所有点的x坐标(或者y坐标)保持不变,而对应的y坐标(或者x坐标)则按比例发生平移,且平移的大小和该点到x轴(或y轴)的垂直距离成正比。错切变换,属于等面积变换,即一个形状在错切变换的前后,其面积是相等的。
对于程序中,一个特别有用的方法对是setScale和postTranslate,它们允许跨单个轴(或者两个轴)翻转图像。如果以一个负数缩放,那么会将该图像绘制到坐标系统的负值空间。由于(0,0)点位于左上角,使用x轴上的负数会导致向左绘制图像。因此我们需要使用postTranslate方法,将图像向右移动,如:
matrix.setScale(-1, 1);
matrix.postTranslate(bmp.getWidth(),0);
可以在y轴上做同样的事情,翻转图像以使其倒置。通过将图像围绕两个轴上的中心点旋转180°,可以实现相同的效果,如
matrix.setScale(1, -1);
matrix.postTranslate(0, bmp.getHeight());
下面是对Android中利用matrix 控制图片的旋转、缩放、移动进行了详细的分析介绍,需要的朋友参考下
本文主要讲解利用android中Matrix控制图形的旋转缩放移动
/** * 使用矩阵控制图片移动、缩放、旋转 */ public class CommonImgEffectView extends View { private Context context ; private Bitmap mainBmp , controlBmp ; private int mainBmpWidth , mainBmpHeight , controlBmpWidth , controlBmpHeight ; private Matrix matrix ; private float [] srcPs , dstPs ; private RectF srcRect , dstRect ; private Paint paint ,paintRect , paintFrame; private float deltaX = 0, deltaY = 0; //位移值 private float scaleValue = 1; //缩放值 private Point lastPoint ; private Point prePivot , lastPivot; private float preDegree , lastDegree ; private short currentSelectedPointindex; //当前操作点击点 private Point symmetricPoint = new Point(); //当前操作点对称点 /** * 图片操作类型 */ public static final int OPER_DEFAULT = -1; //默认 public static final int OPER_TRANSLATE = 0; //移动 public static final int OPER_SCALE = 1; //缩放 public static final int OPER_ROTATE = 2; //旋转 public static final int OPER_SELECTED = 3; //选择 public int lastOper = OPER_DEFAULT; /* 图片控制点 * 0---1---2 * | | * 7 8 3 * | | * 6---5---4 */ public static final int CTR_NONE = -1; public static final int CTR_LEFT_TOP = 0; public static final int CTR_MID_TOP = 1; public static final int CTR_RIGHT_TOP = 2; public static final int CTR_RIGHT_MID = 3; public static final int CTR_RIGHT_BOTTOM = 4; public static final int CTR_MID_BOTTOM = 5; public static final int CTR_LEFT_BOTTOM = 6; public static final int CTR_LEFT_MID = 7; public static final int CTR_MID_MID = 8; public int current_ctr = CTR_NONE; public CommonImgEffectView(Context context){ super(context); this.context = context ; } public CommonImgEffectView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context ; initData(); } /** * 初始化数据 * @author 张进 */ private void initData(){ mainBmp = BitmapFactory.decodeResource(this.context.getResources(), R.drawable.flower); controlBmp = BitmapFactory.decodeResource(this.context.getResources(), R.drawable.control); mainBmpWidth = mainBmp.getWidth(); mainBmpHeight = mainBmp.getHeight(); controlBmpWidth = controlBmp.getWidth(); controlBmpHeight = controlBmp.getHeight(); srcPs = new float[]{ 0,0, mainBmpWidth/2,0, mainBmpWidth,0, mainBmpWidth,mainBmpHeight/2, mainBmpWidth,mainBmpHeight, mainBmpWidth/2,mainBmpHeight, 0,mainBmpHeight, 0,mainBmpHeight/2, mainBmpWidth/2,mainBmpHeight/2 }; dstPs = srcPs.clone(); srcRect = new RectF(0, 0, mainBmpWidth, mainBmpHeight); dstRect = new RectF(); matrix = new Matrix(); prePivot = new Point(mainBmpWidth/2, mainBmpHeight/2); lastPivot = new Point(mainBmpWidth/2, mainBmpHeight/2); lastPoint = new Point(0,0); paint = new Paint(); paintRect = new Paint(); paintRect.setColor(Color.RED); paintRect.setAlpha(100); paintRect.setAntiAlias(true); paintFrame = new Paint(); paintFrame.setColor(Color.GREEN); paintFrame.setAntiAlias(true); setMatrix(OPER_DEFAULT); } /** * 矩阵变换,达到图形平移的目的 * @author 张进 */ private void setMatrix(int operationType){ switch (operationType) { case OPER_TRANSLATE: matrix.postTranslate(deltaX , deltaY); break; case OPER_SCALE: matrix.postScale(scaleValue, scaleValue, symmetricPoint.x, symmetricPoint.y); break; case OPER_ROTATE: matrix.postRotate(preDegree - lastDegree, dstPs[CTR_MID_MID * 2], dstPs[CTR_MID_MID * 2 + 1]); break; } matrix.mapPoints(dstPs, srcPs); matrix.mapRect(dstRect, srcRect); } private boolean isOnPic(int x , int y){ if(dstRect.contains(x, y)){ return true; }else return false; } private int getOperationType(MotionEvent event){ int evX = (int)event.getX(); int evY = (int)event.getY(); int curOper = lastOper; switch(event.getAction()) { case MotionEvent.ACTION_DOWN: current_ctr = isOnCP(evX, evY); Log.i("img", "current_ctr is "+current_ctr); if(current_ctr != CTR_NONE || isOnPic(evX, evY)){ curOper = OPER_SELECTED; } break; case MotionEvent.ACTION_MOVE: if(current_ctr > CTR_NONE && current_ctr < CTR_MID_MID ){ curOper = OPER_SCALE; }else if(current_ctr == CTR_MID_MID ){ curOper = OPER_ROTATE; }else if(lastOper == OPER_SELECTED){ curOper = OPER_TRANSLATE; } break; case MotionEvent.ACTION_UP: curOper = OPER_SELECTED; break; default: break; } Log.d("img", "curOper is "+curOper); return curOper; } /** * 判断点所在的控制点 * @param evX * @param evY * @return */ private int isOnCP(int evx, int evy) { Rect rect = new Rect(evx-controlBmpWidth/2,evy-controlBmpHeight/2,evx+controlBmpWidth/2,evy+controlBmpHeight/2); int res = 0 ; for (int i = 0; i < dstPs.length; i+=2) { if(rect.contains((int)dstPs[i], (int)dstPs[i+1])){ return res ; } ++res ; } return CTR_NONE; } @Override public boolean dispatchTouchEvent(MotionEvent event) { int evX = (int)event.getX(); int evY = (int)event.getY(); int operType = OPER_DEFAULT; operType = getOperationType(event); switch (operType) { case OPER_TRANSLATE: translate(evX, evY); break; case OPER_SCALE: scale(event); break; case OPER_ROTATE: rotate(event); break; } lastPoint.x = evX; lastPoint.y = evY; lastOper = operType; invalidate();//重绘 return true; } /** * 移动 * @param evx * @param evy * @author zhang_jin1 */ private void translate(int evx , int evy){ prePivot.x += evx - lastPoint.x; prePivot.y += evy -lastPoint.y; deltaX = prePivot.x - lastPivot.x; deltaY = prePivot.y - lastPivot.y; lastPivot.x = prePivot.x; lastPivot.y = prePivot.y; setMatrix(OPER_TRANSLATE); //设置矩阵 } /** * 缩放 * 0---1---2 * | | * 7 8 3 * | | * 6---5---4 * @param evX * @param evY */ private void scale(MotionEvent event) { int pointIndex = current_ctr*2 ; float px = dstPs[pointIndex]; float py = dstPs[pointIndex+1]; float evx = event.getX(); float evy = event.getY(); float oppositeX = 0 ; float oppositeY = 0 ; if(current_ctr<4 && current_ctr >= 0){ oppositeX = dstPs[pointIndex+8]; oppositeY = dstPs[pointIndex+9]; }else if(current_ctr >= 4){ oppositeX = dstPs[pointIndex-8]; oppositeY = dstPs[pointIndex-7]; } float temp1 = getDistanceOfTwoPoints(px,py,oppositeX,oppositeY); float temp2 = getDistanceOfTwoPoints(evx,evy,oppositeX,oppositeY); this.scaleValue = temp2 / temp1 ; symmetricPoint.x = (int) oppositeX; symmetricPoint.y = (int)oppositeY; Log.i("img", "scaleValue is "+scaleValue); setMatrix(OPER_SCALE); } /** * 旋转图片 * 0---1---2 * | | * 7 8 3 * | | * 6---5---4 * @param evX * @param evY */ private void rotate(MotionEvent event) { if(event.getPointerCount() == 2){ preDegree = computeDegree(new Point((int)event.getX(0), (int)event.getY(0)), new Point((int)event.getX(1), (int)event.getY(1))); }else{ preDegree = computeDegree(new Point((int)event.getX(), (int)event.getY()), new Point((int)dstPs[16], (int)dstPs[17])); } setMatrix(OPER_ROTATE); lastDegree = preDegree; } /** * 计算两点与垂直方向夹角 * @param p1 * @param p2 * @return */ public float computeDegree(Point p1, Point p2){ float tran_x = p1.x - p2.x; float tran_y = p1.y - p2.y; float degree = 0.0f; float angle = (float)(Math.asin(tran_x/Math.sqrt(tran_x*tran_x + tran_y* tran_y))*180/Math.PI); if(!Float.isNaN(angle)){ if(tran_x >= 0 && tran_y <= 0){//第一象限 degree = angle; }else if(tran_x <= 0 && tran_y <= 0){//第二象限 degree = angle; }else if(tran_x <= 0 && tran_y >= 0){//第三象限 degree = -180 - angle; }else if(tran_x >= 0 && tran_y >= 0){//第四象限 degree = 180 - angle; } } return degree; } /** * 计算两个点之间的距离 * @param p1 * @param p2 * @return */ private float getDistanceOfTwoPoints(Point p1, Point p2){ return (float)(Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y))); } private float getDistanceOfTwoPoints(float x1,float y1,float x2,float y2){ return (float)(Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))); } @Override public void onDraw(Canvas canvas){ drawBackground(canvas);//绘制背景,以便测试矩形的映射 canvas.drawBitmap(mainBmp, matrix, paint);//绘制主图片 drawFrame(canvas);//绘制边框,以便测试点的映射 drawControlPoints(canvas);//绘制控制点图片 } private void drawBackground(Canvas canvas){ canvas.drawRect(dstRect, paintRect); } private void drawFrame(Canvas canvas){ canvas.drawLine(dstPs[0], dstPs[1], dstPs[4], dstPs[5], paintFrame); canvas.drawLine(dstPs[4], dstPs[5], dstPs[8], dstPs[9], paintFrame); canvas.drawLine(dstPs[8], dstPs[9], dstPs[12], dstPs[13], paintFrame); canvas.drawLine(dstPs[0], dstPs[1], dstPs[12], dstPs[13], paintFrame); canvas.drawPoint(dstPs[16], dstPs[17], paintFrame); } private void drawControlPoints(Canvas canvas){ for (int i = 0; i < dstPs.length; i+=2) { canvas.drawBitmap(controlBmp, dstPs[i]-controlBmpWidth/2, dstPs[i+1]-controlBmpHeight/2, paint); } } }Demo效果:
更多相关文章
- Android(安卓)matrix 控制图片的旋转、缩放、移动
- Android异步加载图像小结 (含线程池,缓存方法)
- android WebView 图片缩放功能小结
- android camera(一):camera模组CMM介绍
- android从服务器下载文件(php+apache+win7+MySql)
- android camera(一):camera模组CMM介绍
- android图像处理系统1.3
- android使用inSampleSize、inScaled、inDensity、inTargetDensit
- Android(安卓)webview记住账号密码