已注销用户的gravatar头像
已注销用户 2018-04-25 10:07:20
java图像合并之身份证正反面合成图片

背景

上个项目,看见有个需求:需要把身份证的正面和反面合成一张图片,以便相关人员的审核,这里就分享对应的代码。

 

操作步骤

先从百度图片里面,下载两张图片,一张身份证正面,一张身份证反面

 

然后运行代码,即可获得一张正反面的身份证图片

 

举个栗子:

这是 正面

java图像合并之身份证正反面合成图片

 

这是反面

java图像合并之身份证正反面合成图片

 

合成的结果图:

java图像合并之身份证正反面合成图片

 

目的 简单明了,不用多说了,接下来看代码

package com.essence.util;

import org.apache.commons.codec.binary.Base64;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.*;

/**
 * 图像合并
 */
public class ImageMergeUtil {

	private static Logger LOGGER = LogManager.getLogger(ImageMergeUtil.class);


	/**
	 * 图像合并bytes [图片类型]
	 * @param prosPath 第一张图片路径
	 * @param consPath 第二张图片路径
	 * @return
	 */
	public static byte[] imageMergeToBytes(String prosPath, String consPath) {
		LOGGER.info("prosFile:" + prosPath + ";consFile:" + consPath);
		byte[] bytes;
		try {
			// 读取待合并的文件
			BufferedImage prosImg = ImageIO.read(new File(prosPath));
			BufferedImage consImg = ImageIO.read(new File(consPath));

			// 图像压缩
			prosImg = resize(prosImg, 1000, 1000,true);
			consImg = resize(consImg, 1000, 1000,true);

			// 合并后图像
			BufferedImage mergeImg = mergeImage(prosImg, consImg, false);

			// 压缩 后大概100K-300K
			mergeImg = resize(mergeImg, 1000, 1000,false);

			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ImageIO.write(mergeImg, "jpg", baos);
			bytes = baos.toByteArray();

			baos.close();
		} catch (IOException e) {
			LOGGER.error("[图像合并bytes]异常",e);
			throw new BizException(e.getMessage(),e);
		}
		return bytes;
	}

	/**
	 * 图像合并bytes [.dat类型]
	 * @param prosPath 第一张图片路径
	 * @param consPath 第二张图片路径
	 * @return
	 */
	public static byte[] imageMergeToBytes2(String prosPath, String consPath)
			throws EsServiceException {
		LOGGER.info("prosPath:" + prosPath + ";consPath:" + consPath);
		// 读取待合并的文件
		BufferedImage bi1 = null;
		BufferedImage bi2 = null;
		// 调用mergeImage方法获得合并后的图像
		BufferedImage destImg = null;
		String imgStr = "";
		byte[] bytes = null;
		try {
			// 读取图片的base64String
			String prosString = readFile2String(prosPath, "");
			String consString = readFile2String(consPath, "");

			bi1 = getBufferedImage(prosString);
			bi1 = resize(bi1, 1000, 1000,true);
			bi2 = getBufferedImage(consString);
			bi2 = resize(bi2, 1000, 1000,true);
			// 合成
			destImg = mergeImage(bi1, bi2, false);
			// 压缩 后大概100K-300K
			destImg = resize(destImg, 1000, 1000,false);
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ImageIO.write(destImg, "jpg", baos);
			bytes = baos.toByteArray();
		} catch (IOException e) {
			LOGGER.error("[图像合并bytes2]异常", e);
			throw new BizException(e.getMessage(),e);
		}
		return bytes;
	}

	/**
	 * @param base64string
	 *             图片base64编码
	 * @return 读取到的缓存图像
	 * @throws IOException
	 *             路径错误或者不存在该文件时抛出IO异常
	 */
	private static BufferedImage getBufferedImage(String base64string)
			throws IOException {
		InputStream stream = BaseToInputStream(base64string);
		return ImageIO.read(stream);
	}

	private static InputStream BaseToInputStream(String base64string)
			throws IOException {
		ByteArrayInputStream stream = null;
		byte[] bytes1 = Base64.decodeBase64(base64string.getBytes());
		stream = new ByteArrayInputStream(bytes1);
		return stream;
	}

	/**
	 * @param fileName
	 * @param encoding
	 *            编码类型
	 * @return 转换后的字符串
	 */
	public static String readFile2String(String fileName, String encoding) {
		InputStreamReader reader = null;
		StringWriter writer = new StringWriter();
		try {
			File file = new File(fileName);
			if (encoding != null && !"".equals(encoding.trim())) {
				reader = new InputStreamReader(new FileInputStream(file),
						encoding);
			} else {
				reader = new InputStreamReader(new FileInputStream(file));
			}
			char[] buffer = new char[8 * 1024];
			int n = 0;
			while (-1 != (n = reader.read(buffer))) {
				writer.write(buffer, 0, n);
			}
			reader.close();
			writer.close();
		} catch (FileNotFoundException e) {
			throw new BizException(e.getMessage(),e);
		} catch (IOException e) {
			throw new BizException(e.getMessage(),e);
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					throw new BizException(e.getMessage(),e);
				}
			}
			if (writer != null) {
				try {
					writer.close();
				} catch (IOException e) {
					throw new BizException(e.getMessage(),e);
				}
			}
		}
		if (writer != null) {
			return writer.toString();
		} else {
			return null;
		}
	}

	/**
	 * 免冠照
	 * @return
	 */
	public static byte[] mgImage(String path) {
		LOGGER.info("path:" + path);
		byte[] bytes;
		try {
			// 读取待合并的文件
			BufferedImage mgImg = ImageIO.read(new File(path));

			// 图像压缩
			mgImg = resize(mgImg, 1000, 1000, true);

			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ImageIO.write(mgImg, "jpg", baos);
			bytes = baos.toByteArray();
			baos.close();
		} catch (IOException e) {
			LOGGER.error("[获取免冠照bytes]异常", e);
			throw new BizException(e.getMessage(),e);
		}
		return bytes;
	}

	/**
	 * 获取免冠照
	 * @param mgImage
	 * @return
	 */
	public static String mgImageToString(String mgImage) {
		byte[] bytes = mgImage(mgImage);
		return Base64.encodeBase64String(bytes);
	}

	/**
	 * 图像合并String [图片类型]
	 * @param prosPath 第一张图片路径
	 * @param consPath 第二张图片路径
	 * @return
	 */
	public static String imageMergeToString(String prosPath, String consPath) {
		byte[] bytes = imageMergeToBytes(prosPath, consPath);
		return Base64.encodeBase64String(bytes);
	}

	/**
	 * 图像合并String [.dat类型]
	 * @param prosPath 第一张图片路径
	 * @param consPath 第二张图片路径
	 * @return
	 */
	public static String imageMergeToString2(String prosPath, String consPath) {
		byte[] bytes;
		try {
			bytes = imageMergeToBytes2(prosPath, consPath);
		} catch (EsServiceException e) {
			LOGGER.error("[imageMergeToString2]异常", e);
			throw new BizException(e.getMessage(),e);
		}
		return Base64.encodeBase64String(bytes);
	}

	/**
	 * 压缩图片
	 */
	private static BufferedImage resize(BufferedImage source, int targetW,int targetH,boolean isRotate ) {
		// targetW,targetH分别表示目标长和宽
		int type = source.getType();
		BufferedImage target = null;
		int width = source.getWidth();
		int height = source.getHeight();
		// 图片宽度小于高度 需要 则调整 宽高 值
		if (width < height && isRotate) {
			width = height;
			height = source.getWidth();
		}

		double sx = (double) targetW / width;
		double sy = (double) targetH / height;
		// 这里想实现在targetW,targetH范围内实现等比缩放
		if (sx > sy) {
			sx = sy;
			targetW = (int) (sx * source.getWidth());
		} else {
			sy = sx;
			targetH = (int) (sy * source.getHeight());
		}
		if (type == BufferedImage.TYPE_CUSTOM) {
			ColorModel cm = source.getColorModel();
			WritableRaster raster = cm.createCompatibleWritableRaster(targetW,
					targetH);
			boolean alphaPremultiplied = cm.isAlphaPremultiplied();
			target = new BufferedImage(cm, raster, alphaPremultiplied, null);
		} else {
			target = new BufferedImage(targetW, targetH, type);
		}
		Graphics2D g = target.createGraphics();
		// smoother than exlax:
		g.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
		g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
		g.dispose();
		return target;
	}

	/**
	 * 待合并的两张图必须满足这样的前提,如果水平方向合并,则高度必须相等;如果是垂直方向合并,宽度必须相等。
	 * mergeImage方法不做判断,自己判断。
	 *
	 * @param img1
	 *            待合并的第一张图
	 * @param img2
	 *            带合并的第二张图
	 * @param isHorizontal
	 *            为true时表示水平方向合并,为false时表示垂直方向合并
	 * @return 返回合并后的BufferedImage对象
	 * @throws IOException
	 */
	private static BufferedImage mergeImage(BufferedImage img1,BufferedImage img2, boolean isHorizontal) throws IOException {
		int w1 = img1.getWidth();
		int h1 = img1.getHeight();
		int w2 = img2.getWidth();
		int h2 = img2.getHeight();

		// 从图片中读取RGB
		int[] ImageArrayOne = new int[w1 * h1];
		// 逐行扫描图像中各个像素的RGB到数组中
		ImageArrayOne = img1.getRGB(0, 0, w1, h1, ImageArrayOne, 0, w1);
		int[] ImageArrayTwo = new int[w2 * h2];
		ImageArrayTwo = img2.getRGB(0, 0, w2, h2, ImageArrayTwo, 0, w2);
		// 生成新图片
		BufferedImage destImage = null;
		if (isHorizontal) {
			// 水平方向合并
			destImage = new BufferedImage(w1 + w2, h1, BufferedImage.TYPE_INT_RGB);
			// 设置上半部分或左半部分的RGB
			destImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1);
			destImage.setRGB(w1, 0, w2, h2, ImageArrayTwo, 0, w2);
		} else { // 垂直方向合并
			destImage = new BufferedImage(w1, h1 + h2, BufferedImage.TYPE_INT_RGB);
			// 设置上半部分或左半部分的RGB
			destImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1);
			// 设置下半部分的RGB
			destImage.setRGB(0, h1, w2, h2, ImageArrayTwo, 0, w2);
		}
		return destImage;
	}

	public static void main(String[] args) throws Exception {
		byte[] imgStr = ImageMergeUtil.imageMergeToBytes("E:\\1.png", "E:\\2.png");
		ImageUploadUtil.buff2Image(imgStr,"E:\\sfz.jpg");

		System.out.println("成功..........................");
	}
}

 

就这个工具类,有需要的直接就 copy 即可,里面有异常语句直接去掉,类似这样的 

throw new BizException(e.getMessage(),e);

 

有需要的自行研究吧! 

工作中的代码记录...


打赏

已有4人打赏

LH8826的gravatar头像 shadow小影的gravatar头像 故事_sun的gravatar头像 最代码官方的gravatar头像
最近浏览
reginx100  LV1 2022年2月28日
LikL9420  LV12 2021年7月23日
1910034830 2021年7月6日
暂无贡献等级
潜水D猴子  LV2 2021年5月20日
AAA153759  LV4 2020年7月16日
wkc  LV21 2020年6月28日
Tomcat80  LV4 2020年3月6日
有人说我公主有病 2020年1月18日
暂无贡献等级
java学者wz 2019年11月30日
暂无贡献等级
栗劲松  LV2 2019年11月26日
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友