zoukankan      html  css  js  c++  java
  • 二维码:二维码识别

    1. WEB项目实现二维码识别

    1.1. 问题

    一般实现二维码扫描都是app调用手机,或者调用微信的库即可。但是由于web项目直接调用app的库,而调用微信的扫一扫功能必须在微信上使用。因此要在web项目中实现二维码识别的话,就要自己重新搞一下了。不弄不知道,发现二维码识别涉及的东西还是蛮多的。

    1.2. 实现思路

    WEB项目上面实现二维码识别思路,前端用h5实现调用手机摄像头拍照,然后将照片上传到后端。在后端将二维码图片识别,再将相关信息返回处理。

    1.3. 前端

    1.3.1. html

     1 <!DOCTYPE html>
     2 
     3 <html>
     4 
     5 <head>
     6 
     7 <meta charset="utf-8">
     8 
     9 <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0,
    10 
    11 maximum-scale=1.0, minimum-scale=1.0">
    12 
    13 <title>二维码识别</title>
    14 
    15 <style>
    16 
    17 *{ margin: 0; padding: 0;}
    18 
    19 </style>
    20 
    21 </head>
    22 
    23 <body>
    24 
    25 <button id="Sys" type="button" class="layui-btn" style="margin-left: 22px;" >
    26 
    27 <img style="26px;" alt="扫一扫" src="/images/erweima.png">  扫一扫
    28 
    29 </button>
    30 
    31 </div>
    32 
    33 </div>
    34 
    35 <!-- </form> -->
    36 
    37 </div>
    38 
    39  
    40
    41 <input type="file" id='p_image' accept="image/*" capture='camera' style="opacity: 0"/>
    42 
    43 <img id="tempImage" src="" style="display:none;"/>
    44 
    45  
    46 
    47 <script src="/jquery/jquery-1.11.3.js"></script> <!-- 你必须先引入jQuery1.8或以上版本 -->
    48 
    49 <script type="text/javascript" src="/js/exif.js"></script>
    50 
    51 <script type="text/javascript" src="/js/sys.js"></script>
    52 
    53 </body>
    54 
    55 </html>

    1.3.2. sys.js

    上传图片需要对图片进行压缩,转化成base64字符串

      1 // 扫一扫
      2 
      3 $("#Sys").on('click', function(){
      4 
      5  $("#p_image").click();
      6 
      7 });
      8 
      9  
     10 
     11 //处理扫一扫
     12 
     13 $(function () {
     14 
     15 $("#p_image").change(function (e) {
     16 
     17 var file = e.currentTarget.files[0];
     18 
     19  
     20 
     21 //创建一个文件读取的工具类
     22 
     23 var reader = new FileReader();
     24 
     25 //这里利用了闭包的特性,来保留文件名
     26 
     27 (function (x) {
     28 
     29 reader.onload = function (e) {
     30 
     31 //调用压缩文件的方法,具体实现逻辑见下面
     32 
     33 render(this.result, x);
     34 
     35 }
     36 
     37 })(file.name);
     38 
     39 //告诉文件读取工具类读取那个文件
     40 
     41 reader.readAsDataURL(file);
     42 
     43 });
     44 
     45  
     46 
     47 });
     48 
     49  
     50 
     51 //压缩图片
     52 
     53 function render(src) {
     54 
     55 // 需要压缩的最大尺寸
     56 
     57 var MAX_SIZE = 500;
     58 
     59 //创建Image对象
     60 
     61 var image = new Image();
     62 
     63 //图片方向角
     64 
     65     var orientation = null;
     66 
     67 image.src = src;
     68 
     69 image.onload = function () {
     70 
     71 var canvas = document.createElement("canvas");
     72 
     73 //获取2d画布
     74 
     75 var ctx = canvas.getContext("2d");
     76 
     77 canvas.width = image.width;
     78 
     79 canvas.height = image.height;
     80 
     81 ctx.clearRect(0, 0, canvas.width, canvas.height);
     82 
     83 //绘制图片
     84 
     85 ctx.drawImage(image, 0, 0, image.width, image.height);
     86 
     87 //获取照片方向角属性,用户旋转控制  
     88 
     89 EXIF.getData(image, function() {
     90 
     91 EXIF.getAllTags(this);
     92 
     93 orientation = EXIF.getTag(this,'Orientation');
     94 
     95 });
     96 
     97  
     98 
     99 //通过固定的宽高比压缩
    100 
    101 //宽大于高的情况
    102 
    103 if (image.width > MAX_SIZE && image.width >= image.height) {
    104 
    105 image.height *= MAX_SIZE / image.width;
    106 
    107 image.width = MAX_SIZE;
    108 
    109 } else if (image.height > MAX_SIZE && image.height > image.width) {//宽小于高的情况
    110 
    111 image.width *= MAX_SIZE / image.height;
    112 
    113 image.height = MAX_SIZE;
    114 
    115 }
    116 
    117 canvas.width = image.width;
    118 
    119 canvas.height = image.height;
    120 
    121 ctx.clearRect(0, 0, canvas.width, canvas.height);
    122 
    123 //绘制图片
    124 
    125 ctx.drawImage(image, 0, 0, image.width, image.height);
    126 
    127 //生成base64码
    128 
    129 var base64Code = canvas.toDataURL("image/png");
    130 
    131 $("#tempImage").attr("src", base64Code);
    132 
    133 };
    134 
    135  
    136 
    137  
    138 
    139 var img = document.getElementById('tempImage');
    140 
    141 img.onload = function(){
    142 
    143 var canvas = document.createElement("canvas");
    144 
    145 //获取2d画布
    146 
    147 var ctx = canvas.getContext("2d");
    148 
    149 canvas.width = img.width;
    150 
    151 canvas.height = img.height;
    152 
    153 ctx.clearRect(0, 0, canvas.width, canvas.height);
    154 
    155 //绘制图片
    156 
    157 ctx.drawImage(img, 0, 0, img.width, img.height);
    158 
    159 //如果方向角不为1,都需要进行旋转 added by lzk  
    160 
    161 if(orientation != "" && orientation != 1){
    162 
    163 switch(orientation){
    164 
    165 case 6://需要顺时针(向左)90度旋转
    166 
    167 rotateImg(img,'left',canvas);
    168 
    169 break;
    170 
    171 case 8://需要逆时针(向右)90度旋转
    172 
    173 rotateImg(img,'right',canvas);
    174 
    175 break;
    176 
    177 case 3://需要180度旋转
    178 
    179 rotateImg(img,'right',canvas);//转两次
    180 
    181 rotateImg(img,'right',canvas);
    182 
    183 break;
    184 
    185 }
    186 
    187 }
    188 
    189 var base64Code = canvas.toDataURL("image/png");
    190 
    191 //$("#myImage1").attr("src", base64Code);
    192 
    193 //调用上传图片方法
    194 
    195 send(base64Code);
    196 
    197 }
    198 
    199  
    200 
    201 }
    202 
    203 //上传图片
    204 
    205 function send(baseData){
    206 
    207 var index = layer.load(1, {time: 15*1000}); //加载提示弹窗,并且设定最长等待15秒
    208 
    209 $.ajax({
    210 
    211 url: '/scanFile.action',
    212 
    213 type: 'post',
    214 
    215 data: {"baseData":baseData},
    216 
    217 dataType: 'json',
    218 
    219 success: function (data) {
    220 
    221 if(data.resultcode == "success"){
    222 
    223 $("#FIRMNAME").val(data["ENTERPRISENAME"]);
    224 
    225 $("#USCCODE").val(data["USCCODE"]);
    226 
    227 layer.close(index);
    228 
    229 } else {
    230 
    231 layer.msg(data["resultcontent"]);
    232 
    233 layer.close(index);
    234 
    235 }
    236 
    237 }
    238 
    239 });
    240 
    241 }
    242 
    243 //旋转图片
    244 
    245 function rotateImg(img, direction,canvas) {
    246 
    247 //最小与最大旋转方向,图片旋转4次后回到原方向
    248 
    249 var min_step = 0;
    250 
    251 var max_step = 3;
    252 
    253 if (img == null)return;
    254 
    255 //img的高度和宽度不能在img元素隐藏后获取,否则会出错
    256 
    257 var height = img.height;
    258 
    259 var width = img.width;
    260 
    261 var step = 2;
    262 
    263 if (step == null) {
    264 
    265 step = min_step;
    266 
    267 }
    268 
    269 if (direction == 'right') {
    270 
    271 step++;
    272 
    273 //旋转到原位置,即超过最大值
    274 
    275 step > max_step && (step = min_step);
    276 
    277 } else {
    278 
    279 step--;
    280 
    281 step < min_step && (step = max_step);
    282 
    283 }
    284 
    285 //旋转角度以弧度值为参数
    286 
    287 var degree = step * 90 * Math.PI / 180;
    288 
    289 var ctx = canvas.getContext('2d');
    290 
    291 switch (step) {
    292 
    293 case 0:
    294 
    295 canvas.width = width;
    296 
    297 canvas.height = height;
    298 
    299 ctx.drawImage(img, 0, 0);
    300 
    301 break;
    302 
    303 case 1:
    304 
    305 canvas.width = height;
    306 
    307 canvas.height = width;
    308 
    309 ctx.rotate(degree);    
    310 
    311 ctx.drawImage(img, 0, -height);
    312 
    313 break;
    314 
    315 case 2:
    316 
    317 canvas.width = width;
    318 
    319 canvas.height = height;
    320 
    321 ctx.rotate(degree);
    322 
    323 ctx.drawImage(img, -width, -height);
    324 
    325 break;
    326 
    327 case 3:
    328 
    329 canvas.width = height;
    330 
    331 canvas.height = width;
    332 
    333 ctx.rotate(degree);
    334 
    335 ctx.drawImage(img, -width, 0);
    336 
    337 break;
    338 
    339 }
    340 
    341 }

    1.4. 后端解析二维码

    1.4.1. java解析二维码

    使用Zxing.jar直接对二维码图片进行解析。

      1 import java.awt.image.BufferedImage;
      2 
      3 import java.io.ByteArrayOutputStream;
      4 
      5 import java.io.File;
      6 
      7 import java.io.IOException;
      8 
      9 import java.util.HashMap;
     10 
     11 import java.util.Map;
     12 
     13  
     14 
     15 import javax.imageio.ImageIO;
     16 
     17  
     18 
     19 import com.google.zxing.BarcodeFormat;
     20 
     21 import com.google.zxing.BinaryBitmap;
     22 
     23 import com.google.zxing.ChecksumException;
     24 
     25 import com.google.zxing.DecodeHintType;
     26 
     27 import com.google.zxing.EncodeHintType;
     28 
     29 import com.google.zxing.FormatException;
     30 
     31 import com.google.zxing.MultiFormatWriter;
     32 
     33 import com.google.zxing.NotFoundException;
     34 
     35 import com.google.zxing.Result;
     36 
     37 import com.google.zxing.WriterException;
     38 
     39 import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
     40 
     41 import com.google.zxing.client.j2se.MatrixToImageWriter;
     42 
     43 import com.google.zxing.common.BitMatrix;
     44 
     45 import com.google.zxing.common.HybridBinarizer;
     46 
     47 import com.google.zxing.qrcode.QRCodeReader;
     48 
     49 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
     50 
     51  
     52 
     53 /**
     54 
     55  * 二维码工具类
     56 
     57  * @author limingcheng
     58 
     59  *
     60 
     61  */
     62 
     63 public class QrCodeUtil {
     64 
     65  
     66 
     67 /**
     68 
     69  * 生成一个二维码图片
     70 
     71  * @param width
     72 
     73  * @param height
     74 
     75  * @param content
     76 
     77  * @return
     78 
     79  * @throws WriterException
     80 
     81  * @throws IOException
     82 
     83  */
     84 
     85 public static byte[] createQRCode(int width, int height, String content) throws WriterException, IOException {
     86 
     87 // 二维码基本参数设置
     88 
     89 Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
     90 
     91 hints.put(EncodeHintType.CHARACTER_SET, "utf-8");// 设置编码字符集utf-8
     92 
     93 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);// 设置纠错等级L/M/Q/H,纠错等级越高越不易识别,当前设置等级为最高等级H
     94 
     95 hints.put(EncodeHintType.MARGIN, 0);// 可设置范围为0-10,但仅四个变化0 1(2) 3(4 5 6) 7(8 9 10)
     96 
     97 // 生成图片类型为QRCode
     98 
     99 BarcodeFormat format = BarcodeFormat.QR_CODE;
    100 
    101 // 创建位矩阵对象
    102 
    103 BitMatrix bitMatrix = new MultiFormatWriter().encode(content, format, width, height, hints);
    104 
    105 // 设置位矩阵转图片的参数
    106 
    107 //        MatrixToImageConfig config = new MatrixToImageConfig(Color.black.getRGB(), Color.white.getRGB());
    108 
    109 // 位矩阵对象转流对象
    110 
    111 ByteArrayOutputStream os = new ByteArrayOutputStream();
    112 
    113 MatrixToImageWriter.writeToStream(bitMatrix, "png", os);
    114 
    115 return os.toByteArray();
    116 
    117 }
    118 
    119  
    120 
    121 /**
    122 
    123  * 解析二维码
    124 
    125  * @throws FormatException
    126 
    127  * @throws ChecksumException
    128 
    129  * @throws NotFoundException
    130 
    131  * @throws IOException
    132 
    133  */
    134 
    135 public static void parsingQrCode() throws NotFoundException, ChecksumException, FormatException, IOException {
    136 
    137 QRCodeReader formatReader = new QRCodeReader();
    138 
    139         BufferedImage image;
    140 
    141         File file = new File("E:\bestme.png");
    142 
    143         // 识别图片中的二维码内容
    144 
    145         image = ImageIO.read(file);
    146 
    147 //        image = ImageUtil.binarization(image);
    148 
    149 BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(image)));
    150 
    151  
    152 
    153 //定义二维码参数
    154 
    155 HashMap hints = new HashMap();
    156 
    157 // 解码设置编码方式为:utf-8
    158 
    159 hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
    160 
    161 // 优化精度
    162 
    163 hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
    164 
    165 //复杂模式,开启PURE_BARCODE模式
    166 
    167 // hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
    168 
    169 Result result =  formatReader.decode(binaryBitmap,hints);
    170 
    171  
    172 
    173 System.out.println("解析结果"+result.toString());
    174 
    175 System.out.println("二维码类型"+result.getBarcodeFormat());
    176 
    177 System.out.println("二维码内容"+result.getText());
    178 
    179 }
    180 
    181  
    182 
    183 public static void main(String[] args) throws WriterException, IOException, NotFoundException, ChecksumException, FormatException {
    184 
    185 parsingQrCode();
    186 
    187  
    188 
    189 // byte[] b = createQRCode(100, 100, "遇见最好的自己!");
    190 
    191 // OutputStream os = new FileOutputStream("E:\bestme.png");
    192 
    193 // os.write(b);
    194 
    195 // os.close();
    196 
    197 }
    198 
    199 }

    输出结果:

    解析结果遇见最好的自己!

    二维码类型QR_CODE

    二维码内容遇见最好的自己!

    注意:使用复杂模式会导致图片识别不了,具体原因暂没清晰。

  • 相关阅读:
    逆向笔记——PE文件相对虚拟地址(RVA)转文件偏移地址(FOA)
    逆向笔记——在PE任意一个节中添加代码
    FFT的物理意义
    Hilbert-Huang Transform: matlab 希尔伯特-黄变换: matlab实现
    交叉验证 Cross validation
    AAL template: ROI to brain lobe
    Types of intraclass correlation coefficience (ICC)
    统计:P值 & α值
    Notes: sensitivity & specificity
    Meet Github
  • 原文地址:https://www.cnblogs.com/bestlmc/p/11846662.html
Copyright © 2011-2022 走看看