要实现一个文章签名功能,我的实现思路是把文件转成图片,签字版生成的签名也生成图片,然后先进行签名图片手指移动到指定位置进行图片合成。
图片合成代码

/*** 合成图片* @param background 背景图* @param foreground 前景图* @param foreX X坐标* @return*/public static Bitmap combineBitmap(Bitmap background, Bitmap foreground,Context context,float foreX,float foreY) {if (background == null || foreground=null) {return null;}int screenWidth= DpUtil.displayWidth();int screenHeight=DpUtil.displayHeight();LogUtils.e("屏幕width:"+screenWidth);LogUtils.e("屏幕height:"+screenHeight);int bgWidth = background.getWidth();int bgHeight = background.getHeight();LogUtils.e("背景图width:"+bgWidth);LogUtils.e("背景图height:"+bgHeight);Bitmap newmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888);//这里注意bitmap要用屏幕宽高,如果使用background宽高会使图片放大或缩小Canvas canvas = new Canvas(newmap);canvas.drawBitmap(background, new Matrix(), null);// Rect rect=new Rect((int) (foreX-foreground.getWidth()),(int) (foreY-foreground.getHeight()),(int) (foreX),(int) (foreY));canvas.drawBitmap(foreground, foreX,foreY,null);//设置bitmap所在的位置canvas.save();canvas.restore();return newmap;}

用上面的方法生成的图片会有偏移现象,一直未解决,如果有大佬解决了请指教下。

我用了另一个解决方案,签名图片进行手指移动到需要的位置,然后进行截屏生成图片,为了体验好进行了延时2S

          new Handler().postDelayed(new Runnable() {@Overridepublic void run() {//下面注释的代码为全屏截屏(去掉状态栏)// View view1= getWindow().getDecorView();//  view1.setDrawingCacheEnabled(true);//   view1.buildDrawingCache();//   Bitmap bitmap= view1.getDrawingCache();view.setDrawingCacheEnabled(true);view.buildDrawingCache();Bitmap bitmap=view.getDrawingCache();FileUtils.saveBitmap(bitmap,1,context);ToastUtils.showToast(context,"签名完成");}},2000);

这个方法完美解决签名图片位置偏移问题
手写签字版代码如下:(借鉴大佬的代码,由于源代码链接没找到就不粘贴了)

public class LinePathView extends View {private Context mContext;//起点Xprivate float mX;//起点Yprivate float mY;//手写画笔private final Paint mGesturePaint = new Paint();//路径private final Path mPath = new Path();//画布private Canvas cacheCanvas;//生成的图片private Bitmap cachebBitmap;//画笔宽度 px;private int mPaintWidth = 10;//画笔颜色private int mPenColor = Color.BLACK;//背景色(指最终签名结果文件的背景颜色,默认为透明色)private int mBackColor=Color.TRANSPARENT;public LinePathView(Context context) {super(context);init(context);}public LinePathView(Context context, AttributeSet attrs) {super(context, attrs);init(context);}public LinePathView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context);}private void init(Context context) {this.mContext = context;//设置抗锯齿mGesturePaint.setAntiAlias(true);//设置签名笔画样式mGesturePaint.setStyle(Paint.Style.STROKE);//设置笔画宽度mGesturePaint.setStrokeWidth(mPaintWidth);//设置签名颜色mGesturePaint.setColor(mPenColor);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);//创建跟view一样大的bitmap,用来保存签名(在控件大小发生改变时调用。)cachebBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);cacheCanvas = new Canvas(cachebBitmap);cacheCanvas.drawColor(mBackColor);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//画此次笔画之前的签名canvas.drawBitmap(cachebBitmap, 0, 0, mGesturePaint);// 通过画布绘制多点形成的图形canvas.drawPath(mPath, mGesturePaint);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()){case MotionEvent.ACTION_DOWN:touchDown(event);break;case MotionEvent.ACTION_MOVE:touchMove(event);break;case MotionEvent.ACTION_UP://将路径画到bitmap中,即一次笔画完成才去更新bitmap,而手势轨迹是实时显示在画板上的。cacheCanvas.drawPath(mPath, mGesturePaint);mPath.reset();break;}// 更新绘制invalidate();return true;}// 手指点下屏幕时调用private void touchDown(MotionEvent event) {// 重置绘制路线mPath.reset();float x = event.getX();float y = event.getY();mX = x;mY = y;// mPath绘制的绘制起点mPath.moveTo(x,y);}// 手指在屏幕上滑动时调用private void touchMove(MotionEvent event) {final float x = event.getX();final float y = event.getY();final float previousX = mX;final float previousY = mY;final float dx = Math.abs(x - previousX);final float dy = Math.abs(y - previousY);// 两点之间的距离大于等于3时,生成贝塞尔绘制曲线if (dx >= 3 || dy >= 3) {// 设置贝塞尔曲线的操作点为起点和终点的一半float cX = (x + previousX) / 2;float cY = (y + previousY) / 2;// 二次贝塞尔,实现平滑曲线;previousX, previousY为操作点,cX, cY为终点mPath.quadTo(previousX, previousY, cX, cY);// 第二次执行时,第一次结束调用的坐标值将作为第二次调用的初始坐标值mX = x;mY = y;}}/*** 清除画板*/public void clear() {if (cacheCanvas != null) {//更新画板信息mGesturePaint.setColor(mPenColor);cacheCanvas.drawColor(mBackColor, PorterDuff.Mode.CLEAR);mGesturePaint.setColor(mPenColor);invalidate();}}/*** 保存画板* @param path 保存到路径*/public void save(String path)  throws IOException {save(path, false, 0);}/*** 保存画板* @param path       保存到路径* @param clearBlank 是否清除边缘空白区域* @param blank  要保留的边缘空白距离*/public void save(String path, boolean clearBlank, int blank) throws IOException {Bitmap bitmap=cachebBitmap;if (clearBlank) {bitmap = clearBlank(bitmap, blank);}ByteArrayOutputStream bos = new ByteArrayOutputStream();bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);byte[] buffer = bos.toByteArray();if (buffer != null) {File file = new File(path);if (file.exists()) {file.delete();}OutputStream outputStream = new FileOutputStream(file);outputStream.write(buffer);outputStream.close();}}/*** 保存画板* @param clearBlank 是否清除边缘空白区域* @param blank  要保留的边缘空白距离*/public Bitmap saveToBitmap(boolean clearBlank, int blank){Bitmap bitmap=cachebBitmap;//BitmapUtil.createScaledBitmapByHeight(srcBitmap, 300);//  压缩图片if (clearBlank) {bitmap = clearBlank(bitmap, blank);}return bitmap;}/*** 获取画板的bitmap* @return*/public Bitmap getBitMap(){setDrawingCacheEnabled(true);buildDrawingCache();Bitmap bitmap=getDrawingCache();setDrawingCacheEnabled(false);return bitmap;}/*** 逐行扫描 清楚边界空白。** @param bp* @param blank 边距留多少个像素* @return*/private Bitmap clearBlank(Bitmap bp, int blank) {int HEIGHT = bp.getHeight();int WIDTH = bp.getWidth();int top = 0, left = 0, right = 0, bottom = 0;int[] pixs = new int[WIDTH];boolean isStop;//扫描上边距不等于背景颜色的第一个点for (int y = 0; y < HEIGHT; y++) {bp.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1);isStop = false;for (int pix : pixs) {if (pix != mBackColor) {top = y;isStop = true;break;}}if (isStop) {break;}}//扫描下边距不等于背景颜色的第一个点for (int y = HEIGHT - 1; y >= 0; y--) {bp.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1);isStop = false;for (int pix : pixs) {if (pix != mBackColor) {bottom = y;isStop = true;break;}}if (isStop) {break;}}pixs = new int[HEIGHT];//扫描左边距不等于背景颜色的第一个点for (int x = 0; x < WIDTH; x++) {bp.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT);isStop = false;for (int pix : pixs) {if (pix != mBackColor) {left = x;isStop = true;break;}}if (isStop) {break;}}//扫描右边距不等于背景颜色的第一个点for (int x = WIDTH - 1; x > 0; x--) {bp.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT);isStop = false;for (int pix : pixs) {if (pix != mBackColor) {right = x;isStop = true;break;}}if (isStop) {break;}}if (blank < 0) {blank = 0;}//计算加上保留空白距离之后的图像大小left = left - blank > 0 ? left - blank : 0;top = top - blank > 0 ? top - blank : 0;right = right + blank > WIDTH - 1 ? WIDTH - 1 : right + blank;bottom = bottom + blank > HEIGHT - 1 ? HEIGHT - 1 : bottom + blank;//防止创建null的bitmap  引发的崩溃if (left==0&&top==0&&right==0&&bottom==0){left=1;top=1;right=351;bottom=251;}return Bitmap.createBitmap(bp, left, top, right - left, bottom - top);}/*** 设置画笔宽度 默认宽度为10px** @param mPaintWidth*/public void setPaintWidth(int mPaintWidth) {mPaintWidth = mPaintWidth > 0 ? mPaintWidth : 10;this.mPaintWidth = mPaintWidth;mGesturePaint.setStrokeWidth(mPaintWidth);}public void setBackColor(@ColorInt int backColor){mBackColor=backColor;}/*** 设置画笔颜色** @param mPenColor*/public void setPenColor(int mPenColor) {this.mPenColor = mPenColor;mGesturePaint.setColor(mPenColor);}
}

Android 手写签名 (图片合成)相关推荐

  1. Android手写签名功能(包含画米字格,人名和书写轨迹)

    本文主要介绍Android手写签名的功能实现,效果如下图 1.根据人名的个数绘制人的名称 这个逻辑分几个步骤:首先创建画笔,然后根据一个字,创建一个字的矩形框,然后根据矩形框获取到画这个字的宽高. / ...

  2. Android手写签名 附带背景图设置

    android手写签名的demo网上其实有很多,但是大多没考虑到签名用在哪里的问题,所以就需要背景图设置,保存电子签名的时候  会连同背景图一起保存   这才达到了电子签名的效果,背景可以放置合同,请 ...

  3. android 手写签名

    Android 手写签名是指使用手指在 Android 设备上绘制的签名.它通常用于数字签名或签署电子文件.可以通过使用手写输入 API 和触摸事件 API 来实现手写签名功能.这可以通过开发自定义视 ...

  4. 手写签名图片处理-Android

    背景 用户通过笔在纸上手写了个人签名,通过拍照上传的方式将其笔迹设置为签名图片. 如果直接使用此图片(包括裁剪后的图片),则在签名的过程中会签名图案中不但有用户的笔迹,还有纸的颜色背景,效果堪忧. 解 ...

  5. Android手写签名

    手写签名自定义实现,看注释就行了 package com.zhuzi.taobamboo.user_defined; import android.content.Context; import an ...

  6. Android 手写签名实例

    这篇文章本来想在一个月前就发布的,最近一直忙于国家电网手持终端的应用开发,所以没抽出时间来写.周末到了,终于可以闲下来整理整理.话不多说,直奔主题. Android 提供了很多丰富.实用而且很有特色的 ...

  7. jsignature插件实操,完成手写签名图片格式功能

    jSignature是什么,如何使用? jSignature是一个H5基于canvas画布得一个插件可以用于手机,浏览器进行手写签名功能实现啦 Jsignature使用效果展示 注:本插件最新版是支持 ...

  8. android签名图片不显示,android手写签名遇见bitmap黑屏和本地html插入签名图片

    项目需求 :Android 展示Html保单模版页面, 类似于这种界面 屏幕快照 2017-11-07 下午4.02.11.png 然后调用签名(其实就一个绘画的窗口),签上你的大名,点击确定.展示签 ...

  9. android手写签名android-signaturepad

    GitHub地址: GitHub - gcacace/android-signaturepad: A custom Android View for drawing smooth signatures ...

  10. java实现手写签名,Android实现手写签名

    本文实例为大家分享了Android手写签名的实现方法,产品要求用户可以在app上签协议..所以得弄个手写签名版,参考了一些资料自己写了个PaintView去继承View,实现签名功能. package ...

最新文章

  1. 60 Permutation Sequence
  2. Silverlight 2.0学习笔记——XAML
  3. mqtt linux 编译,MQTT客户端代码X64位Ubuntu环境编译+测试实践小结
  4. gatekeeper学习概述
  5. 【干货下载】大数据分析的四个关键环节
  6. 使用Mutability Detector对Java数据类的不变性进行单元测试
  7. .gitignore忽略文件提交服务器
  8. L1-006 连续因子 (20 分)—团体程序设计天梯赛
  9. DEM数据(12米)精度获取方法
  10. CFA要学哪些课程?零基础怎么学CFA呢?
  11. 企业微信集成自建应用——踩坑记录
  12. python周环比增长率_Python如何计算环比增长率
  13. 微信网页授获取code
  14. 达梦MPP 环境搭建
  15. 数字化运营管控是如何提升管理透明及效率的!
  16. 科研ABC - 数据图表的绘制
  17. 怎样做网络推广浅析网站标题如何写更利于SEO?
  18. Linux进程5:exec族函数(execl, execlp, execle, execv, execvp, execvpe)总结及exec配合fork使用
  19. 计算机组成原理与结构
  20. 【系列】区块链与以太坊实战(1)-基础知识

热门文章

  1. [re入门]音乐文件加密破解
  2. 华为计算机主板,华为鲲鹏920台式机主板亮相:性能配置都亮眼
  3. 什么是台式机主板的“双通道”认知误区?
  4. 【B站弹幕游戏开发笔记02】Win10系统下给Python项目导入Protobuf
  5. 1:0 本立而道生!
  6. CF676A Nicholas and Permutation 题解
  7. jupyter 中,前面输入字符,后面的字符被覆盖消失(带小键盘的联想笔记本insert用法)
  8. idea gradle GC overhead limit exceeded
  9. lua工具库penlight--06数据(二)
  10. 华为光纤猫HG8240破解,开启路由功能表