1.导入maven依赖如下:
<!-- Java工具类包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
<version>4.0.10</version>
</dependency>
<!-- 生成二维码 -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.3.2</version>
</dependency>
hutool是一个工具类包,封装了大量java开发常用的工具类.
2.工具类:
package com.baidu.Util;
import cn.hutool.core.util.ImageUtil;
import com.google.zxing.*;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
public class QrCodeUtil {
private static final int BLACK = -16777216;
private static final int WHITE = -1;
public QrCodeUtil() {
}
public static byte[] generatePng(String content, int width, int height) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
generate(content, width, height, "png", out);
return out.toByteArray();
}
public static File generate(String content, int width, int height, File targetFile) {
BufferedImage image = generate(content, width, height);
ImageUtil.write(image, targetFile);
return targetFile;
}
public static void generate(String content, int width, int height, String imageType, OutputStream out) {
BufferedImage image = generate(content, width, height);
ImageUtil.write(image, imageType, out);
}
public static BufferedImage generate(String content, int width, int height) {
BitMatrix bitMatrix = encode(content, width, height);
return toImage(bitMatrix);
}
public static BitMatrix encode(String content, int width, int height) {
return encode(content, BarcodeFormat.QR_CODE, width, height);
}
public static BitMatrix encode(String content, BarcodeFormat format, int width, int height) {
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
HashMap<EncodeHintType, Object> hints = new HashMap();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
try {
BitMatrix bitMatrix = multiFormatWriter.encode(content, format, width, height, hints);
return bitMatrix;
} catch (WriterException var7) {
throw new QrCodeException(var7);
}
}
public static String decode(InputStream qrCodeInputstream) {
return decode((Image)ImageUtil.read(qrCodeInputstream));
}
public static String decode(File qrCodeFile) {
return decode((Image)ImageUtil.read(qrCodeFile));
}
public static String decode(Image image) {
MultiFormatReader formatReader = new MultiFormatReader();
LuminanceSource source = new BufferedImageLuminanceSource(ImageUtil.toBufferedImage(image));
Binarizer binarizer = new HybridBinarizer(source);
BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
HashMap<DecodeHintType, Object> hints = new HashMap();
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
Result result;
try {
result = formatReader.decode(binaryBitmap, hints);
} catch (NotFoundException var8) {
throw new QrCodeException(var8);
}
return result.getText();
}
public static BufferedImage toImage(BitMatrix matrix) {
int width = matrix.getWidth();
int height = matrix.getHeight();
BufferedImage image = new BufferedImage(width, height, 1);
for(int x = 0; x < width; ++x) {
for(int y = 0; y < height; ++y) {
image.setRGB(x, y, matrix.get(x, y)?-16777216:-1);
}
}
return image;
}
}
package com.baidu.Util;
import com.google.zxing.LuminanceSource;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
public final class BufferedImageLuminanceSource extends LuminanceSource {
private final BufferedImage image;
private final int left;
private final int top;
public BufferedImageLuminanceSource(BufferedImage image) {
this(image, 0, 0, image.getWidth(), image.getHeight());
}
public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {
super(width, height);
int sourceWidth = image.getWidth();
int sourceHeight = image.getHeight();
if(left + width <= sourceWidth && top + height <= sourceHeight) {
for(int y = top; y < top + height; ++y) {
for(int x = left; x < left + width; ++x) {
if((image.getRGB(x, y) & -16777216) == 0) {
image.setRGB(x, y, -1);
}
}
}
this.image = new BufferedImage(sourceWidth, sourceHeight, 10);
this.image.getGraphics().drawImage(image, 0, 0, (ImageObserver)null);
this.left = left;
this.top = top;
} else {
throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
}
}
public byte[] getRow(int y, byte[] row) {
if(y >= 0 && y < this.getHeight()) {
int width = this.getWidth();
if(row == null || row.length < width) {
row = new byte[width];
}
this.image.getRaster().getDataElements(this.left, this.top + y, width, 1, row);
return row;
} else {
throw new IllegalArgumentException("Requested row is outside the image: " + y);
}
}
public byte[] getMatrix() {
int width = this.getWidth();
int height = this.getHeight();
int area = width * height;
byte[] matrix = new byte[area];
this.image.getRaster().getDataElements(this.left, this.top, width, height, matrix);
return matrix;
}
public boolean isCropSupported() {
return true;
}
public LuminanceSource crop(int left, int top, int width, int height) {
return new BufferedImageLuminanceSource(this.image, this.left + left, this.top + top, width, height);
}
public boolean isRotateSupported() {
return true;
}
public LuminanceSource rotateCounterClockwise() {
int sourceWidth = this.image.getWidth();
int sourceHeight = this.image.getHeight();
AffineTransform transform = new AffineTransform(0.0D, -1.0D, 1.0D, 0.0D, 0.0D, (double)sourceWidth);
BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, 10);
Graphics2D g = rotatedImage.createGraphics();
g.drawImage(this.image, transform, (ImageObserver)null);
g.dispose();
int width = this.getWidth();
return new BufferedImageLuminanceSource(rotatedImage, this.top, sourceWidth - (this.left + width), this.getHeight(), width);
}
}
package com.baidu.Util;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
public class QrCodeException extends RuntimeException {
private static final long serialVersionUID = 469027218631691847L;
public QrCodeException(Throwable e) {
super(ExceptionUtil.getMessage(e), e);
}
public QrCodeException(String message) {
super(message);
}
public QrCodeException(String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params));
}
public QrCodeException(String message, Throwable throwable) {
super(message, throwable);
}
public QrCodeException(Throwable throwable, String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params), throwable);
}
}
package com.baidu.Util;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.regex.Pattern;
public final strictfp class MathUtil {
private MathUtil() {
}
// 默认运算精度
private static int DEF_SCALE = 10;
/**
* 提供数据类型转换为BigDecimal
*
* @param object 原始数据
* @return BigDecimal
*/
public static final BigDecimal bigDecimal(Object object) {
if (object == null) {
throw new NullPointerException();
}
BigDecimal result;
try {
result = new BigDecimal(String.valueOf(object).replaceAll(",", ""));
} catch (NumberFormatException e) {
throw new NumberFormatException("Please give me a numeral.Not " + object);
}
return result;
}
/**
* 提供(相对)精确的加法运算。
*
* @param num1 被加数
* @param num2 加数
* @return 两个参数的和
*/
public static final Double add(Object num1, Object num2) {
BigDecimal result = bigDecimal(num1).add(bigDecimal(num2));
return result.setScale(DEF_SCALE, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供(相对)精确的减法运算。
*
* @param num1 被减数
* @param num2 减数
* @return 两个参数的差
*/
public static final Double subtract(Object num1, Object num2) {
BigDecimal result = bigDecimal(num1).subtract(bigDecimal(num2));
return result.setScale(DEF_SCALE, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供(相对)精确的乘法运算。
*
* @param num1 被乘数
* @param num2 乘数
* @return 两个参数的积
*/
public static final Double multiply(Object num1, Object num2) {
BigDecimal result = bigDecimal(num1).multiply(bigDecimal(num2));
return result.setScale(DEF_SCALE, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精度为10位,以后的数字四舍五入。
*
* @param num1 被除数
* @param num2 除数
* @return 两个参数的商
*/
public static final Double divide(Object num1, Object num2) {
return divide(num1, num2, DEF_SCALE);
}
/**
* 提供(相对)精确的除法运算。 当发生除不尽的情况时,由scale参数指定精度,以后的数字四舍五入。
*
* @param num1 被除数
* @param num2 除数
* @param scale 表示表示需要精确到小数点以后几位。
* @return 两个参数的商
*/
public static final Double divide(Object num1, Object num2, Integer scale) {
if (scale == null) {
scale = DEF_SCALE;
}
num2 = num2 == null || Math.abs(new Double(num2.toString())) == 0 ? 1 : num2;
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal result = bigDecimal(num1).divide(bigDecimal(num2), scale, BigDecimal.ROUND_HALF_UP);
return result.doubleValue();
}
/**
* 提供精确的小数位四舍五入处理。
*
* @param num 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/
public static final Double round(Object num, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal result = bigDecimal(num).divide(bigDecimal("1"), scale, BigDecimal.ROUND_HALF_UP);
return result.doubleValue();
}
/**
* 获取start到end区间的随机数,不包含start+end
*
* @param start
* @param end
* @return
*/
public static final BigDecimal getRandom(int start, int end) {
return new BigDecimal(start + Math.random() * end);
}
/**
* 格式化
*
* @param obj
* @param pattern
* @return
*/
public static final String format(Object obj, String pattern) {
if (obj == null) {
return null;
}
if (pattern == null || "".equals(pattern)) {
pattern = "#";
}
DecimalFormat format = new DecimalFormat(pattern);
return format.format(bigDecimal(obj));
}
/** 是否数字 */
public static final boolean isNumber(Object object) {
Pattern pattern = Pattern.compile("\\d+(.\\d+)?$");
return pattern.matcher(object.toString()).matches();
}
public static final void main(String[] args) {
System.out.println(add(1.000001, 2.10));
}
QrCodeUtil是生成二维码的核心工具类,需要引入QrCodeException异常类和BufferedImageLuminanceSource资源类;MathUtil是封装的一些简单计算的工具类,主要是用来计算二维码在照片上的宽高和位置
3.代码部分:
package com.baidu.controller;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ImageUtil;
import cn.hutool.core.util.URLUtil;
import com.baidu.Util.MathUtil;
import com.baidu.Util.QrCodeUtil;
import com.baidu.entity.User;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
/**
* Created by dangsl on 2018/4/21.
*/
@RequestMapping("image")
@Controller
public class QrCodeController {
@RequestMapping(value = "getImage",method = RequestMethod.GET)
public ResponseEntity<byte[]> getImage(){
//要转化二维码的链接
User user = new User();
user.setId("960832482708553728");
user.setNickName("祭司");
String url = "http://xxxxxxxxxx/user/login.html?recommendId=" + user.getId();
//微信昵称
String userName = user.getNickName();
//最终图片宽高
int w = 520,h = 853;
//二维码高度
int codeW = MathUtil.divide(w,3).intValue();
//生成二维码
BufferedImage generateCode = QrCodeUtil.generate(url, codeW, codeW);
//获取背景图片
BufferedImage backgroundImage = ImageUtil.read(URLUtil.url("http://XXXXXXXXXXX/976295506168774656"));
//将二维码当作图片水印放置在背景图片上
BufferedImage pressImage = ImageUtil.pressImage(backgroundImage, generateCode, 0, codeW-40, 0.9f);
//将“我是 ”和微信昵称当作文字水印放置在背景图片上
BufferedImage pressText = ImageUtil.pressText(pressImage, "我是 "+userName, Color.BLACK, new Font("宋体", 0, 27), 0, codeW+112, 0.9f);
//输出结果
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageUtil.write(pressText, FileUtil.file("E:\\weixin"+"/qrcode.png")); // 保存到本地指定目录
ImageUtil.writeJpg(pressText,os);
byte[] bytes = os.toByteArray();
// 输出到前台展示
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<byte[]>(bytes, headers, HttpStatus.OK);
}
}