二维码分类
线性堆叠二维码
邮政码
矩阵式二维码(常用) 通过矩形空间黑白像素不同分布进行编码。点出现是1,不出现0.比如QR Code
二维码的优点:高密度编码,信息容量大;编码范围广;容错能力强;译码可靠性高;可引入加密措施;成本低,易制作,持久耐用。
缺点:手机病毒、钓鱼网站传播渠道
注意:添加http://头才会识别为链接而不是文本
使用google的zxing
官方github
maven配置
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.3.0</version>
</dependency>
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
/**
* @author icecrea on 18-1-5
*/
public class QRCodeUtil {
private static final int width = 300;// 默认二维码宽度
private static final int height = 300;// 默认二维码高度
private static final String format = "png";// 默认二维码文件格式
private static final Map<EncodeHintType, Object> hints = new HashMap();// 二维码参数
static {
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");// 字符编码
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);// 容错等级 L、M、Q、H 其中 L 为最低, H 为最高
hints.put(EncodeHintType.MARGIN, 2);// 二维码与图片边距
}
/**
* 返回一个 BufferedImage 对象
* @param content 二维码内容
* @param width 宽
* @param height 高
*/
public static BufferedImage toBufferedImage(String content, int width, int height) throws WriterException, IOException {
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
return MatrixToImageWriter.toBufferedImage(bitMatrix);
}
/**
* 将二维码图片输出到一个流中
* @param content 二维码内容
* @param stream 输出流
* @param width 宽
* @param height 高
*/
public static void writeToStream(String content, OutputStream stream, int width, int height) throws WriterException, IOException {
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
MatrixToImageWriter.writeToStream(bitMatrix, format, stream);
}
/**
* 生成二维码图片文件
* @param content 二维码内容
* @param path 文件保存路径
* @param width 宽
* @param height 高
*/
public static void createQRCode(String content, String path, int width, int height) throws WriterException, IOException {
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
//toPath() 方法由 jdk1.7 及以上提供
MatrixToImageWriter.writeToPath(bitMatrix, format, new File(path).toPath());
}
public static void main(String[] args) throws Exception {
OutputStream outputStream=new FileOutputStream(new File("/home/icecrea/hello.png"));
QRCodeUtil.writeToStream("www.baidu.com",outputStream,width,height);
QRCodeUtil.createQRCode("www.qunar.com","/home/icecrea/qunar.png",width,height);
}
}
在spring mvc中,可以通过流的形式在显示图片,抽象出如下工具类
public class QRCodeUtil {
private static Logger logger = LoggerFactory.getLogger(QRCodeUtil.class);
// 默认二维码宽度
private static final int width = 300;
// 默认二维码高度
private static final int height = 300;
// 默认二维码文件格式
private static final String format = "png";
// 二维码参数
private static final Map<EncodeHintType, Object> hints = new HashMap();
static {
// 字符编码
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
// 容错等级 L、M、Q、H 其中 L 为最低, H 为最高
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 二维码与图片边距
hints.put(EncodeHintType.MARGIN, 2);
}
public static void generateQRCode(String url, HttpServletResponse response) throws Exception {
Preconditions.checkArgument(!Strings.isNullOrEmpty(url), "连接地址为空");
generateQRCode(url,response,height,width);
}
public static void generateQRCode(String url, HttpServletResponse response, int height, int width) throws Exception {
Preconditions.checkArgument(!Strings.isNullOrEmpty(url), "连接地址为空");
OutputStream stream = null;
try {
stream = response.getOutputStream();
BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, height, width, hints);
MatrixToImageWriter.writeToStream(bitMatrix, format, stream);
} finally {
if (stream != null) {
stream.close();
}
}
}
}
@RequestMapping("qrcode")
public void qrcode(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse){
try {
QRCodeUtil.generateQRCode("http://www.qunar.com",httpServletResponse);
} catch (Exception e) {
e.printStackTrace();
}
}
生成Logo版本
package com.sdu.util;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import static com.google.zxing.client.j2se.MatrixToImageConfig.BLACK;
import static com.google.zxing.client.j2se.MatrixToImageConfig.WHITE;
/**
* @author ligen
* @create 2018-01-09 下午9:02
*/
public class QRCodeUtil {
/**
* 默认二维码宽度
*/
private static final int width = 300;
/**
* 默认二维码高度
*/
private static final int height = 300;
/**
* 默认二维码文件格式
*/
private static final String format = "png";
/**
* 二维码参数
*/
private static final Map<EncodeHintType, Object> hints = new HashMap();
static {
// 字符编码
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
// 容错等级 L、M、Q、H 其中 L 为最低, H 为最高
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 二维码与图片边距
hints.put(EncodeHintType.MARGIN, 1);
}
public static void generateQRCode(String url, HttpServletResponse response) throws Exception {
Preconditions.checkArgument(!Strings.isNullOrEmpty(url), "连接地址为空");
generateQRCode(url,response,height,width);
}
public static void generateQRCode(String url, HttpServletResponse response, int height, int width) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(url), "连接地址为空");
try (OutputStream stream= response.getOutputStream()){
BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, height, width, hints);
// MatrixToImageWriter.writeToStream(bitMatrix, format, stream);
BufferedImage bufferedImage=toBufferedImage(bitMatrix);
bufferedImage=setMatrixLogo(bufferedImage,"http://i.ce.cn/ce/aero/201601/04/W020160104629730930933.jpg");
ImageIO.write(bufferedImage,format,stream);
} catch (Exception e){
// log.error("生成二维码失败",e);
}
}
public static BufferedImage setMatrixLogo(BufferedImage matrixImage,String logUri) throws IOException{
/**
* 读取二维码图片,并构建绘图对象
*/
Graphics2D g2 = matrixImage.createGraphics();
int matrixWidth = matrixImage.getWidth();
int matrixHeigh = matrixImage.getHeight();
/**
* 读取Logo图片
*/
BufferedImage logo = ImageIO.read(new URL(logUri));
//开始绘制图片
g2.drawImage(logo,matrixWidth/5*2,matrixHeigh/5*2, matrixWidth/5, matrixHeigh/5, null);
//绘制边框
BasicStroke stroke = new BasicStroke(5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
// 设置笔画对象
g2.setStroke(stroke);
//指定弧度的圆角矩形
RoundRectangle2D.Float round = new RoundRectangle2D.Float(matrixWidth/5*2, matrixHeigh/5*2, matrixWidth/5, matrixHeigh/5,20,20);
g2.setColor(Color.white);
// 绘制圆弧矩形
g2.draw(round);
//设置logo 有一道灰色边框
BasicStroke stroke2 = new BasicStroke(1,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
// 设置笔画对象
g2.setStroke(stroke2);
RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(matrixWidth/5*2+2, matrixHeigh/5*2+2, matrixWidth/5-4, matrixHeigh/5-4,20,20);
g2.setColor(new Color(128,128,128));
g2.draw(round2);// 绘制圆弧矩形
g2.dispose();
matrixImage.flush() ;
return matrixImage ;
}
public static BufferedImage toBufferedImage(BitMatrix matrix) {
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) ? BLACK : WHITE));
// image.setRGB(x, y, (matrix.get(x, y) ? Color.YELLOW.getRGB() : Color.CYAN.getRGB()));
}
}
return image;
}
}
参考文章:
https://www.jianshu.com/p/05e9ee773898
https://www.jianshu.com/p/7ae3b7002530