二维码:二维码识别

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

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

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

原文地址:https://www.cnblogs.com/bestlmc/p/11846662.html