chenjiahe
2021-10-15 9fb8897cb017a185d946cae406b81217085d8bbc
提交 | 用户 | age
5c5945 1 package com.hx.util;
E 2
3 import java.awt.*;
4 import java.awt.image.BufferedImage;
db7fc9 5 import java.io.ByteArrayOutputStream;
5c5945 6 import java.io.File;
E 7 import java.io.IOException;
8 import java.text.SimpleDateFormat;
9 import java.util.*;
10 import java.util.List;
11
12 import javax.imageio.ImageIO;
13
14 import com.google.zxing.*;
15
16 import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
17 import com.google.zxing.common.BitMatrix;
18 import com.google.zxing.common.HybridBinarizer;
19 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
20
21 public class QRCodeUtil {
22
23     // 二维码颜色==黑色
24     private static final int BLACK = 0xFF000000;
25     // 二维码颜色==白色
26     private static final int WHITE = 0xFFFFFFFF;
27     // 二维码图片格式==jpg和png两种
28     private static final List<String> IMAGE_TYPE = new ArrayList<>();
29
30     static {
31         IMAGE_TYPE.add("jpg");
32         IMAGE_TYPE.add("png");
33     }
34
35     /**
db7fc9 36      * zxing方式生成二维码(返回base64)
C 37      * 注意:
38      * 1,文本生成二维码的方法独立出来,返回image流的形式,可以输出到页面
39      * 2,设置容错率为最高,一般容错率越高,图片越不清晰, 但是只有将容错率设置高一点才能兼容logo图片
40      * 3,logo图片默认占二维码图片的20%,设置太大会导致无法解析
41      *
42      * @param content  二维码包含的内容,文本或网址
43      * @param size     生成的二维码图片尺寸 可以自定义或者默认(250)
44      * @param logoPath logo的存放位置
45      */
46     public static String QRCodeCreate(String content, Integer size, String logoPath) {
47         ByteArrayOutputStream bos = null;
48         if(size == null){
49             size = 400;
50         }
51         try{
52             char[] rands = content.toCharArray();
53             //获取二维码流的形式,写入到目录文件中
54             BufferedImage image = getBufferedImage(content, size, logoPath);
55             bos = new ByteArrayOutputStream();
56             ImageIO.write(image, "JPEG", bos);
57             byte[] buf = bos.toByteArray();
c0a0c6 58             return "data:image/png;base64,"+Base64.getEncoder().encodeToString(buf);
db7fc9 59         }catch (Exception e){
C 60             e.printStackTrace();
61         }finally {
62             if(bos != null) {
63                 try {
64                     bos.close();
65                 } catch (IOException e) {
66                     e.printStackTrace();
67                 }
68                 bos = null;
69             }
70         }
71         return null;
72     }
73
74     /**
75      * zxing方式生成二维码(返回路径)
5c5945 76      * 注意:
E 77      * 1,文本生成二维码的方法独立出来,返回image流的形式,可以输出到页面
78      * 2,设置容错率为最高,一般容错率越高,图片越不清晰, 但是只有将容错率设置高一点才能兼容logo图片
79      * 3,logo图片默认占二维码图片的20%,设置太大会导致无法解析
80      *
81      * @param content  二维码包含的内容,文本或网址
82      * @param path     生成的二维码图片存放位置
83      * @param size     生成的二维码图片尺寸 可以自定义或者默认(250)
84      * @param logoPath logo的存放位置
85      * @param autoDateFolder 在存放链接上生成日期文件夹,格式是yyyyMM
86      */
87     public static String QRCodeCreate(String content, String path, Integer size, String logoPath,Boolean autoDateFolder) {
88         try {
89             Date newDate = new Date();
90             if(autoDateFolder){
91                 if(autoDateFolder){
92                     if(path.endsWith("/")){
93                         path = path+dateFormat(newDate,"yyyyMM")+"/";
94                     }else{
95                         path = path+"/"+dateFormat(newDate,"yyyyMM")+"/";
96                     }
97                 }
98             }
99
100             path = path+newDate.getTime()+".jpg";
101
102             //图片类型
103             String imageType = "jpg";
104             //获取二维码流的形式,写入到目录文件中
105             BufferedImage image = getBufferedImage(content, size, logoPath);
106             //获得随机数
107             Random random = new Random();
108             //生成二维码存放文件
109             File file = new File(path);
110             if (!file.exists()) {
111                 file.mkdirs();
112             }
113             ImageIO.write(image, imageType, file);
114         } catch (IOException e) {
115             e.printStackTrace();
116         }
117         return path;
118     }
119
120     /**
121      * 二维码流的形式,包含文本内容
122      *
123      * @param content  二维码文本内容
124      * @param size     二维码尺寸
125      * @param logoPath logo的存放位置
126      * @return
127      */
128     public static BufferedImage getBufferedImage(String content, Integer size, String logoPath) {
129         if (size == null || size <= 0) {
130             size = 250;
131         }
132         BufferedImage image = null;
133         try {
134             // 设置编码字符集
135             Map<EncodeHintType, Object> hints = new HashMap<>();
136             //设置编码
137             hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
138             //设置容错率最高
139             hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
140             hints.put(EncodeHintType.MARGIN, 1);
141             // 1、生成二维码
142             MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
143             BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, size, size, hints);
144             // 2、获取二维码宽高
145             int codeWidth = bitMatrix.getWidth();
146             int codeHeight = bitMatrix.getHeight();
147             // 3、将二维码放入缓冲流
148             image = new BufferedImage(codeWidth, codeHeight, BufferedImage.TYPE_INT_RGB);
149             for (int i = 0; i < codeWidth; i++) {
150                 for (int j = 0; j < codeHeight; j++) {
151                     // 4、循环将二维码内容定入图片
152                     image.setRGB(i, j, bitMatrix.get(i, j) ? BLACK : WHITE);
153                 }
154             }
155             //判断是否写入logo图片
156             if (logoPath != null && !"".equals(logoPath)) {
157                 File logoPic = new File(logoPath);
158                 if (logoPic.exists()) {
159                     Graphics2D g = image.createGraphics();
160                     BufferedImage logo = ImageIO.read(logoPic);
161                     int widthLogo = logo.getWidth(null) > image.getWidth() * 2 / 10 ? (image.getWidth() * 2 / 10) : logo.getWidth(null);
162                     int heightLogo = logo.getHeight(null) > image.getHeight() * 2 / 10 ? (image.getHeight() * 2 / 10) : logo.getHeight(null);
163                     int x = (image.getWidth() - widthLogo) / 2;
164                     int y = (image.getHeight() - heightLogo) / 2;
165                     // 开始绘制图片
166                     g.drawImage(logo, x, y, widthLogo, heightLogo, null);
167                     g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);
168                     //边框宽度
169                     g.setStroke(new BasicStroke(2));
170                     //边框颜色
171                     g.setColor(Color.WHITE);
172                     g.drawRect(x, y, widthLogo, heightLogo);
173                     g.dispose();
174                     logo.flush();
175                     image.flush();
176                 }
177             }
178         } catch (WriterException e) {
179             e.printStackTrace();
180         } catch (IOException e) {
181             e.printStackTrace();
182         }
183         return image;
184     }
185
186     /**
187      * 给二维码图片添加Logo
188      *
189      * @param qrPic   二维码图片
190      * @param logoPic logo图片
191      * @param path    合成后的图片存储目录
192      */
193     public static boolean zxingCodeCreate(File qrPic, File logoPic, String path) {
194         try {
195             String imageType = path.substring(path.lastIndexOf(".") + 1).toLowerCase();
196             if (!IMAGE_TYPE.contains(imageType)) {
197                 return false;
198             }
199
200             if (!qrPic.isFile() && !logoPic.isFile()) {
201                 return false;
202             }
203
204             //读取二维码图片,并构建绘图对象
205             BufferedImage image = ImageIO.read(qrPic);
206             Graphics2D g = image.createGraphics();
207             //读取Logo图片
208             BufferedImage logo = ImageIO.read(logoPic);
209             //设置logo的大小,最多20%0
210             int widthLogo = logo.getWidth(null) > image.getWidth() * 2 / 10 ? (image.getWidth() * 2 / 10) : logo.getWidth(null);
211             int heightLogo = logo.getHeight(null) > image.getHeight() * 2 / 10 ? (image.getHeight() * 2 / 10) : logo.getHeight(null);
212             // 计算图片放置位置,默认在中间
213             int x = (image.getWidth() - widthLogo) / 2;
214             int y = (image.getHeight() - heightLogo) / 2;
215             // 开始绘制图片
216             g.drawImage(logo, x, y, widthLogo, heightLogo, null);
217             g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);
218             //边框宽度
219             g.setStroke(new BasicStroke(2));
220             //边框颜色
221             g.setColor(Color.WHITE);
222             g.drawRect(x, y, widthLogo, heightLogo);
223             g.dispose();
224             logo.flush();
225             image.flush();
226             File newFile = new File(path);
227             if (!newFile.exists()) {
228                 newFile.mkdirs();
229             }
230             ImageIO.write(image, imageType, newFile);
231             return true;
232         } catch (Exception e) {
233             e.printStackTrace();
234             return false;
235         }
236     }
237
238
239     /**
240      * 二维码的解析方法
241      *
242      * @param path 二维码图片目录
243      * @return
244      */
245     public static Result zxingCodeAnalyze(String path) {
246         try {
247             MultiFormatReader formatReader = new MultiFormatReader();
248             File file = new File(path);
249             if (file.exists()) {
250                 BufferedImage image = ImageIO.read(file);
251                 LuminanceSource source = new BufferedImageLuminanceSource(image);
252                 Binarizer binarizer = new HybridBinarizer(source);
253                 BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
254                 Map hints = new HashMap();
255                 hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
256                 Result result = formatReader.decode(binaryBitmap, hints);
257                 return result;
258             }
259         } catch (IOException e) {
260             e.printStackTrace();
261         } catch (NotFoundException e) {
262             e.printStackTrace();
263         }
264         return null;
265     }
266
267     /**
268      *
269      * @param date 时间
270      * @param format 时间格式
271      * @return 返回的时间格式字符串
272      */
273     public static String dateFormat(Date  date,String format) {
274         SimpleDateFormat df = new SimpleDateFormat(format);//设置日期格式
275         return df.format(date);
276     }
277
278 }