Android手写笔迹并透明化处理

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

  1. 用户选择已经拍摄的笔迹照片
  2. 用户通过裁剪区域选择手写笔迹(尺寸为300*120)
  3. 程序将裁剪好的手写笔迹区域进行笔迹采集和透明化处理
    -将图片中的黑色像素点1 保留,其他像素点设置为透明 (难点和重点:哪些色值可以被认定为笔迹、用户拍照时候的光线影响、用户手写纸的背景色)
    -将图片保存为手写区域
  4. 将处理好的手写笔迹采集结果给用户预览
  5. 用户确认后将此手写笔迹处理后的图提交给服务端

Android模块的核心代码(图片裁剪不在此范围)

package cn.org.bjca.wcert.ywq.utils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Environment;

import java.io.File;
import java.io.FileOutputStream;

/*************************************************************************************************
 * <pre>
 * @包路径: cn.org.bjca.wcert.ywq.utils
 * @版权所有: 北京数字认证股份有限公司 (C) 2020
 *
 * @类描述: 手写笔迹处理
 * @版本: V4.0.0
 * @作者 daizhenhong
 * @创建时间 2020/11/2 3:50 PM
</pre>
 ************************************************************************************************/
public class HandSignUtil {
    
    

    final static String filePathHeader = "file://";
    private final static int maxColorBlack = 145;
    private final static int mColorDifMax = 14;

    /**
     * 将已经裁剪了的手写签名笔迹图片进行透明化处理
     *
     * @param context
     * @param imagePath 图片的文件地址(前缀是file://)
     * @return 经过背景透明化处理后的图片地址(需要添加file://协议头)
     * @throws Exception
     */
    public static String getHandSignByImagePath(Context context, String imagePath) throws Exception {
    
    
        String path = imagePath.substring(filePathHeader.length());
        Bitmap originBitmap = BitmapFactory.decodeFile(path);
        Bitmap translateBitmap = translateBitmap(originBitmap);
        String filePath = getSaveImagePath(context);
        File saveFile = new File(filePath);
        translateBitmap.compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(saveFile));
        return filePathHeader + saveFile.toString();
    }

    private static String getSaveImagePath(Context context) {
    
    
        String cachePath = "";
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
                || !Environment.isExternalStorageRemovable()) {
    
    
            cachePath = context.getExternalCacheDir().getPath();
        } else {
    
    
            cachePath = context.getCacheDir().getPath();
        }
        File fileParent = new File(cachePath);
        if (!fileParent.exists()) {
    
    
            fileParent.mkdirs();
        }
        File path = new File(cachePath, System.currentTimeMillis() + ".png");
        return path.toString();
    }

    /**
     * 将图片进行背景透明化处理
     *
     * @param originBitmap 原始图片的bitmap对象
     * @return 背景透明化处理后的bitmap
     */
    private static Bitmap translateBitmap(Bitmap originBitmap) {
    
    
        Bitmap translateBitmap = originBitmap.copy(Bitmap.Config.ARGB_8888, true);
        int nWidth = translateBitmap.getWidth();
        int nHeight = translateBitmap.getHeight();
        // 由于图片经过裁剪后是jpeg格式的,如果直接保存成png图片,会造成透明的背景色变成黑色(因为jpeg图片没有alpha通道)
        Bitmap resultBitmap = Bitmap.createBitmap(nWidth, nHeight, Bitmap.Config.ARGB_8888);

        for (int y = 0; y < nHeight; ++y)
            for (int x = 0; x < nWidth; ++x) {
    
    
                int nPixelColor = originBitmap.getPixel(x, y);
                int newColor = getNewColor(nPixelColor);
                resultBitmap.setPixel(x, y, newColor);
            }
        return resultBitmap;
    }


    /**
     * 获取像素点需要变更的颜色
     * 当像素点不是黑色的,则将其设置为透明
     *
     * @param nPixelColor
     * @return
     */
    private static int getNewColor(int nPixelColor) {
    
    
        if (isBlackColor(nPixelColor)) {
    
    
            return Color.argb(Color.alpha(nPixelColor), Color.red(nPixelColor), Color.green(nPixelColor), Color.blue(nPixelColor));
        }
        return Color.TRANSPARENT;
    }


    /**
     * 判断是否是黑色笔迹
     *
     * @param color 颜色的int值
     * @return true-认定为黑色笔迹
     */
    private static boolean isBlackColor(int color) {
    
    
        int r = Color.red(color);
        int g = Color.green(color);
        int b = Color.blue(color);
        int colorMax = Math.max(Math.max(r, g), b);
        int colorMin = Math.min(Math.min(r, g), b);
        int dif = colorMax - colorMin;
        return colorMax < maxColorBlack && dif <= mColorDifMax;
    }

}


  1. 黑色像素点我们的计算方式:图像的像素有rgb(jpeg图片)或rgba组件(png图片),我们目前的设定是:rgb的最大一项不大于145 ,同时rgb之前的最大差距不能超过14 ↩︎

猜你喜欢

转载自blog.csdn.net/u010899138/article/details/109477416