拉伸无锯齿的SVG图片

2023-11-03

package com.moonlight.example;

import com.larvalabs.svgandroid.SVG;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Bitmap.Config;
import android.graphics.Paint.Style;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;

import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * @ClassName: SVGView
 * @Description: Scalable Vector Graphics M = moveto 相当于 android Path 里的moveTo(),用于移动起始点 L = lineto
 *               相当于 android Path 里的lineTo(),用于画线 H = horizontal lineto 用于画水平线 V = vertical lineto
 *               用于画竖直线 C = curveto 相当于cubicTo(),三次贝塞尔曲线 S = smooth curveto 同样三次贝塞尔曲线,更平滑 Q =
 *               quadratic Belzier curve quadTo(),二次贝塞尔曲线 T = smooth quadratic Belzier curveto
 *               同样二次贝塞尔曲线,更平滑 A = elliptical Arc 相当于arcTo(),用于画弧 Z = closepath 相当于closeTo(),关闭path
 * @author: moonlight
 * @date: 2016-9-19 下午4:06:15
 */
public class SVGView extends View {
	public static final String TAG = "SVGView";
	private Drawable sp_close, sp_scale, sp_flip;
	private RectF dstRect;
	private Paint paint_region;
	private TouchHelper touchHelper;
	private SVG svg;
	private Bitmap svgBitmap;
	private RectF srcRect;
	private float[] srcPts = new float[8];
	private float[] dstPts = new float[8];
	//用于svg的bitmap做旋转
	private Matrix svgMatrix = new Matrix();
	private Matrix rectMatrix = new Matrix();
	private ISVGAction svgAction;
	private float degreeTotal, flip = 1f;
	float[] values = new float[9];

	public SVGView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}
	public SVGView(Context context) {
		super(context);
		init(context);
	}
	public void init(Context context) {
		sp_close = getResources().getDrawable(R.drawable.sp_close);
		sp_scale = getResources().getDrawable(R.drawable.sp_scale);
		sp_flip = getResources().getDrawable(R.drawable.sp_flip);
		dstRect = new RectF();
		srcRect = new RectF();
		paint_region = new Paint();
		paint_region.setColor(Color.BLACK);
		paint_region.setStyle(Style.STROKE);
		touchHelper = new TouchHelper();
	}
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		if (svg != null && svgBitmap == null) {
			int svg_w = svg.getPicture().getWidth();
			int svg_h = svg.getPicture().getHeight();
			int w_valid = w - sp_close.getIntrinsicWidth();
			int h_valid = h - sp_close.getIntrinsicHeight();
			if (svg_w > (w_valid) || svg_h > (h_valid)) {
				float scale_w = 1.0f * svg_w / w_valid;
				float scale_h = 1.0f * svg_h / h_valid;
				float scale = Math.max(scale_w, scale_h);
				svg_w /= scale;
				svg_h /= scale;
			}
			srcRect = new RectF(0, 0, svg_w, svg_h);
			srcPts[0] = srcRect.left;
			srcPts[1] = srcRect.top;
			srcPts[2] = srcRect.right;
			srcPts[3] = srcRect.top;
			srcPts[4] = srcRect.right;
			srcPts[5] = srcRect.bottom;
			srcPts[6] = srcRect.left;
			srcPts[7] = srcRect.bottom;
			rectMatrix.postTranslate(w / 2f - srcRect.centerX(), h / 2f - srcRect.centerY());
			touchHelper.lastDegree = (float) Math.toDegrees(Math.atan2(svg_h, svg_w));
			rectMatrix.mapRect(dstRect, srcRect);
			rectMatrix.mapPoints(dstPts, srcPts);
			changeSVGBitmap();
		}
	}
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		return touchHelper.onTouchEvent(event);
	}
	public void setSVG(SVG svg) {
		this.svg = svg;
		//可能View还没有初始化
		if (getWidth() != 0 && getHeight() != 0) {
			changeSVGBitmap();
		}
	}

	public enum RegionAction {
		MOVE, CLOSE, FINISH, SCALE, FLIP, NONE;
	}

	public RegionAction judgeRegionAction(MotionEvent event) {
		int x = (int) event.getX();
		int y = (int) event.getY();
		//先判断四个控制点在判断移动区域
		if (sp_scale.getBounds().contains(x, y)) {
			return RegionAction.SCALE;
		}
		if (sp_close.getBounds().contains(x, y)) {
			return RegionAction.CLOSE;
		}
		if (sp_flip.getBounds().contains(x, y)) {
			return RegionAction.FLIP;
		}
		Matrix inverse = new Matrix();
		rectMatrix.invert(inverse);
		float[] pt = new float[] { x, y };
		inverse.mapPoints(pt);
		if (srcRect.contains(pt[0], pt[1])) {
			return RegionAction.MOVE;
		}
		return RegionAction.FINISH;
	}

	public class TouchHelper {
		private float lastX, lastY;
		private RegionAction actionRegion;
		private float lastDegree;

		public boolean onTouchEvent(MotionEvent event) {
			switch (event.getActionMasked()) {
				case MotionEvent.ACTION_DOWN:
					lastX = event.getX();
					lastY = event.getY();
					actionRegion = judgeRegionAction(event);
					break;
				case MotionEvent.ACTION_MOVE: {
					switch (actionRegion) {
						case MOVE: {
							float dx = (event.getX() - lastX);
							float dy = (event.getY() - lastY);
							regionMove(dx, dy);
							lastX = event.getX();
							lastY = event.getY();
							invalidate();
							break;
						}
						case SCALE: {
							regionScale(event);
							regionRotate(event);
							changeSVGBitmap();
							lastX = event.getX();
							lastY = event.getY();
							invalidate();
							break;
						}
						default:
							break;
					}
				}
					break;
				case MotionEvent.ACTION_UP:
					RegionAction actionRegionDown = judgeRegionAction(event);
					actionRegion = actionRegionDown == actionRegion ? actionRegionDown : RegionAction.NONE;
					switch (actionRegion) {
						case CLOSE:
							closeAction();
							break;
						case FINISH:
							finishAction();
							break;
						case FLIP:
							flipAction();
							invalidate();
							break;
						default:
							break;
					}
					break;
				default:
					break;
			}
			return true;
		}
		public void regionMove(float dx, float dy) {
			//if (dx < 0 && dstRect.left + dx < 0) {
			//	dx = -dstRect.left;
			//} else if (dx > 0 && dstRect.right + dx > getWidth()) {
			//	dx = getWidth() - (dstRect.right);
			//}
			//if (dy < 0 && dstRect.top + dy < 0) {
			//	dy = -dstRect.top;
			//} else if (dy > 0 && dstRect.bottom + dy > getHeight()) {
			//	dy = getHeight() - (dstRect.bottom);
			//}
			rectMatrix.postTranslate(dx, dy);
		}
		public void regionRotate(MotionEvent event) {
			float degree = (float) Math.toDegrees(Math.atan2(event.getY() - dstRect.centerY(),
					event.getX() - dstRect.centerX()));
			float degreeChange = degree - lastDegree;
			degreeTotal = (degreeTotal + degreeChange) % 360;
			rectMatrix.postRotate(degreeChange, dstRect.centerX(), dstRect.centerY());
			lastDegree = degree;
		}
		//基于中心点放缩
		public void regionScale(MotionEvent event) {
			float centerX = dstRect.centerX();
			float centerY = dstRect.centerY();
			float scale = (float) (Math.sqrt((event.getY() - centerY) * ((event.getY() - centerY))
					+ (event.getX() - centerX) * (event.getX() - centerX)) / Math.sqrt((lastY - centerY)
					* ((lastY - centerY)) + (lastX - centerX) * (lastX - centerX)));
			rectMatrix.postScale(scale, scale, centerX, centerY);
			svgMatrix.postScale(scale, scale);
		}
		public void finishAction() {
			if (svgAction != null) {
				svgAction.done(svgBitmap, new Rect((int) dstRect.left, (int) dstRect.top, (int) dstRect.right,
						(int) dstRect.bottom));
			}
		}
		public void closeAction() {
			if (svgAction != null) {
				svgAction.close();
			}
		}
		private void flipAction() {
			flip *= -1;
			//这个会变换坐标系,将x的方向翻转
			changeSVGBitmap();
		}
	}

	public void setSVGAction(ISVGAction action) {
		this.svgAction = action;
	}

	public interface ISVGAction {
		public void close();
		public void done(Bitmap bitmap, Rect postion);
	}

	//思路:先绘制未旋转的bmp,在去中心点做旋转操作
	public void changeSVGBitmap() {
		//变换前获得最终效果dstRect
		rectMatrix.mapRect(dstRect, srcRect);
		RectF svgRect, svgNoRotateRect;
		svgRect = new RectF(0, 0, (int) dstRect.width(), (int) dstRect.height());
		svgNoRotateRect = new RectF();
		svgMatrix.mapRect(svgNoRotateRect, srcRect);
		if (svgBitmap == null || (svgBitmap.getWidth() != svgRect.width() || svgBitmap.getHeight() != svgRect.height())) {
			if (svgBitmap != null)
				svgBitmap.recycle();
			svgBitmap = Bitmap.createBitmap((int) svgRect.width(), (int) svgRect.height(), Config.ARGB_4444);
		}
		//对canvas先做旋转,翻转,再做位移,注意顺序:位移最后做
		Canvas c = new Canvas(svgBitmap);
		c.drawColor(Color.TRANSPARENT, Mode.CLEAR);
		c.rotate(degreeTotal, svgRect.centerX(), svgRect.centerY());
		c.scale(flip, 1, svgRect.centerX(), svgRect.centerY());
		c.translate((svgRect.width() - svgNoRotateRect.width()) / 2f, (svgRect.height() - svgNoRotateRect.height()) / 2);
		//对svgNoRotateRect只做位移变换
		//Matrix m = new Matrix();
		//m.postTranslate((svgRect.width() - svgNoRotateRect.width()) / 2f,	(svgRect.height() - svgNoRotateRect.height()) / 2);
		//m.mapRect(svgNoRotateRect);
		c.drawPicture(svg.getPicture(), svgNoRotateRect);
	}
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		if (svgBitmap != null) {
			rectMatrix.mapRect(dstRect, srcRect);
			rectMatrix.mapPoints(dstPts, srcPts);
			drawFrame(canvas);
			canvas.drawBitmap(svgBitmap, dstRect.centerX() - svgBitmap.getWidth() / 2f,
					dstRect.centerY() - svgBitmap.getHeight() / 2f, null);
			drawControlBtns(canvas);
		}
	}
	private void drawControlBtns(Canvas canvas) {
		setBoundsByCenterXY(sp_close, dstPts[0], dstPts[1]);
		sp_close.draw(canvas);
		setBoundsByCenterXY(sp_flip, dstPts[2], dstPts[3]);
		sp_flip.draw(canvas);
		setBoundsByCenterXY(sp_scale, dstPts[4], dstPts[5]);
		sp_scale.draw(canvas);
	}
	private void drawFrame(Canvas canvas) {
		canvas.drawLine(dstPts[0], dstPts[1], dstPts[2], dstPts[3], paint_region);
		canvas.drawLine(dstPts[2], dstPts[3], dstPts[4], dstPts[5], paint_region);
		canvas.drawLine(dstPts[4], dstPts[5], dstPts[6], dstPts[7], paint_region);
		canvas.drawLine(dstPts[6], dstPts[7], dstPts[0], dstPts[1], paint_region);
	}
	private void setBoundsByCenterXY(Drawable drawable, float centerX, float centerY) {
		drawable.setBounds((int) centerX - drawable.getIntrinsicWidth() / 2,
				(int) centerY - drawable.getIntrinsicHeight() / 2, (int) centerX + drawable.getIntrinsicWidth() / 2,
				(int) centerY + drawable.getIntrinsicHeight() / 2);
	}
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

拉伸无锯齿的SVG图片 的相关文章

随机推荐