• 基于 zxing 的二维码生成、解析


      在很多的场景下我们需要用到二维码,这里就通过google的zxing来对二维码进行实现。

    二维码生成:

    1.导入依赖:

    <dependency>
      <groupId>com.google.zxing</groupId>
      <artifactId>core</artifactId>
      <version>2.2</version>
    </dependency>
    <dependency>
      <groupId>com.google.zxing</groupId>
      <artifactId>javase</artifactId>
      <version>2.2</version>
    </dependency>

    2.编写二维码工具类,用于讲生成的二维码图片通过流的形式写到浏览器,同时支持在二维码中间添加定制图片:

    import com.google.zxing.*;
    import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
    import com.google.zxing.common.BitMatrix;
    import com.google.zxing.common.HybridBinarizer;
    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.File;
    import java.io.IOException;
    import java.util.Hashtable;
    
    import static org.apache.catalina.manager.Constants.CHARSET;
    
    public class RecodeUtil {
    
        private static final int WIDTH = 30;
        private static final int HEIGHT = 30;
    
    
        public static void creatRrCode(String contents, int width, int height, HttpServletResponse response) throws Exception {
            Hashtable hints = new Hashtable();
    
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //容错级别最高
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); //设置字符编码
            hints.put(EncodeHintType.MARGIN, 1); //二维码空白区域,最小为0也有白边,只是很小,最小是6像素左右
            try {
                BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints); // 1、读取文件转换为字节数组
                BufferedImage image = toBufferedImage(bitMatrix);
                //转换成png格式的IO流
                ImageIO.write(image, "png", response.getOutputStream());
            } catch (WriterException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * image流数据处理
         */
        public static BufferedImage toBufferedImage(BitMatrix matrix) throws Exception {
            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++) {//0xFF000000  0xFFFFFFFF
                    //https://blog.csdn.net/cgwcgw_/article/details/21155229 颜色查询
                    image.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
                }
            }
            insertImage(image,"D:/head.jpg",true,width,height);//调用insertImage函数插入图片
            return image;
        }
        /**
         * 插入内嵌图片
         * @param source
         * @param imgPath 要插入图片路径
         * @param needCompress 要插入图片的像素是否大于60
         * @throws Exception
         */
        private static void insertImage(BufferedImage source, String imgPath,
                                        boolean needCompress,int qrWidth,int qrHeight) throws Exception {
            File file = new File(imgPath);
            if(!file.exists()){
                System.err.print(""+imgPath+"路径不存在!");
                return;
            }
            Image src = ImageIO.read(new File(imgPath));
            int width = src.getWidth(null);//获得原宽度
            int height = src.getHeight(null);//获得源高度
            if(needCompress){//比较要插入的图片的宽度是否大于设定的WIDTH=30像素宽
                if(width>WIDTH){
                    width = WIDTH;
                }
                if(height>HEIGHT){//比较要插入的图片的高度是否大于设定的HEIGTH=30像素宽
                    height = HEIGHT;
                }
                Image image = src.getScaledInstance(width, height, //把image对象的getScaledInstance方法把图片缩小heightXwidth像素大小
                        Image.SCALE_SMOOTH);
                BufferedImage tag = new BufferedImage(width,height,///创建一个透明色的BufferedImage对象
                        BufferedImage.TYPE_INT_RGB);
                Graphics g = tag.getGraphics();//获得画笔
                g.drawImage(image, 0, 0, null);//绘制指定图像中当前可用的image图像,图像的左上角位于该图形上下文坐标(0,0)的 (x, y)
            }
            //开始画内嵌图片
            Graphics2D graph = source.createGraphics();
            //计算绘画坐标
            int x = (qrWidth-width)/2;
            int y = (qrHeight-height)/2;
            graph.drawImage(src, x, y, width, height, null);//内嵌坐标为(x,y)的地方
            Shape shape = new RoundRectangle2D.Float(x,y,width,width,6,6);
            graph.setStroke(new BasicStroke(3f));
            graph.draw(shape);
            graph.dispose();
        }
    
        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 hints = new Hashtable();
            hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
            result = new MultiFormatReader().decode(bitmap, hints);
            String resultStr = result.getText();
            return resultStr;
        }
    
    }

    3.提供请求控制器:

    @RestController
    public class QRCodeController {
    
        @GetMapping("/qrcode")
        public void qrcode(HttpServletRequest request, HttpServletResponse response) throws Exception {
            String content = "你是猪";
            long l = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
            content += String.valueOf(l);
            if (StringUtils.isBlank(content)) {
                System.out.println("404");
                return;
            }
            //调用工具类,生成二维码
            RecodeUtil.creatRrCode(content, 180, 180, response);   //180为图片高度和宽度
        }
    
        @PostMapping("/qrcode/parse")
        public void read(MultipartFile file) throws Exception {
            File toFile = null;
            InputStream ins = null;
            ins = file.getInputStream();
            toFile = new File(file.getOriginalFilename());
            inputStreamToFile(ins, toFile);
            ins.close();
    
            RecodeUtil.decode(toFile);
        }
    
        //获取流文件
        private static void inputStreamToFile(InputStream ins, File file) {
            try {
                OutputStream os = new FileOutputStream(file);
                int bytesRead = 0;
                byte[] buffer = new byte[8192];
                while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                    os.write(buffer, 0, bytesRead);
                }
                os.close();
                ins.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    4.通过以上的代码就完成了后端代码的编写,接下去看一下前端代码。我前端代码基于  Vue 。:

    // ......省略代码
    <button v-on:click="qrcode">二维码</button><br/>
    <img :src = "qrcodeImage" >
    <img src = "http://localhost:8889/qrcode" >
    
    export default {
      name: 'HelloWorld',
      data () {
        return {
          qrcodeImage: ''
        }
      },
      methods: {
        qrcode: function () {
          this.qrcodeImage = null
          this.$axios({
            method: 'get',
            url: '/api/qrcode',
            responseType: 'arraybuffer'
          }).then(function (res) {
            return 'data:image/png;base64,' + btoa(
              new Uint8Array(res.data)
                .reduce((data, byte) => data + String.fromCharCode(byte), '')
            )
          }).then(data => {
            this.qrcodeImage = data
          }).catch(function (err) {
            alert(err)
          })
        }
    }

    5.启动项目,不点击二维码按钮的时候只有一个固定不变的二维码。当点击二维码按钮可以看到一下效果:

      这样子就可以实现我们的二维码。

    二维码解析:

      二维码解析可以通过调用上述 /qrcode/parse 接口,这里采用 postman作为演示,我们先将上面得到的二维码截图保存:

      然后就可以得到二维码的内容了。解析的代码上面也已经给出。

  • 相关阅读:
    Apple Swift编程语言入门教程
    网络请求错误
    Mac使用大全
    MPMovieplayerController添加新控件
    ios9 新变化
    UITableView总结
    UINavigationController的简单学习
    HTML
    谓词(NSPredicate)
    NSString字符串
  • 原文地址:https://www.cnblogs.com/wuzhenzhao/p/13295245.html
Copyright © 2020-2023  润新知