涂鸦,Canvas绘图

    公司的项目里有一个功能是,用户有个涂鸦签字的功能,需要再白色面板上涂鸦,然后上传到又拍云,把又拍云返回的图片url通过post请求上传到服务器。摸索了一段时间,完成了这个功能,并且实现的不错。下面贴出截图跟部分demo:

       

上传到又拍云的那部分demo就不贴了,涉及到很多图片url定义规则还有项目隐私的东西,只贴到 保存图片到本地的,后面上传图片就是很简单啦!

1.自定义的ImageTextView.class

<span style="font-size:14px;">public class ImageEditTextView extends EditText {

        private Paint mPaint;
        private Rect mRect;
        private Context mContext;

        public ImageEditTextView(Context context) {
                super(context);

                mContext = context;

        }


        public ImageEditTextView(Context context, AttributeSet attrs, int defStyle) {

                super(context, attrs, defStyle);
                // TODO Auto-generated constructor stub
                mPaint = new Paint();
                mPaint.setStyle(Paint.Style.STROKE);
                mPaint.setColor(Color.BLACK);

                mContext = context;

        }
        public ImageEditTextView(Context context, AttributeSet attrs) {
                super(context, attrs);
                // TODO Auto-generated constructor stub

                mPaint = new Paint();
                mPaint.setStyle(Paint.Style.STROKE);
                mPaint.setColor(Color.BLUE);


                mContext = context;
        }





        @Override
        protected void onLayout(boolean changed, int left, int top, int right,
                                int bottom) {
                System.out.println("left:"+left+".top:"+top+".right:"+right+".bottom:"+bottom);
                super.onLayout(changed, left, top, right, bottom);
        }


        @Override
        protected void onDraw(Canvas canvas) {
                // TODO Auto-generated method stub
                super.onDraw(canvas);
                WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
                int windowWidth = wm.getDefaultDisplay().getWidth();
                int windowHeight = wm.getDefaultDisplay().getHeight();

                Paint paint = new Paint();
                paint.setStyle(Paint.Style.FILL);
                paint.setColor(Color.BLACK);
                paint.setColor(Color.WHITE);

                int paddingTop    = getPaddingTop();
                int paddingBottom = getPaddingBottom();

                int scrollY       = getScrollY();  		//
                int scrollX       = getScrollX()+windowWidth;
                int innerHeight   = scrollY + getHeight() - paddingTop - paddingBottom;
                int lineHeight    = getLineHeight();
                int baseLine      = scrollY + (lineHeight - (scrollY % lineHeight));
                int x = 8;
                while (baseLine < innerHeight) {
                        //canvas.drawBitmap(line, x, baseLine + paddingTop, paint);

                        canvas.drawLine(x, baseLine + paddingTop,scrollX, baseLine + paddingTop, paint);
                        baseLine += lineHeight;
                }
        }
	
	
}</span>
2.自定义 HandTouchView.class

public class HandTouchView extends View {
	public Handler mbitmaphHandler;
	public Handler getMbitmaphHandler() {
		return mbitmaphHandler;
	}
	public void setMbitmaphHandler(Handler mbitmaphHandler) {
		this.mbitmaphHandler = mbitmaphHandler;
	}

	private DisplayMetrics dm;
	private Bitmap bitmap=null;
	private Bitmap mBitmap=null;
	private Bitmap myBitmap ;
	private Paint mPaint=null;
	private Canvas mCanvas=null;
	private Paint mBitmapPaint=null;
	private Timer timer=null;
	private savePath sPath;
	private List<savePath> lists =null;
	private FingerMatrix fingerMatrix=null;
	private float Xi,Yi;
	private Path path=null;
	public HandTouchView(Context context) {
		super(context);
		dm = new DisplayMetrics();
		((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
		inter(dm.widthPixels, dm.heightPixels);

	}

	public HandTouchView(Context context, AttributeSet attrs) {
		super(context, attrs);
		dm = new DisplayMetrics();
		((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
		inter(dm.widthPixels, dm.heightPixels);


	}

	public HandTouchView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		dm = new DisplayMetrics();
		((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
		inter(dm.widthPixels, dm.heightPixels);


	}

	/**
	 * 初始化
	 * @param w
	 * @param h
	 */
	public void inter(int w,int h){
		mBitmap =Bitmap.createBitmap(w, h, Config.ARGB_8888);
		mCanvas = new Canvas(mBitmap);
		mBitmapPaint = new Paint(Paint.DITHER_FLAG);
		path = new Path();
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
		mPaint.setStyle(Paint.Style.STROKE);
		mPaint.setStrokeJoin(Paint.Join.ROUND);// 设置外边缘
		mPaint.setStrokeCap(Paint.Cap.SQUARE);// 形状
		mPaint.setStrokeWidth(15);// 画笔宽度
		mPaint.setColor(FingerMatrix.colorValue);
		lists = new ArrayList<HandTouchView.savePath>();
		fingerMatrix = new FingerMatrix();
		timer = new Timer(true);				//定时器来截取字
	}

	public void minter(int w,int h){
		mBitmap =Bitmap.createBitmap(w, h, Config.ARGB_8888);
		mCanvas = new Canvas(mBitmap);
		mBitmapPaint = new Paint(Paint.DITHER_FLAG);
		path = new Path();
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
		mPaint.setStyle(Paint.Style.STROKE);
		mPaint.setStrokeJoin(Paint.Join.ROUND);// 设置外边缘
		mPaint.setStrokeCap(Paint.Cap.SQUARE);// 形状
		mPaint.setStrokeWidth(15);// 画笔宽度
		mPaint.setColor(FingerMatrix.colorValue);
		lists = new ArrayList<HandTouchView.savePath>();
		fingerMatrix = new FingerMatrix();
		timer = new Timer(true);
	}

	public void RefreshPaint(){
		path = new Path();
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
		mPaint.setStyle(Paint.Style.STROKE);
		mPaint.setStrokeJoin(Paint.Join.ROUND);// 设置外边缘
		mPaint.setStrokeCap(Paint.Cap.SQUARE);// 形 状
		mPaint.setStrokeWidth(15);// 画笔宽度
		mPaint.setColor(Color.BLACK);
	}

	protected void onDraw(Canvas canvas) {
		// 设置canvas画布背景为白色
		canvas.drawColor(Color.WHITE);
		canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
		if (path!=null) {
			canvas.drawPath(path, mPaint);
		}
		super.onDraw(canvas);
	}


	/**
	 * 手指 移动事件
	 */
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:			//按下屏幕时
				mPaint.setColor(FingerMatrix.colorValue);
				float x = event.getX();
				float y = event.getY();
				if (task!=null) {			//如果等于空
					task.cancel();			//关闭定时器将原任务从队列中移除
					task = new TimerTask() {
						public void run() {
							Message message = new Message();
							message.what = 1;
							handler.sendMessage(message);		//发给handler
						}
					};
				}
				//Log.i("线程", "触屏时的坐标"+x+"y坐标"+y);
				if (fingerMatrix==null) {
					fingerMatrix = new FingerMatrix();
					//Log.i("线程", "<staRT>fingerMatrix等于空");
					fingerMatrix.init(x, y);
				}else {
					fingerMatrix.getx(x);
					//Log.i("线程", "<等于空>fingerMatrix等于空");
					fingerMatrix.getY(y);
				}
				path = new Path();
				sPath =new savePath();
				sPath.paint = mPaint;		//保存路径
				sPath.path = path;
				path.moveTo(x, y);			//开始划线
				Xi = x;
				Yi = y;
				invalidate();			//刷新
				break;
			case MotionEvent.ACTION_MOVE:			//移动中
				float X1 = event.getX();
				float Y1 = event.getY();
				if (task!=null) {
					task.cancel();
					task = new TimerTask() {
						public void run() {
							Message message = new Message();
							message.what=1;
							handler.sendMessage(message);
						}
					};

				}
				if (fingerMatrix!=null) {
					fingerMatrix.getx(X1);
					fingerMatrix.getY(Y1);
					//Log.i("线程", "fingerMatrix不等于空");
				}
				float j = Math.abs(X1-Xi);
				float i = Math.abs(Yi-Y1);
				if (j>=5||i>=5) {
					path.quadTo(Xi, Yi, X1, Y1);
					Xi = X1;
					Yi = Y1;
				}
				invalidate();
				break;
			case MotionEvent.ACTION_UP:			//手指松下离开屏幕时
				//一旦有在屏幕按下抬起操作时,就给SettleAccountActivity发送消息,告知已签字
				Message message = new Message();
				message.what=2;
				message.arg1=1;
				if (mbitmaphHandler!=null){
					mbitmaphHandler.sendMessage(message);
				}

				float My = event.getX();		//手指离开屏幕时的坐标
				float Mx = event.getY();
				if (fingerMatrix!=null) {
					fingerMatrix.getx(Mx);
					//Log.i("线程", "离开"+Mx);
					fingerMatrix.getY(My);
				}
				mCanvas.drawPath(path, mPaint);
				lists.add(sPath);
				invalidate();
				if (timer!=null) {
					if (task!=null) {
						task.cancel();
						task = new TimerTask() {
							public void run() {
								Message message = new Message();
								message.what = 1;
								handler.sendMessage(message);
							}
						};
						timer.schedule(task, 2200, 2200);				//2200秒后发送消息给handler更新Activity
					}
				}else {
					timer = new Timer(true);
					timer.schedule(task, 2200, 2200);					//2200秒后发送消息给handler更新Activity
				}
				break;
			default:

				if (task!=null) {
					task.cancel();
					task = new TimerTask() {
						public void run() {
							handler.sendEmptyMessage(0);
						}
					};

				}
				break;
		}
		return true;
	}


	/**
	 * 处理屏幕显示
	 */
	Handler handler = new Handler(){
		public void handleMessage(Message msg) {
			switch (msg.what) {			//handler告诉Activity处理数据
				case 1:						//CUT_BITMAP_SEND_TO_ACTIVITY//切割图片发送给Activity处理
					//Log.i("线程", "handler收到");
					myBitmap = mBitmap;			//获取写好的图片
					if (fingerMatrix!=null) {			//获取绘制的区域坐标
						myBitmap = cutBitmap(myBitmap);					//切割Bitmap图片方法
					}
					fingerMatrix=null;
					if (mbitmaphHandler!=null){

						Matrix matrix = new Matrix();
						matrix.postRotate(90); /*翻转90度*/
						int width = myBitmap.getWidth();
						int height =myBitmap.getHeight();
						myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, width, height, matrix, true);
						saveBiamtImate(myBitmap);
					}
					Message message = new Message();
					message.what=1;
					Bundle bundle = new Bundle();
					bundle.putParcelable("bitmap",myBitmap);
					message.setData(bundle);
					if (mbitmaphHandler!=null){
						mbitmaphHandler.sendMessage(message);
					}
					//RefreshCanvas();
					break;
			}
			super.handleMessage(msg);
		}
	};


	/**
	 * 发送消息给handler更新ACTIVITY
	 */
	TimerTask task = new TimerTask() {
		public void run() {
			Message message = new Message();
			message.what=1;
			//Log.i("线程", "来了");
			handler.sendMessage(message);
		}
	};

	/**
	 * 保存路径类
	 * @author Administrator
	 */
	class savePath{
		Paint paint;
		Path path;
	}

	/**
	 * 切割图片方法和更新Activity
	 * @param bnBitmap
	 */
	public Bitmap cutBitmap(Bitmap bnBitmap){
		//最小
		float minx = fingerMatrix.getMinX();		//最小的x坐标
		float miny = fingerMatrix.getMinY();		//最小的y坐标
		//最大
		float maxy = fingerMatrix.getMaxY();		//最大的Y坐标
		float maxX = fingerMatrix.getMaxX();		//最大的x坐标
		//Log.i("","矩阵的坐标信息为:-======最大X:"+maxX+"----====最大Y:"+maxy+"----====最小X:"+minx+"----====最小Y:"+miny);
		int cutMinX = (int)(minx-15);		//切割的最小值
		int cutMinY = (int)(miny-15);		//切割的最小值
		int cutMaxX = (int)(maxX+15);
		int cutMaxY = (int)(maxy+15);
		if (cutMinX<=0) {
			cutMinX=0;
		}
		if (cutMinY<=0) {
			cutMinY=0;
		}
		if (cutMaxX>mBitmap.getWidth()) {			//如果X坐标大于图片的宽度
			cutMaxX =  mBitmap.getWidth()-1;		//那就把图片的宽度付给X坐标 的最大值
		}
		if (cutMaxY>mBitmap.getHeight()) {			//如果Y坐标大于图片的宽度
			cutMaxY = mBitmap.getHeight()-1;		//那就把图片的宽度付给Y坐标 的最大值
		}

		int width =(int)(cutMaxX - cutMinX);		//最大的x坐标减去最小的x坐标
		int height =(int)(cutMaxY-cutMinY);			//最大的Y坐标减去最小的y坐标

		Bitmap wBitmap =Bitmap.createBitmap(bnBitmap, cutMinX, cutMinY, width, height);		//这个步骤意思是在什么坐标位置创建一张图片
		if (myBitmap!=null ) {
			//myBitmap.recycle();
			myBitmap= null;
		}
		//Log.i("线程", "剪切图片成功");
		return wBitmap;
	}

	/**
	 * 保存图片
	 * @param bitmap1
	 */
	public boolean saveBiamtImate(Bitmap bitmap1){
		Date localDate=new Date();
		String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "AthenaImage";
		File file=new File(path);
		if (!file.exists()){
			file.mkdirs();
		}
		//String fileUrl = Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator+"AthenaImage"+ "/save.jpg";
		String fileUrl ="save.png";

		try {
			FileOutputStream fos = new FileOutputStream(new File(file,fileUrl));
			bitmap1.compress(CompressFormat.PNG, 100, fos);
			fos.flush();
			fos.close();
			Log.i("TAG", "2成功!" + fileUrl);
			return true;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 刷新画布
	 */
	public void RefreshCanvas(){
		//Log.i("线程", "初始化数据并且 刷新画布");
		if (lists!=null&&lists.size()>0) {
			lists.remove(lists);
			if (mBitmap!=null) {
				mBitmap=null;
			}
			path=null;
//			inter(dm.widthPixels,dm.heightPixels);
			inter(dm.widthPixels,dm.heightPixels);

			//Log.i("线程", "初始化数据成功");
			invalidate();
		}
		if (task!=null) {
			task.cancel();
		}
	}
}
3.布局文件引用:

<FrameLayout
        android:layout_below="@+id/tv2"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/finger_layout"
        android:background="@drawable/tv_border_thin"
        android:layout_margin="@dimen/common_sw320dp_of_10"
        >
        <com.canvas.ImageEditTextView
                android:id="@+id/main_image_edit"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:background="@color/transparent"
                android:focusable="true"
                android:focusableInTouchMode="true"
                android:gravity="top|left"
                android:paddingBottom="3dip"
                android:paddingTop="3dip"
                android:textSize="50dip" >
        </com.canvas.ImageEditTextView>

        <com.canvas.HandTouchView
                android:id="@+id/hand_touch"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:background="@color/transparent">
        </com.canvas.HandTouchView>
</FrameLayout>
4.Activity:
private void initView() {

        Display display = this.getWindowManager().getDefaultDisplay();
        mWidth = display.getWidth();
        mHeight = display.getHeight();

        touchView=(HandTouchView) include2.findViewById(R.id.hand_touch);


        imageEditTextView = (ImageEditTextView)include2.findViewById(R.id.main_image_edit);


    }
public int mWidth,mHeight;
    public HandTouchView touchView;
    private Bitmap tempBitmap;
/**
 * 图片处理方法
*/
Handler handler = new Handler(){
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    Bundle bundle = new Bundle();
                    bundle = msg.getData();
                    tempBitmap = bundle.getParcelable("bitmap");			//获取图片
                    if (null!=tempBitmap) {

                        isGetBitmap=1;//0:未签字;1:已签字
                        Log.i("线程", "前台取到VIEW的值");
                        int w  = tempBitmap.getWidth();							//获取图片的宽度如果大就缩小如果小就不变
                        int h = tempBitmap.getHeight();
                        //取到当前的行高和行宽
                        int lineHeight =  (int) (mHeight/6f);
                        int lineWidth = (int) (mWidth/4f);
                        if(mHeight == 1280 && mWidth == 800){
                            lineHeight =  (int) (mHeight/5.4f);
                            lineWidth = (int) (mWidth/4f);
                        }
                        tempBitmap =BitmapAmplification(tempBitmap);
                        editInsertBitmap(tempBitmap);				//显示在EditText上
                        try {
                            EditTextSaveImage();
                            tv_submit_c.setEnabled(true);
                            Log.i("TAG","①图片已保存本地");

                            /*if (tv_submit_c.getText().toString().equals("保存")){
                                tv_submit_c.setEnabled(true);
                                Log.i("TAG","①图片已保存本地");
                            }*/

                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }else {
                        if (dialog.isShowing()){
                            dialog.dismiss();
                        }
                        Toast.makeText(SettleAccountActivity.this,"提交前请先签字",Toast.LENGTH_SHORT).show();
                    }
                    break;
                default:
                    isGetBitmap= msg.arg1;//0:未签字;1:已签字

                    break;
            }

            super.handleMessage(msg);
        }

    };
    /**
     * 将bitmap添加到自定义edittext中
     * @param bitmap
     */
    public void editInsertBitmap(Bitmap bitmap) {
        SpannableString ss = new SpannableString("1");
        ImageSpan span = new ImageSpan(bitmap, ImageSpan.ALIGN_BOTTOM);
        ss.setSpan(span, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        imageEditTextView.append(ss);
        imageEditTextView.setPadding(0, 0, 0, 10);

    }
    /**
     * 删除方法
     */
    public void editImageDelete(){
        Editable editable = imageEditTextView.getText();
        int end = imageEditTextView.getSelectionEnd();		//删除最后的一个
        if (end==1) {
            imageEditTextView.setText("");
            return;
        }
        if (end<=0) {
            imageEditTextView.setText("");
            return;
        }
        CharSequence sequence = editable.subSequence(0, end-1);
        imageEditTextView.setText(sequence);
        imageEditTextView.setSelection(end - 1);
    }

    Bitmap bp;
    public Bitmap BitmapAmplification(Bitmap path) {
        if (path!=null) {
            if(bp!=null){
                bp=null;
            }
            int w = path.getWidth();	//得到图片的宽度
            int h = path.getHeight();//得到图片的高度
            Log.v("nnn", "宽"+w+"高"+h);
            float ww = ((float) 62) / w;
            float hh = ((float) 45) / h;
            Matrix matrix = new Matrix();
            matrix.postScale(ww, hh);
            Log.v("nnn", "可以www");
            bp = Bitmap.createBitmap(path, 0, 0, w, h, matrix, true);
            if (tempBitmap!=null ) {
                tempBitmap=null;
            }
            return bp;
        }
        return null;
    }
    //private Bitmap savebitmap;

    public void EditTextSaveImage() throws IOException {


        //取本地图片
        String fileUrl = Environment.getExternalStorageDirectory().getAbsoluteFile()+File.separator+"AthenaImage"+File.separator+"save.png";
        //String fileUrl=Environment.getExternalStorageDirectory().getAbsoluteFile()+File.separator+"iv.jpg";
        Log.i("TAG", "②取到本地图片地址:fileUrl:" + fileUrl);

        if (!StringUtils.isEmpty(fileUrl)&&!hasSaved) {
            saveUPYun(fileUrl);
        }

    }
</pre><pre name="code" class="java">
好了,写到这里,其实你的本地就已经存好了图片,剩下来的步骤就很简单啦
注意保存的图片格式是PNG,千万一定要用PNG,不要用JPG啊,因为JPG保存的图片背景是黑色的,有好长一段时间我都掉进了这个坑!具体什么原因,我也不清楚,欢迎交流学习。




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值