Helius
2021-06-29 5252d1396e21a16774be699a5ba1c8d39c14a22e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
package com.xzx.gc.common.utils.image;
 
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Result;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.lang3.StringUtils;
 
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Hashtable;
import java.util.Iterator;
 
public class QrCodeBaseUtils {
 
    private static final String CHARSET = "utf-8";
 
    // 二维码001尺寸
    private static final int QRCODE_SIZE = 172;
 
    // 二维码002尺寸
    private static final int QRCODES_OTHER_SIZE = 200;
 
    // LOGO宽度
    private static final int WIDTH = 50;
    // LOGO高度
    private static final int HEIGHT = 50;
 
    /**
     * 删除二维码白边
     * 
     * @param bitMatrix
     * @return
     */
    public static BitMatrix deleteWhite(BitMatrix bitMatrix) {
        int[] rec = bitMatrix.getEnclosingRectangle();
        int resWidth = rec[2] + 1;
        int resHeight = rec[3] + 1;
 
        BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
        resMatrix.clear();
        for (int i = 0; i < resWidth; i++) {
            for (int j = 0; j < resHeight; j++) {
                if (bitMatrix.get(i + rec[0], j + rec[1])) {
                    resMatrix.set(i, j);
                }
            }
        }
        return resMatrix;
    }
 
    /*
     * 插入LOGO
     * 
     * @param source 二维码图片
     * 
     * @param imgPath LOGO图片地址
     * 
     * @param needCompress 是否压缩
     * 
     * @param frame 是否去白边
     * 
     * @param type
     * 
     * @throws Exception
     */
    @SuppressWarnings("unused")
    private static void insertImage(BufferedImage source, String imgPath, boolean needCompress, boolean frame, int type)
        throws Exception {
        BufferedImage logoBufferedImage = null;
        if (StringUtils.isNotBlank(imgPath)) {
            if (imgPath.startsWith("http")) {
                logoBufferedImage = ImageIO.read(new URL(imgPath));
            } else {
                logoBufferedImage = ImageIO.read(new File(imgPath));
            }
        }
        if (logoBufferedImage == null) {
            return;
        }
        int width = 0;
        int height = 0;
        if (imgPath.endsWith("/132")) {
            width = 132;
            height = 132;
        } else {
            width = logoBufferedImage.getWidth();
            height = logoBufferedImage.getHeight();
        }
        // 压缩LOGO
        if (needCompress) {
            if (width > WIDTH) {
                width = WIDTH;
            }
            if (height > HEIGHT) {
                height = HEIGHT;
            }
            if (imgPath.startsWith("http")) {
                logoBufferedImage = Thumbnails.of(new URL(imgPath)).size(width, height).asBufferedImage();
            } else {
                logoBufferedImage = Thumbnails.of(imgPath).size(width, height).asBufferedImage();
            }
        }
        // 插入LOGO
        Graphics2D graph = source.createGraphics();
        int x = 0;
        int y = 0;
        if (frame) {
            x = (QRCODE_SIZE - width - 39) / 2;
            y = (QRCODE_SIZE - height - 39) / 2;
        } else {
            if (type == 0) {
                x = (QRCODE_SIZE - width) / 2;
                y = (QRCODE_SIZE - height) / 2;
 
            } else if (type == 1) {
                x = (QRCODES_OTHER_SIZE - width) / 2;
                y = (QRCODES_OTHER_SIZE - height) / 2;
            }
        }
        graph.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graph.drawImage(logoBufferedImage, x, y, width, height, null);
        // logoBufferedImage 是 logo对象 xy 是gs两个边的距离,width height 是 logo的大小
        Shape shape = new RoundRectangle2D.Float(x, y, width, height, 8, 8);
        // 边框
        //  默认情况下,Graphics
        // 绘图类使用的笔画属性是粗细为1个像素的正方形,而Java2D的Graphics2D类可以调用setStroke()方法设置笔画的属性,如改变线条的粗细、虚实和定义线段端点的形状、风格等
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }
 
    /**
     * 解析二维码
     * 
     * @param file
     *            二维码图片
     * @return
     * @throws Exception
     */
    public static String decode(File file) throws Exception {
        BufferedImage image;
        image = ImageIO.read(file);
        if (image == null) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result;
        Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }
 
    /**
     * 解析二维码
     * 
     * @param path
     *            二维码图片地址
     * @return
     * @throws Exception
     */
    public static String decode(String path) throws Exception {
        return decode(new File(path));
    }
 
    /**
     *
     * compressPicByQuality 压缩图片,通过压缩图片质量,保持原图大小
     *
     * @param bufferImage
     * @param quality
     *            :0-1
     * @return
     */
    public static byte[] compressPicByQuality(BufferedImage bufferImage, float quality) {
        byte[] inByte = null;
        try {
 
            if (bufferImage == null) {
                return null;
            }
            // 得到指定Format图片的writer
            // 得到迭代器
            Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpeg");
            // 得到writer
            ImageWriter writer = (ImageWriter)iter.next();
 
            // 得到指定writer的输出参数设置(ImageWriteParam )
            ImageWriteParam iwp = writer.getDefaultWriteParam();
            // 设置可否压缩
            iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            // 设置压缩质量参数
            iwp.setCompressionQuality(quality);
 
            iwp.setProgressiveMode(ImageWriteParam.MODE_DISABLED);
 
            ColorModel colorModel = ColorModel.getRGBdefault();
            // 指定压缩时使用的色彩模式
            iwp.setDestinationType(
                new javax.imageio.ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16)));
 
            // 开始打包图片,写入byte[]
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            IIOImage iIamge = new IIOImage(bufferImage, null, null);
 
            // 此处因为ImageWriter中用来接收write信息的output要求必须是ImageOutput
            // 通过ImageIo中的静态方法,得到byteArrayOutputStream的ImageOutput
            writer.setOutput(ImageIO.createImageOutputStream(byteArrayOutputStream));
            writer.write(null, iIamge, iwp);
            inByte = byteArrayOutputStream.toByteArray();
        } catch (IOException e) {
            System.out.println("write errro");
            e.printStackTrace();
        }
        return inByte;
    }
 
    /**
     * image File 转 BufferedImage 直接使用 ImageIO 可能会使图片染红。
     * 
     * @param imaPath
     * @return
     * @throws Exception
     */
    public static BufferedImage imageToBufferedImage(String imaPath) throws Exception {
        if (StringUtils.isNotBlank(imaPath)) {
            Image src = null;
            BufferedImage img = null;
            if (imaPath.startsWith("http")) {
                src = Toolkit.getDefaultToolkit().getImage(new URL(imaPath));
            } else {
                src = Toolkit.getDefaultToolkit().getImage(imaPath);
            }
            if (src != null) {
                img = toBufferedImage(src);
            }
            return img;
        } else {
            return null;
        }
    }
 
    /**
     * image File 转 BufferedImage 直接使用 ImageIO 可能会使图片染红。
     * 
     * @param url
     * @return
     * @throws Exception
     */
    public static BufferedImage imageToBufferedImage(URL url) throws Exception {
        Image src = Toolkit.getDefaultToolkit().getImage(url);
        BufferedImage img = null;
        if (src != null) {
            img = toBufferedImage(src);
        }
        return img;
    }
 
    /**
     * image File 转 BufferedImage 的依赖函数
     * 
     * @param image
     * @return
     */
    public static BufferedImage toBufferedImage(Image image) {
        if (image instanceof BufferedImage) {
            return (BufferedImage)image;
        }
        // This code ensures that all the pixels in the image are loaded
        image = new ImageIcon(image).getImage();
        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        try {
            int transparency = Transparency.OPAQUE;
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency);
        } catch (HeadlessException e) {
            // The system does not have a screen
        }
        if (bimage == null) {
            // Create a buffered image using the default color model
            int type = BufferedImage.TYPE_INT_RGB;
            bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        }
        // Copy image to buffered image
        Graphics g = bimage.createGraphics();
        // Paint the image onto the buffered image
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return bimage;
    }
 
    /*
     * 插入LOGO
     * 
     * @param source 二维码图片
     * 
     * @param imgUrl LOGOURL
     * 
     * @param needCompress 是否压缩
     * 
     * @param frame 是否去白边
     * 
     * @param type
     * 
     * @throws Exception
     */
    public static void insertImage(BufferedImage source, URL imgUrl, boolean needCompress, boolean frame,
        int qrCodeSize) throws Exception {
 
        if (qrCodeSize == 0) {
            qrCodeSize = QRCODE_SIZE;
        }
 
        BufferedImage logoBufferedImage = ImageIO.read(imgUrl);
        if (logoBufferedImage == null) {
            return;
        }
        int width = 0;
        int height = 0;
        width = logoBufferedImage.getWidth();
        height = logoBufferedImage.getHeight();
        if (needCompress) {
            if (qrCodeSize == 136) {
                if (width > 33) {
                    width = 33;
                }
                if (height > 33) {
                    height = 33;
                }
            } else {
                if (width > WIDTH) {
                    width = WIDTH;
                }
                if (height > HEIGHT) {
                    height = HEIGHT;
                }
            }
            logoBufferedImage = Thumbnails.of(imgUrl).size(width, height).asBufferedImage();
        }
        // 插入LOGO
        Graphics2D graph = source.createGraphics();
        int x = 0;
        int y = 0;
        if (frame) {
            x = (QRCODE_SIZE - width - 39) / 2;
            y = (QRCODE_SIZE - height - 39) / 2;
        } else {
            x = (qrCodeSize - width) / 2;
            y = (qrCodeSize - height) / 2;
        }
        graph.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graph.drawImage(logoBufferedImage, x, y, width, height, null);
        // logoBufferedImage 是 logo对象 xy 是gs两个边的距离,width height 是 logo的大小
        Shape shape = new RoundRectangle2D.Float(x, y, width, height, 8, 8);
        // 边框
        //  默认情况下,Graphics
        // 绘图类使用的笔画属性是粗细为1个像素的正方形,而Java2D的Graphics2D类可以调用setStroke()方法设置笔画的属性,如改变线条的粗细、虚实和定义线段端点的形状、风格等
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }
 
    /*
     * 插入LOGO
     * 
     * @param source 二维码图片
     * 
     * @param imgFile LOGO-图片(File)
     * 
     * @param needCompress 是否压缩
     * 
     * @param frame 是否去白边
     * 
     * @param type
     * 
     * @throws Exception
     */
    public static void insertImage(BufferedImage source, File imgFile, boolean needCompress, boolean frame,
        int qrCodeSize) throws Exception {
        BufferedImage logoBufferedImage = null;
        logoBufferedImage = ImageIO.read(imgFile);
        if (logoBufferedImage == null) {
            return;
        }
        int width = logoBufferedImage.getWidth();
        int height = logoBufferedImage.getHeight();
        // 压缩LOGO
        if (needCompress) {
            if (needCompress) {
                if (qrCodeSize == 136) {
                    if (width > 33) {
                        width = 33;
                    }
                    if (height > 33) {
                        height = 33;
                    }
                } else {
                    if (width > WIDTH) {
                        width = WIDTH;
                    }
                    if (height > HEIGHT) {
                        height = HEIGHT;
                    }
                }
                logoBufferedImage = Thumbnails.of(imgFile).size(width, height).asBufferedImage();
            }
        }
        // 插入LOGO
        Graphics2D graph = source.createGraphics();
        int x = 0;
        int y = 0;
        if (frame) {
            x = (QRCODE_SIZE - width - 39) / 2;
            y = (QRCODE_SIZE - height - 39) / 2;
        } else {
            if (qrCodeSize == 0) {
                qrCodeSize = QRCODE_SIZE;
            }
            x = (qrCodeSize - width) / 2;
            y = (qrCodeSize - height) / 2;
        }
        graph.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graph.drawImage(logoBufferedImage, x, y, width, height, null);
        // logoBufferedImage 是 logo对象 xy 是gs两个边的距离,width height 是 logo的大小
        Shape shape = new RoundRectangle2D.Float(x, y, width, height, 8, 8);
        // 边框
        //  默认情况下,Graphics
        // 绘图类使用的笔画属性是粗细为1个像素的正方形,而Java2D的Graphics2D类可以调用setStroke()方法设置笔画的属性,如改变线条的粗细、虚实和定义线段端点的形状、风格等
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }
}