版权声明 :
本文为博主原创文章,如需转载,请注明出处(https://blog.csdn.net/F1004145107/article/details/84317601)
本文包含俩部分,使用的是 java.awt.Graphics2D 类
1.生成二维码(彩色二维码,去白边)
2.将二维码、文字合成到图片上面
代码的逻辑都在注释里面了,如果有不懂的可以私信我,代码中的图片可以做测试,链接均可用
public static void main(String[] args) {
java.awt.Font font = new java.awt.Font("宋体", java.awt.Font.BOLD, 36);// 添加字体的属性设置
InputStream is = null;
try {
// 图片1
BufferedImage backImg = ImageIO.read(new URL("http://wisezhe.oss-cn-beijing.aliyuncs.com/18-11-21/87298612.jpg"));
// 图片2
String urlStr = "http://wisezhe.oss-cn-beijing.aliyuncs.com/18-11-21/59672258.jpg";
URL url = new URL(urlStr);
// 打开连接
URLConnection con = url.openConnection();
// 设置请求超时为5s
con.setConnectTimeout(5 * 1000);
// 输入流
is = con.getInputStream();
BufferedImage imageLocal = ImageIO.read(is);
// 加载用户的二维码
BufferedImage imageCode = ImageIO.read(new URL(getQrCode()));
// 创建模板
Graphics2D g = imageLocal.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 在模板上添加用户二维码(地址,左边距,上边距,图片宽度,图片高度),值都为像素
g.drawImage(imageCode, 474, 42, 170, 170, null);
g.setFont(font);
// 设置刷子颜色
g.setColor(new java.awt.Color(148, 134, 118));
// 添加文字
g.drawString("我是wise", 60, 129);
// 完成模板修改
g.dispose();
// 合成图片
imageLocal = PictureUtils.mergeImage(backImg, imageLocal, false, 0, 0);
// 将图片直接生成到桌面
File file = new File("C:\\Users\\Administrator\\Desktop\\test.jpg");
ImageIO.write(imageLocal, "jpg", file);
// 如果图片需要返回使用下列代码即可,上传图片并且返回图片url
// ByteArrayOutputStream outPutStream =3 new ByteArrayOutputStream();
// ImageIO.write(imageLocal, "jpg", outPutStream);
// String s = UploadUtils.submitImage(id + ".jpg", outPutStream.toByteArray());
// String key = "";
// BaseUpImageEntity baseUpImageEntity = JacksonUtil.readValue(s, BaseUpImageEntity.class);
// if (baseUpImageEntity != null && "0".equals(baseUpImageEntity.getHead().getRspStatusCode())) {
// key = baseUpImageEntity.getBody().getUrl();
// }
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 生成用户二维码
*
* @author wise
* @return java.lang.String
*/
private static String getQrCode() {
// 跳转链接
String content = "https://www.google.com/";
ByteArrayOutputStream baos = null;
String url = "";
try {
baos = new ByteArrayOutputStream();
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
Map hints = new HashMap();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 400, 400, hints);
// 去掉二维码的白边
bitMatrix = updateBit(bitMatrix, 0);
// 生成彩色二维码
BufferedImage bufferedImage = toBufferedImage(bitMatrix);
ByteArrayOutputStream outPutStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpg", outPutStream);
String json = UploadUtils.submitImage("xxxxxx.jpg", outPutStream.toByteArray());
// 如不需生成彩色二维码直接使用下面被注释掉的代码即可
// MatrixToImageWriter.writeToStream(bitMatrix, "jpg", baos);
// String json = UploadUtils.submitImage(id + uid + ".jpg", baos.toByteArray());
BaseUpImageEntity baseUpImageEntity = JacksonUtil.readValue(json, BaseUpImageEntity.class);
if (baseUpImageEntity != null && "0".equals(baseUpImageEntity.getHead().getRspStatusCode())) {
url = baseUpImageEntity.getBody().getUrl();
}
return url;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (baos != null) {
baos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
/**
* 去掉二维码的白边
*
* @author wise
* @param matrix
* @return com.google.zxing.common.BitMatrix
*/
public static BitMatrix updateBit(BitMatrix matrix, int margin) {
int tempM = margin * 2;
// 获取二维码图案的属性
int[] rec = matrix.getEnclosingRectangle();
int resWidth = rec[2] + tempM;
int resHeight = rec[3] + tempM;
// 按照自定义边框生成新的BitMatrix
BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
resMatrix.clear();
// 循环,将二维码图案绘制到新的bitMatrix中
for (int i = margin; i < resWidth - margin; i++) {
for (int j = margin; j < resHeight - margin; j++) {
if (matrix.get(i - margin + rec[0], j - margin + rec[1])) {
resMatrix.set(i, j);
}
}
}
return resMatrix;
}
/**
* 生成彩色二维码
*
* @author wise
* @param matrix
* @return java.awt.image.BufferedImage
*/
public static BufferedImage toBufferedImage(BitMatrix matrix) {
// 背景颜色 RGB:242,241,236
Integer backColor = 0xF2F1EC;//十六进制
// 二维码颜色 RGB:148,134,118
Integer qrCodeColor = 0x948676;//
int width = matrix.getWidth();
int height = matrix.getHeight();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, matrix.get(x, y) ? qrCodeColor : backColor);
}
}
return image;
}
俩张图片进行合成的工具类源码
package com.shengya.service.utils;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
/**
* @author wise
*/
public class PictureUtils {
/**
* @param fileUrl 文件绝对路径或相对路径
* @return 读取到的缓存图像
* @throws IOException 路径错误或者不存在该文件时抛出IO异常
*/
public static BufferedImage getBufferedImage(String fileUrl) throws IOException {
File f = new File(fileUrl);
return ImageIO.read(f);
}
/**
* @param savedImg 待保存的图像
* @param saveDir 保存的目录
* @param fileName 保存的文件名,必须带后缀,比如 "beauty.jpg"
* @param format 文件格式:jpg、png或者bmp
* @return
*/
public static boolean saveImage(BufferedImage savedImg, String saveDir, String fileName, String format) {
boolean flag = false;
// 先检查保存的图片格式是否正确
String[] legalFormats = {"jpg", "JPG", "png", "PNG", "bmp", "BMP"};
int i = 0;
for (i = 0; i < legalFormats.length; i++) {
if (format.equals(legalFormats[i])) {
break;
}
}
if (i == legalFormats.length) { // 图片格式不支持
System.out.println("不是保存所支持的图片格式!");
return false;
}
// 再检查文件后缀和保存的格式是否一致
String postfix = fileName.substring(fileName.lastIndexOf('.') + 1);
if (!postfix.equalsIgnoreCase(format)) {
System.out.println("待保存文件后缀和保存的格式不一致!");
return false;
}
String fileUrl = saveDir + fileName;
File file = new File(fileUrl);
try {
flag = ImageIO.write(savedImg, format, file);
} catch (IOException e) {
e.printStackTrace();
}
return flag;
}
/**
* 待合并的两张图必须满足这样的前提,如果水平方向合并,则高度必须相等;如果是垂直方向合并,宽度必须相等。
* mergeImage方法不做判断,自己判断。
*
* @param img1 待合并的第一张图
* @param img2 带合并的第二张图
* @param isHorizontal 为true时表示水平方向合并,为false时表示垂直方向合并
* @return 返回合并后的BufferedImage对象
* @throws IOException
*/
public static BufferedImage mergeImage(BufferedImage img1, BufferedImage img2, boolean isHorizontal, int startX, int startY) 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];
ImageArrayOne = img1.getRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 逐行扫描图像中各个像素的RGB到数组中
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, h1, BufferedImage.TYPE_INT_RGB);
DestImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
DestImage.setRGB(startX, startY, w2, h2, ImageArrayTwo, 0, w2); // 设置下半部分的RGB
} else { // 垂直方向合并
DestImage = new BufferedImage(w1, h1 + h2, BufferedImage.TYPE_INT_RGB);
DestImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
DestImage.setRGB(0, h1, w2, h2, ImageArrayTwo, 0, w2); // 设置下半部分的RGB
}
return DestImage;
}
}
在只用工具类时可能会报java.lang.ArrayIndexOutOfBoundsException: Coordinate out of bounds!异常,原因是俩张图片的尺寸问题,如果进行垂直合成就必须保证俩张图片的宽度像素是一样,水平合成需保证高度像素是一样