一、创建枚举类型

package com.chuangtu;/*** 比例枚举:此枚举是计算出的各个位置在身份证上的比例信息*/
public enum ProportioEnum {//身份证号idNumber(0.5416666666666667, 0.0805467372134039, 0.3157894736842105, 0.8055784832451499),//姓名name(0.2460850111856823, 0.0986524822695035, 0.1733780760626398, 0.104113475177305),//性别gender(0.0503355704697987, 0.0797872340425532, 0.1733780760626398, 0.2446808510638298),//民族national(0.0503355704697987, 0.0797872340425532,0.3713646532438479, 0.2446808510638298),//生日birthday(0.3557046979865772, 0.0797872340425532,0.1733780760626398,0.3687943262411348),//地址address(0.421834451901566, 0.2482269503546099, 0.1733780760626398, 0.4893617021276596),//面部face(0,0,0,0);ProportioEnum(double targetWith , double targetHeight, double iocationWith, double iocationHeight) {this.targetWith = targetWith;this.targetHeight = targetHeight;this.iocationWith = iocationWith;this.iocationHeight = iocationHeight;}private double targetWith;private double targetHeight;private double iocationWith;private double iocationHeight;/*** 获取目标对象的宽度比* @return*/public double getTargetWith(){return targetWith;}/*** 获取目标对象的高度比* @return*/public double getTargetHeight(){return targetHeight;}/*** 获取位置坐标的宽度比* @return*/public double getIocationWith(){return iocationWith;}/*** 获取位置坐标的高度比* @return*/public double getIocationHeight(){return iocationHeight;}
}

二、添加打码工具类

package com.creatoo.hn.util;import com.creatoo.hn.util.enums.ProportioEnum;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Map;/*** 图片处理类* @author hty**/
public class IdCardUtil {/*** 身份证脱敏方法* @param file 要脱敏的图片文件* @param p 身份证的四个顶点坐标* @param center 人脸中心点坐标* @param proportion 要遮罩的部分(姓名、性别、民族、生日、地址、身份证号、人脸)* @param map 人脸尺寸* @return* @throws Exception*/public static File desensitization(File file, Point[] p, Point center, ProportioEnum proportion, Map<String,Double> map) throws Exception{if ("face".equals(proportion.name())){//获取马赛克区域的长和宽double width = map.get("width");double height = map.get("height");int radius = 0;if (width>height){radius = (int) (width/2);}else {radius = (int) (height/2);}//获取人脸顶点坐标Point[] points = getFacePoint(radius,center);//给人脸加马赛克File faceFile = mosaicFace(file,points,radius,20);if (faceFile != null) {file = faceFile;return file;}}int firstIdex = getInterval(p, center);Point first = p[firstIdex];//获取身份证长度和宽度double with = getLength(first, p[getIndex(firstIdex, p.length, 1)]);double height = getLength(first, p[getIndex(firstIdex, p.length, p.length - 1)]);double xAngle = getAngle(first, p[getIndex(firstIdex, p.length, 1)]);double yAngle = getAngle(first, p[getIndex(firstIdex, p.length, p.length - 1)]);//身份证号长宽double targetWith = with * proportion.getTargetWith();double targetHeight = height * proportion.getTargetHeight();//位置坐标长宽double locationWith = with * proportion.getIocationWith();double locationHeight = height * proportion.getIocationHeight();double y = first.y + locationWith * Math.sin(xAngle) + locationHeight * Math.sin(yAngle);double x = (first.x + locationHeight * Math.cos(yAngle)) + locationWith * Math.cos(xAngle);Point a = new Point(x, y);Point b = getPoint(a, targetWith, xAngle);Point c = getPoint(b, targetHeight, yAngle);Point d = getPoint(a, targetHeight, yAngle);return mosaic(file, a, b, c, d, 15);}/*** 给图片指定位置打马赛克* @param mosaicSize 马赛克尺寸,即每个矩形的长宽* @return* @throws IOException*/@SuppressWarnings("static-access")public static File mosaic(File file, Point p1, Point p2, Point p3, Point p4, int mosaicSize) throws IOException {if (!file.isFile()) {throw new RuntimeException("请上传文件");}int index = file.getName().lastIndexOf(".");if (index == -1){throw new RuntimeException("文件格式不正确");}String suffix = file.getName().substring(index + 1);if (!suffix.equalsIgnoreCase("png") && !suffix.equalsIgnoreCase("jpg") &&!suffix.equalsIgnoreCase("gif") && !suffix.equalsIgnoreCase("bmp")) {throw new RuntimeException("文件格式不正确");}BufferedImage bi = ImageIO.read(file); // 读取该图片BufferedImage spinImage = new BufferedImage(bi.getWidth(),bi.getHeight(), bi.TYPE_INT_RGB);double width = getLength(p1, p2);double height = getLength(p1, p4);//2. 设置各方向绘制的马赛克块个数int xcount = (int)Math.floor( width/ mosaicSize) +1; // 方向绘制个数int ycount = (int)Math.floor( height/ mosaicSize) +1; // y方向绘制个数//3. 绘制马赛克(绘制矩形并填充颜色)Graphics2D gs = spinImage.createGraphics();gs.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);gs.drawImage(bi, 0, 0, null);double xAngle = getAngle(p1 ,p2);double yAngle = getAngle(p1 ,p4);Point tmp = new Point(p1.x, p1.y);for (int i = 0; i < ycount; i++) {Point newline = tmp;for (int j = 0; j < xcount; j++) {//马赛克矩形格大小double mwidth = mosaicSize;double mheight = mosaicSize;//矩形颜色取中心像素点RGB值double centerX = tmp.x;double centerY = tmp.y;if (mwidth % 2 == 0) {centerX += mwidth / 2;} else {centerX += (mwidth - 1) / 2;}if (mheight % 2 == 0) {centerY += mheight / 2;} else {centerY += (mheight - 1) / 2;}Color color = new Color(bi.getRGB((int) centerX, (int) centerY));gs.setColor(color);Point tmp2 = getPoint(tmp, mwidth,xAngle);Point tmp3 = getPoint(tmp2, mheight,yAngle);Point tmp4 = getPoint(tmp, mheight,yAngle);if(j == 0){newline = tmp4;}gs.fill(getCutPath(tmp, tmp2, tmp3, tmp4));tmp = tmp2;}tmp = newline;}gs.dispose();File outputfile = new File(IDUtils.getID()+"."+suffix);ImageIO.write(spinImage, suffix, outputfile);return outputfile;}/*** 给人脸区域添加马赛克* @param file 要脱敏的图片文件* @param points 人脸四个顶点的坐标* @param radius 打码区域边长的一半* @param mosaicSize 马赛克粒度* @return 处理后的图片文件* @throws IOException*/private static File mosaicFace(File file,Point[] points,Integer radius,int mosaicSize) throws IOException {if (!file.isFile()) {throw new RuntimeException("传入的不是文件");}int index = file.getName().lastIndexOf(".");String suffix = file.getName().substring(index + 1);// 读取图片文件BufferedImage bi = ImageIO.read(file);BufferedImage spinImage = new BufferedImage(bi.getWidth(),bi.getHeight(), BufferedImage.TYPE_INT_RGB);// 设置绘制的马赛克块个数int count = (int)Math.floor( radius*2/ mosaicSize) +1; // 方向绘制个数//创建一个 Graphics2D ,可以用来绘制这个 BufferedImage 。Graphics2D gs = spinImage.createGraphics();gs.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);gs.drawImage(bi, 0, 0, null);//起点坐标Point tmp = points[0];for (int i = 0; i < count; i++) {//行Point newline = tmp;for (int j = 0; j < count; j++) {//列//马赛克矩形格大小double mwidth = mosaicSize;//取矩形中心点坐标double centerX = tmp.x;double centerY = tmp.y;if (mwidth % 2 == 0) {centerX += mwidth / 2;centerY += mwidth / 2;} else {centerX += (mwidth - 1) / 2;centerY += (mwidth - 1) / 2;}//取矩形中心点坐标颜色Color color = new Color(bi.getRGB((int) centerX, (int) centerY));gs.setColor(color);//获取每个小方格的顶点坐标Point tmp2 = new Point(tmp.x+mwidth,tmp.y);Point tmp3 = new Point(tmp.x+mwidth,tmp.y+mwidth);Point tmp4 = new Point(tmp.x,tmp.y+mwidth);//控制第二行的起点if(j == 0){newline = tmp4;}//填充图形gs.fill(getCutPath(tmp, tmp2, tmp3, tmp4));tmp = tmp2;}tmp = newline;}//关闭资源gs.dispose();//将文件持久化到本地File outputfile = new File(IDUtils.getID()+"."+suffix);ImageIO.write(spinImage, suffix, outputfile);return outputfile;}/*** 获取人脸顶点坐标* @param radius 尺寸信息* @param center 人脸中心点坐标* @return*/private static Point[] getFacePoint(int radius, Point center) {Point[] points = new Point[4];Point p1 = new Point(center.x - radius, center.y - radius);Point p2 = new Point(center.x + radius, center.y - radius);Point p3 = new Point(center.x + radius, center.y + radius);Point p4 = new Point(center.x - radius, center.y + radius);points[0] = p1;points[1] = p2;points[2] = p3;points[3] = p4;return points;}/*** 获取区域路径** @return*/public static GeneralPath getCutPath(Point p1, Point p2, Point p3, Point p4) {GeneralPath path = new GeneralPath();path.moveTo(p1.x, p1.y);path.lineTo(p2.x, p2.y);path.lineTo(p3.x, p3.y);path.lineTo(p4.x, p4.y);path.lineTo(p1.x, p1.y);return path;}/*** 与x轴角度* @param p1* @param p2* @return*/public static double getAngle(Point p1, Point p2) {return  Math.atan2((p2.y - p1.y), (p2.x - p1.x));}/*** 获取指定区域的点坐标* @param p* @param length* @param angle* @return*/public static Point getPoint(Point p, double length, double angle) {double x = length * Math.cos(angle) + p.x;double y = (length * Math.sin(angle)) + p.y;return new Point(x,y);}/*** 获取两点间长度* @param p1* @param p2* @return*/public static double getLength(Point p1, Point p2) {return Math.sqrt(Math.abs((p1.getX() - p2.getX())* (p1.getX() - p2.getX())+(p1.getY() - p2.getY()) * (p1.getY() - p2.getY())));}/*** 返回身份证左上角坐标* @return*/public static  int getIndex(int current,int length, int size){int next = current;for(int i =0; i<size; i++){if(next == length -1){next = 0;}else {next ++;}}return next;}/*** 返回身份证左上角坐标* @param center* @return*/public static  int getInterval(Point[] p, Point center){double with = getLength(p[0], p[1]);double height = getLength(p[0], p[3]);// p[0] - p[1], p[2]-p[3]if(with > height){Point minpoint = minpoint(p[0], p[1]);Point minpoint2 = minpoint(p[2], p[3]);if(check(p[0],minpoint,minpoint2,p[3],center)){return 2;}else {return 0;}//p1-p4 , p2-p3}else {Point minpoint = minpoint(p[0], p[3]);Point minpoint2 = minpoint(p[1], p[2]);if(check(p[0],minpoint,minpoint2,p[1],center)){return 3;}else {return 1;}}}//两点坐标的中点public static Point minpoint(Point a,Point b){double x=(a.getX()+b.getX())/2;double y=(a.getY()+b.getY())/2;return new Point(x, y);}/*** 一个点是否在多边形内* @return*/private static boolean check(Point p1, Point p2, Point p3, Point p4, Point center) {Point2D.Double center2 = new Point2D.Double(center.x, center.y);Point2D.Double d1 = new Point2D.Double(p1.x, p1.y);Point2D.Double d2 = new Point2D.Double(p2.x, p2.y);Point2D.Double d3 = new Point2D.Double(p3.x, p3.y);Point2D.Double d4 = new Point2D.Double(p4.x, p4.y);GeneralPath peneralPath = new GeneralPath();peneralPath.moveTo(d1.x, d1.y);peneralPath.lineTo(d2.x, d2.y);peneralPath.lineTo(d3.x, d3.y);peneralPath.lineTo(d4.x, d4.y);peneralPath.lineTo(d1.x, d1.y);peneralPath.closePath();// 测试指定的 Point2D 是否在 Shape 的边界内。return peneralPath.contains(center2);}}

测试

package com.chuangtu;import java.io.*;
import java.util.HashMap;
import java.util.Map;public class Test {public static void main(String[] args) {try {//============= 通过阿里orc服务获取参数========//身份证四个顶点坐标Point[] p =  new Point[4];p[0] = new Point(19,463);p[1] = new Point(931,460);p[2] = new Point(931,1044);p[3] = new Point(25,1046);//头像中心点坐标Point center = new Point(721,728);//人脸尺寸Map<String,Double> map = new HashMap<String, Double>();map.put("width",(double)324);map.put("height",(double)268);File file = new File("C:\\Users\\PC0825\\Desktop\\zhaopian(1)\\2.jpg");//脸部打码File desensitizationFace = IdCardUtil.desensitization(file, p, center, ProportioEnum.face,map);//身份证号打码File desensitizationId = IdCardUtil.desensitization(desensitizationFace, p, center, ProportioEnum.idNumber,map);//姓名打码File desensitizationName = IdCardUtil.desensitization(desensitizationId, p, center, ProportioEnum.name,map);//住址打码File desensitization = IdCardUtil.desensitization(desensitizationName, p, center, ProportioEnum.address,map);//文件持久化BufferedInputStream bis = new BufferedInputStream(new FileInputStream(desensitization));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\fillOval2.jpg"));byte[]bys = new byte[1024];int len;while ((len=bis.read(bys))!=-1){bos.write(bys,0,len);}//关闭流资源bos.close();bis.close();//删除项目中产生的图片文件desensitizationFace.deleteOnExit();desensitizationId.deleteOnExit();desensitizationName.deleteOnExit();desensitization.deleteOnExit();} catch (Exception e) {System.err.println("出错了!!!!");e.printStackTrace();}}}

Java程序为身份证照片添加马赛克相关推荐

  1. Java后台开发Tomcat添加https支持小程序开发过程

    文章原文:blog.ouyangsihai.cn >> Java后台开发Tomcat添加https支持小程序开发过程 1 给自己的域名申请证书 注意:申请好了如果不是在腾讯注册的域名,不会 ...

  2. idea java opts_idea为java程序添加启动参数(program arguments,vm arguments,Environment variable),并在程序中获取使用...

    # 一.问题描述 # ## 1. 开发环境 ## 1. idea2019 2. jdk1.8 3. win10 在实际的项目开发中我们经常需要为java程序添加一些启动参数(又叫java启动命令),比 ...

  3. 编写Java程序,在屏幕上显示带标题的窗口,并添加一个按钮。当用户单击按钮时,结束程序。

    编写Java程序,在屏幕上显示带标题的窗口,并添加一个按钮.当用户单击按钮时,结束程序. package p3;import java.awt.event.ActionEvent; import ja ...

  4. java对象添加字段_99.9%的Java程序员都说不清的问题:JVM中的对象内存布局?

    在 Java 程序中,我们拥有多种新建对象的方式.除了最为常见的new语句之外,我们还可以通过反射机制.Object.clone方法.反序列化以及Unsafe.allocateInstance 方法来 ...

  5. java channel midi_为Java程序中添加播放MIDI音乐功能

    下载本文示例代码 Java在多媒体处理方面的确优势不大,但是我们在程序中有些时候又需要一些音乐做为点缀,如果播放的音乐是wav等波形音频文件,又挺大,所以背景音乐最好就是MIDI了,可是网上很多播放M ...

  6. java关闭事件_为Java程序添加退出事件

    package org.swing.os; import java.util.*; import java.io.*; /** * 为Java程序添加退出事件 * * @author wuhq */ ...

  7. 为诺基亚S40手机添加java程序的cmwap代理配置!

    很多用诺基亚S40手机的朋友会发现这样一个问题,只要使用cmwap接入点,不论网络怎样设置,有些java程序就是不能联网,比如Opera Mini和英文版的Google Maps,而使用cmnet就可 ...

  8. java程序实现给图片添加logo

    java程序实现给图片添加logo 练习需求: 拿到一张图片,给图片添加上水印信息 package com.zcl.newDemo;import javax.imageio.ImageIO; impo ...

  9. UiBot新版本即将上线!添加Java程序支持!

    UiBot 1.0一经推出即广受好评. 上线不到一周, 下载数和注册数双双破千! 不过, 我们的程序猿们并没有因此而满足. 春节的脚步慢慢临近 但他们依然没有松懈 出于对事业的热爱, 对技术的精益求精 ...

最新文章

  1. myeclipse修改编译器版本的方法 .
  2. Linux shell脚本基础学习详细介绍(完整版)一
  3. 查看、修改linux系统的最大链接数限制、文件描述符限制、端口范围限制、虚拟内存等...
  4. SAP Spartacus B2B 页面 Disable 按钮的显示原理
  5. Linux搜索无线网络命令,Linux操作系统的无线网络命令
  6. 12句让人心疼的话 哪一句说到你心里了?
  7. JavaWeb 基础系列篇
  8. 新鲜出炉,Amazon SDE 面经(电面+Onsite)
  9. 网站子域名扫描程序,采用三种扫描方式(crt网站查询、站长网站查询、字典暴力破解)
  10. python实现一个土豆聊天 potato chat 机器人
  11. android 401,Android HttpClient身份验证始终返回401代码
  12. android充电线排序,安卓数据线分类有哪些
  13. mysql sock_mysql.sock 文件解析
  14. 2022英语词汇积累
  15. 2022年全球与中国湿钽电容器行业发展趋势及投资战略分析报告
  16. hive和presto计算日期时间差
  17. 花里胡哨的天气插件代码生成
  18. jquery抓娃娃机代码
  19. 怎么恢复相机格式化的照片?
  20. excal怎么设置模板阈值

热门文章

  1. 2018 51信用卡春招后端开发实习题解
  2. 常用电平标准——LVTTL、LVCMOS、LVDS
  3. Android【Socket通讯】
  4. php八字喜用神实现博客,八字喜用神测算方法
  5. DDN4.9实践 - Source版的安装
  6. 专家纵论谈大数据:认清本质 挖掘真价值
  7. 如何将论文图表做得漂亮?
  8. 学习分享——基于深度学习的NILM负荷分解(一)对DL的看法准备工作
  9. Direct3d 设备丢失 (device lost)
  10. 2017 Google I/O 最新科技看点