1 package a;
2
3 import java.awt.BasicStroke;
4 import java.awt.Graphics;
5 import java.awt.Graphics2D;
6 import java.awt.Image;
7 import java.awt.Shape;
8 import java.awt.geom.RoundRectangle2D;
9 import java.awt.image.BufferedImage;
10 import java.io.File;
11 import java.io.OutputStream;
12 import java.util.Hashtable;
13 import java.util.Random;
14
15 import javax.imageio.ImageIO;
16
17 import com.google.zxing.BarcodeFormat;
18 import com.google.zxing.BinaryBitmap;
19 import com.google.zxing.DecodeHintType;
20 import com.google.zxing.EncodeHintType;
21 import com.google.zxing.MultiFormatReader;
22 import com.google.zxing.MultiFormatWriter;
23 import com.google.zxing.Result;
24 import com.google.zxing.common.BitMatrix;
25 import com.google.zxing.common.HybridBinarizer;
26 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
27
28 /**
29 * 二維碼工具類
30 *
31 */
32 public class QRCodeUtil {
33
34 private static final String CHARSET = "utf-8";
35 private static final String FORMAT_NAME = "JPG";
36 // 二維碼尺寸
37 private static final int QRCODE_SIZE = 300;
38 // LOGO寬度
39 private static final int WIDTH = 60;
40 // LOGO高度
41 private static final int HEIGHT = 60;
42
43 private static BufferedImage createImage(String content, String imgPath,
44 boolean needCompress) throws Exception {
45 Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
46 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);// 設置二維碼糾錯級別
47 hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
48 hints.put(EncodeHintType.MARGIN, 1);// 設置兩邊空白區域
49 // 建立比特矩陣(位矩陣)的QR碼編碼的字符串
50 BitMatrix bitMatrix = new MultiFormatWriter().encode(content,
51 BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
52 // 使BufferedImage勾畫QRCode (getWidth()獲得的 是行二維碼像素點)
53 int width = bitMatrix.getWidth();
54 int height = bitMatrix.getHeight();
55 // 開始在緩衝圖片中畫二維碼
56 BufferedImage image = new BufferedImage(width, height,
57 BufferedImage.TYPE_INT_RGB);
58 for (int x = 0; x < width; x++) {
59 for (int y = 0; y < height; y++) {
60 image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000
61 : 0xFFFFFFFF);
62 }
63 }
64 if (imgPath == null || "".equals(imgPath)) {
65 return image;
66 }
67 // 插入圖片
68 QRCodeUtil.insertImage(image, imgPath, needCompress);
69 return image;
70 }
71
72 /**
73 * 插入LOGO
74 *
75 * @param source
76 * 二維碼圖片
77 * @param imgPath
78 * LOGO圖片地址
79 * @param needCompress
80 * 是否壓縮
81 * @throws Exception
82 */
83 private static void insertImage(BufferedImage source, String imgPath,
84 boolean needCompress) throws Exception {
85 File file = new File(imgPath);
86 if (!file.exists()) {
87 System.err.println("" + imgPath + " 該文件不存在!");
88 return;
89 }
90 Image src = ImageIO.read(new File(imgPath));
91 int width = src.getWidth(null);
92 int height = src.getHeight(null);
93 if (needCompress) { // 壓縮LOGO
94 if (width > WIDTH) {
95 width = WIDTH;
96 }
97 if (height > HEIGHT) {
98 height = HEIGHT;
99 }
100 Image image = src.getScaledInstance(width, height,
101 Image.SCALE_SMOOTH);
102 BufferedImage tag = new BufferedImage(width, height,
103 BufferedImage.TYPE_INT_RGB);
104 Graphics g = tag.getGraphics();
105 g.drawImage(image, 0, 0, null); // 繪製縮小後的圖
106 g.dispose();
107 src = image;
108 }
109 // 插入LOGO
110 Graphics2D graph = source.createGraphics();
111 int x = (QRCODE_SIZE - width) / 2;
112 int y = (QRCODE_SIZE - height) / 2;
113 graph.drawImage(src, x, y, width, height, null);
114 Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
115 graph.setStroke(new BasicStroke(3f));
116 graph.draw(shape);
117 graph.dispose();
118 }
119
120 /**
121 * 生成二維碼(內嵌LOGO)
122 *
123 * @param content
124 * 內容
125 * @param imgPath
126 * LOGO地址
127 * @param destPath
128 * 存放目錄
129 * @param needCompress
130 * 是否壓縮LOGO
131 * @throws Exception
132 */
133 public static void encode(String content, String imgPath, String destPath,
134 boolean needCompress) throws Exception {
135 BufferedImage image = QRCodeUtil.createImage(content, imgPath,
136 needCompress);
137 mkdirs(destPath);
138 String file = new Random().nextInt(99999999) + ".jpg";
139 ImageIO.write(image, FORMAT_NAME, new File(destPath + "/" + file));
140 }
141
142 /**
143 * 當文件夾不存在時,mkdirs會自動建立多層目錄,區別於mkdir.(mkdir若是父目錄不存在則會拋出異常)
144 *
145 * @author
146 * @date
147 * @param destPath
148 * 存放目錄
149 */
150 public static void mkdirs(String destPath) {
151 File file = new File(destPath);
152 // 當文件夾不存在時,mkdirs會自動建立多層目錄,區別於mkdir.(mkdir若是父目錄不存在則會拋出異常)
153 if (!file.exists() && !file.isDirectory()) {
154 file.mkdirs();
155 }
156 }
157
158 /**
159 * 生成二維碼(內嵌LOGO)
160 *
161 * @param content
162 * 內容
163 * @param imgPath
164 * LOGO地址
165 * @param destPath
166 * 存儲地址
167 * @throws Exception
168 */
169 public static void encode(String content, String imgPath, String destPath)
170 throws Exception {
171 QRCodeUtil.encode(content, imgPath, destPath, false);
172 }
173
174 /**
175 * 生成二維碼
176 *
177 * @param content
178 * 內容
179 * @param destPath
180 * 存儲地址
181 * @param needCompress
182 * 是否壓縮LOGO
183 * @throws Exception
184 */
185 public static void encode(String content, String destPath,
186 boolean needCompress) throws Exception {
187 QRCodeUtil.encode(content, null, destPath, needCompress);
188 }
189
190 /**
191 * 生成二維碼
192 *
193 * @param content
194 * 內容
195 * @param destPath
196 * 存儲地址
197 * @throws Exception
198 */
199 public static void encode(String content, String destPath) throws Exception {
200 QRCodeUtil.encode(content, null, destPath, false);
201 }
202
203 /**
204 * 生成二維碼(內嵌LOGO)
205 *
206 * @param content
207 * 內容
208 * @param imgPath
209 * LOGO地址
210 * @param output
211 * 輸出流
212 * @param needCompress
213 * 是否壓縮LOGO
214 * @throws Exception
215 */
216 public static void encode(String content, String imgPath,
217 OutputStream output, boolean needCompress) throws Exception {
218 BufferedImage image = QRCodeUtil.createImage(content, imgPath,
219 needCompress);
220 ImageIO.write(image, FORMAT_NAME, output);
221 }
222
223 /**
224 * 生成二維碼
225 *
226 * @param content
227 * 內容
228 * @param output
229 * 輸出流
230 * @throws Exception
231 */
232 public static void encode(String content, OutputStream output)
233 throws Exception {
234 QRCodeUtil.encode(content, null, output, false);
235 }
236
237 /**
238 * 解析二維碼
239 *
240 * @param file
241 * 二維碼圖片
242 * @return
243 * @throws Exception
244 */
245 public static String decode(File file) throws Exception {
246 BufferedImage image;
247 image = ImageIO.read(file);
248 if (image == null) {
249 return null;
250 }
251 BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(
252 image);
253 BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
254 Result result;
255 Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
256 hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
257 result = new MultiFormatReader().decode(bitmap, hints);
258 String resultStr = result.getText();
259 return resultStr;
260 }
261
262 /**
263 * 解析二維碼
264 *
265 * @param path
266 * 二維碼圖片地址
267 * @return
268 * @throws Exception
269 */
270 public static String decode(String path) throws Exception {
271 return QRCodeUtil.decode(new File(path));
272 }
273
274 public static void main(String[] args) throws Exception {
275 String text = "https://www.hao123.com/";
276 QRCodeUtil.encode(text, "G:/新建文件夾/1/2.png", "G:/新建文件夾/1/", true);
277 }
278 }
1 package a;
2
3 import java.awt.Graphics2D;
4 import java.awt.geom.AffineTransform;
5 import java.awt.image.BufferedImage;
6
7 import com.google.zxing.LuminanceSource;
8 /**
繼承 LuminanceSource 實現解析二維碼
*/
9 public class BufferedImageLuminanceSource extends LuminanceSource {
10 private final BufferedImage image;
11 private final int left;
12 private final int top;
13
14 public BufferedImageLuminanceSource(BufferedImage image) {
15 this(image, 0, 0, image.getWidth(), image.getHeight());
16 }
17
18 public BufferedImageLuminanceSource(BufferedImage image, int left, int top,
19 int width, int height) {
20 super(width, height);
21
22 int sourceWidth = image.getWidth();
23 int sourceHeight = image.getHeight();
24 if (left + width > sourceWidth || top + height > sourceHeight) {
25 throw new IllegalArgumentException(
26 "Crop rectangle does not fit within image data.");
27 }
28
29 for (int y = top; y < top + height; y++) {
30 for (int x = left; x < left + width; x++) {
31 if ((image.getRGB(x, y) & 0xFF000000) == 0) {
32 image.setRGB(x, y, 0xFFFFFFFF); // = white
33 }
34 }
35 }
36
37 this.image = new BufferedImage(sourceWidth, sourceHeight,
38 BufferedImage.TYPE_BYTE_GRAY);
39 this.image.getGraphics().drawImage(image, 0, 0, null);
40 this.left = left;
41 this.top = top;
42 }
43
44 public byte[] getRow(int y, byte[] row) {
45 if (y < 0 || y >= getHeight()) {
46 throw new IllegalArgumentException(
47 "Requested row is outside the image: " + y);
48 }
49 int width = getWidth();
50 if (row == null || row.length < width) {
51 row = new byte[width];
52 }
53 image.getRaster().getDataElements(left, top + y, width, 1, row);
54 return row;
55 }
56
57 public byte[] getMatrix() {
58 int width = getWidth();
59 int height = getHeight();
60 int area = width * height;
61 byte[] matrix = new byte[area];
62 image.getRaster().getDataElements(left, top, width, height, matrix);
63 return matrix;
64 }
65
66 public boolean isCropSupported() {
67 return true;
68 }
69
70 public LuminanceSource crop(int left, int top, int width, int height) {
71 return new BufferedImageLuminanceSource(image, this.left + left,
72 this.top + top, width, height);
73 }
74
75 public boolean isRotateSupported() {
76 return true;
77 }
78
79 public LuminanceSource rotateCounterClockwise() {
80 int sourceWidth = image.getWidth();
81 int sourceHeight = image.getHeight();
82 AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0,
83 0.0, sourceWidth);
84 BufferedImage rotatedImage = new BufferedImage(sourceHeight,
85 sourceWidth, BufferedImage.TYPE_BYTE_GRAY);
86 Graphics2D g = rotatedImage.createGraphics();
87 g.drawImage(image, transform, null);
88 g.dispose();
89 int width = getWidth();
90 return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth
91 - (left + width), getHeight(), width);
92 }
93 }