精华内容
下载资源
问答
  • uniapp中应用H5自定义二维码扫码界面

    千次阅读 2020-09-10 15:48:17
    uniapp中应用H5自定义二维码扫码界面最终效果pages配置组件代码 最终效果 pages配置 { "path": "components/barcode/scan-page", "style": { "navigationBarTitleText": "扫一扫" } } 组件代码 <template&...

    uniapp中应用H5自定义二维码扫码界面

    最终效果

    效果图

    pages配置

    {
    	"path": "components/barcode/scan-page",
    	"style": {
    		"navigationBarTitleText": "扫一扫"
    	}
    }
    

    组件代码

    <template>
    
    	<view>
    		<!-- 扫码页面 -->
    		<!-- #ifndef APP-PLUS -->
    		<view class="wrap">
    			<view class="u-tips-color">
    				请在app中打开
    			</view>
    		</view>
    		<!-- #endif -->
    	</view>
    </template>
    
    <script>
    	export default {
    		data() {
    			return {
    				barcode: null,
    				flash: false,
    				tip: '将二维码放入框中,即可自动扫描',
    			}
    		},
    		onShow() {
    			// 页面展示时,重新启动扫描检测
    			if (this.barcode) {
    				this.barcode.start()
    			}
    		},
    		onLoad(params) {
    			const {
    				tip
    			} = params
    			if (tip) {
    				this.tip = tip
    			}
    			// #ifdef APP-PLUS
    			plus.navigator.setFullscreen(true); //全屏
    			let currentWebview = this.$scope.$getAppWebview();
    			this.createBarcode(currentWebview)
    			this.createTipInfoView(currentWebview)
    			this.createFlashBarView(currentWebview)
    			// #endif
    		},
    		mounted() {
    
    		},
    		methods: {
    			/**
    			 * 创建二维码
    			 * @param {Object} currentWebview
    			 */
    			createBarcode(currentWebview) {
    				if (!this.barcode) {
    					this.barcode = plus.barcode.create('barcode', [plus.barcode.QR], {
    						top: `0px`,
    						left: '0px',
    						height: `100%`,
    						width: '100%',
    						position: 'absolute',
    						background: '#FFCC00',
    						frameColor: '#FFCC33',
    						scanbarColor: '#FFCC33',
    					});
    					this.barcode.onmarked = this.onmarked;
    					this.barcode.setFlash(this.flash);
    					//此处未演示扫码成功回调的地址设置,实际请参考HTML5Plus API自行处理  
    					//注意扫码区域需为正方形,否则影响扫码识别率  
    					currentWebview.append(this.barcode);
    				}
    				this.barcode.start()
    			},
    
    			/**
    			 * 创建提示信息
    			 * @param {Object} currentWebview
    			 */
    			createTipInfoView(currentWebview) {
    				const content = new plus.nativeObj.View('content', {
    						top: '0px',
    						left: '0px',
    						height: '100%',
    						width: '100%'
    					},
    					[{
    						tag: 'font',
    						id: 'scanTips',
    						text: this.tip,
    						textStyles: {
    							size: '14px',
    							color: '#ffffff',
    							whiteSpace: 'normal'
    						},
    						position: {
    							top: '90px',
    							left: '10%',
    							width: '80%',
    							height: 'wrap_content'
    						}
    					}]);
    				currentWebview.append(content);
    
    			},
    			// 创建 开关灯按钮
    			createFlashBarView(currentWebview) {
    
    				const openImg = this.crtFlashImg('static/yellow-scanBar.png')
    				const closeImg = this.crtFlashImg('static/scanBar.png')
    				const scanBarVew = new plus.nativeObj.View('scanBarVew', {
    						top: '65%',
    						left: '40%',
    						height: '10%',
    						width: '20%',
    					},
    					closeImg);
    				scanBarVew.interceptTouchEvent(true);
    
    				currentWebview.append(scanBarVew);
    
    				scanBarVew.addEventListener("click", (e) => { //点亮手电筒
    					this.flash = !this.flash;
    					if (this.flash) {
    						scanBarVew.draw(openImg);
    					} else {
    						scanBarVew.draw(closeImg)
    					}
    					if (this.barcode) {
    						this.barcode.setFlash(this.flash);
    					}
    				}, false)
    			},
    			crtFlashImg(imgsrc) {
    				return [{
    					tag: 'img',
    					id: 'scanBar',
    					src: imgsrc,
    					position: {
    						width: '28%',
    						left: '36%',
    						height: '30%'
    					}
    				}, {
    					tag: 'font',
    					id: 'font',
    					text: '轻触照亮',
    					textStyles: {
    						size: '10px',
    						color: '#ffffff'
    					},
    					position: {
    						width: '80%',
    						left: '10%'
    					}
    				}]
    			},
    			// 扫码成功回调
    			onmarked(type, result) {
    				console.log('条码类型:' + type);
    				console.log('条码内容:' + result);
    				// 业务代码
    				// 核对扫描结果
    				// 判断是否是正确的格式
    				// 不正确则跳转到 错误页面
    					
    			}
    
    		}
    	}
    </script>
    
    <style scoped>
    	.wrap {
    		height: calc(100vh);
    		/* #ifdef H5 */
    		height: calc(100vh - var(--window-top));
    		/* #endif */
    		display: flex;
    		flex-direction: column;
    		justify-content: center;
    		align-items: center;
    	}
    </style>
    
    

    参考资料
    h5 barcode

    展开全文
  • 二维码扫码优化

    千次阅读 2017-10-20 15:21:45
    1. 二维码扫码库介绍 二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示更多的数据类型。 二维条码/二维码(2-...

    1. 二维码扫码库介绍

    二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示更多的数据类型。

    二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的;在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理:它具有条码技术的一些共性:每种码制有其特定的字符集;每个字符占有一定的宽度;具有一定的校验功能等。同时还具有对不同行的信息自动识别功能、及处理图形旋转变化点。

    目前市面上的 主流的二维码解析库主要有ZxingZbar

    Zxing是一个开源Java类库用于解析多种格式的1D/2D条形码,能够对QR编码、Data Matrix、UPC的1D条形码进行解码。其提供了多种平台下的客户端包括:J2ME、J2SE和Android等。目前在android 手机上应用广泛。

    Zbar用C/C++实现,Zbar 可以直接扫码二维码和条码,在iphone上应用广泛。

    文本主要探讨Zxing的优化,提高扫码速度与效率。

    2. 解码优化

    2.1. 减少解码格式

    zxing默认支持15种格式,支持格式有QR Code、Aztec、Code 128、Code 39、EAN-8 等等。然后我们在实际中用不到这么多解码样式,我们常见的二维码格式是QR Code,一维码格式为Code 128, 如果无特殊要求,这两种格式就能满足一般的条码与二维码的需求。 在解码过程中减少一种解码,就会减少解析时间,提高解码速度。

    所以我们在实践过程中可以根据实际减少解码样式,提高解码速度,如果app实际只有二维码扫码,甚至可以只保留QR Code这一种解码格式。

    Zxing 我们可以修改DecodeFormatManager 及DecodeThread这两个类减少解码种类。

      static {
            PRODUCT_FORMATS = EnumSet.of(BarcodeFormat.UPC_A, BarcodeFormat.UPC_E, BarcodeFormat.EAN_13,
                    BarcodeFormat.EAN_8, BarcodeFormat.RSS_14, BarcodeFormat.RSS_EXPANDED);
            INDUSTRIAL_FORMATS = EnumSet.of(BarcodeFormat.CODE_39, BarcodeFormat.CODE_93, BarcodeFormat
                    .CODE_128, BarcodeFormat.ITF, BarcodeFormat.CODABAR);
            //注释掉一维码解码格式,减少解码耗时,提高速度
            //   ONE_D_FORMATS = EnumSet.copyOf(PRODUCT_FORMATS);
            //   ONE_D_FORMATS.addAll(INDUSTRIAL_FORMATS);
    
            ONE_D_FORMATS = EnumSet.of(BarcodeFormat.CODE_128);
    
            QR_CODE_FORMATS = EnumSet.of(BarcodeFormat.QR_CODE);
        }

        public DecodeThread(CaptureActivity activity, int decodeMode) {
    
            this.activity = activity;
            handlerInitLatch = new CountDownLatch(1);
    
            hints = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);
    
            Collection<BarcodeFormat> decodeFormats = new ArrayList<BarcodeFormat>();
            //移除了所有与BarcodeFormat.CODE_128,二维码,不相关的格式
    //        decodeFormats.addAll(EnumSet.of(BarcodeFormat.AZTEC));
    //        decodeFormats.addAll(EnumSet.of(BarcodeFormat.PDF_417));
            ......
        }

    2.2. 解码算法优化

    二维码的解码算法主要分两部分,第一部分是二值化,第二部分是提取码值。第二部分又分为1.寻找定位符,2.寻找校正符,3.转换矩阵。我们可以对各个过程进行优化。

    zxing中读取条码主要涉及4个类,分别是LuminanceSource、Binarizer、BinaryBitmap和MultiFormatReader。第1、2和4是抽象类,根据对象的不同有不同的具体实现。LuminanceSource类用于存放图片数据,binarizer用于二值化图片,BinaryBitmap用于存放二值化图片,MultiFormatReader用于解码。

    目前我们在Zxing我们能看到HybridBinarizer及GlobalHistogramBinarizer,HybridBinarizer继承自GlobalHistogramBinarizer,在其基础上做了功能改进。这两个类都是Binarizer的实现类,都是基于二值化,将图片的色域变成黑白两个颜色,然后提取图形中的二维码矩阵。

    官网上介绍GlobalHistogramBinarizer算法适合低端设备,对手机CPU和内存要求不高。但它选择了全部的黑点来计算,因此无法处理阴影和渐变这两种情况。HybridBinarizer的算法在执行效率上要慢于GlobalHistogramBinarizer算法,但识别相对更加有效,它专门以白色为背景的连续黑块二维码图像解析而设计,也更适合来解析更具有严重阴影和渐变的二维码图像。

    zxing项目官方默认使用的是HybridBinarizer二值化方法。然而目前的大部分二维码都是黑色二维码,白色背景的。不管是二维码扫描还是二维码图像识别,使用GlobalHistogramBinarizer算法的效果要稍微比HybridBinarizer好一些,识别的速度更快,对低分辨的图像识别精度更高。
    可以在DecodeHandler 中更改算法

     DecodeHandler.java:
    private void decode(byte[] data, int width, int height) {
        ......
        //you can use HybridBinarizer or GlobalHistogramBinarizer
        //but in most of situations HybridBinarizer is shit
        BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
        ......
    }

    当然图像识别领域肯定有更牛逼的的算法存在,各位大牛可以可以持续改进。

    顺便提下,微信扫码使用了自家开发的QBar引擎,并导入了预判算法,在识别条码之前会过滤无码图像,只识别有意义的内容——二维码和条形码。整个扫码预判模块位于核心识别引擎之前,不再需要对输入的视频中的每一帧图像进行检测识别,能实现快速过滤大量无码图像,减少后续不必要的定位和识别对扫码客户端造成的阻塞,使响应更加及时,增加扫码过程中的流畅度,而这就是微信扫码快速的关键原因。期望能开源代码,让我们能学习下。

    2.3. 减少解码数据

    现在的手机拍照的照片像素都很高,目前市场上好一点手机像素都上千万,拍摄一张照片的就十几M, 这个大的数据量对解码很有压力,我们在开发过程有必要采取措施减少解码数据量。

    官方为了减少解码的数据,提高解码效率和速度,利用扫码区域范围来裁剪裁剪无用区域,减少解码数据。我们在开发过程可以调整好扫码区域,减少解码的数据量。

    2.4 Zbar 与Zxing融合

    目前Zxing官方开放全部源代码,用户可以根据自己的需求,灵活的改造优化。然后条形码扫码上就不尽人意,在某些手机上死活识别不出来,而且当条形码与扫描方向成一定角度,也很难扫出结果。而Zbar库在条形码上相对Zxing来说好得多了。所以有人结合Zxing二维码算法和Zbar条形码算法,提高扫码速度。可参见https://github.com/heiBin/QrCodeScanner

    3. 优化相机设置

    二维码扫描解码除了上述因素外,还有一个重大的相关因素就是相机设置方面的。如果我们预览的图片模糊、或者二维码拉伸、图片过小、图片旋转或者扭曲等,都会导致很难定位到二维码,解析二维码困难。

    3.1 选择最佳预览尺寸/图片尺寸

    如果手机摄像头生成的预览图片宽高比和手机屏幕像素宽高比(准确地说是和相机预览屏幕宽高比)不一样的话,投影的结果肯定就是图片被拉伸。现在基本上每个摄像头支持好几种不同的预览尺寸(parameters.getSupportedPreviewSizes()),我们可以根据屏幕尺寸来选择相机最适合的预览尺寸,当然如果相机支持的预览尺寸与屏幕尺寸一样更好,否则就找到宽高比相同,尺寸最为接近的。代码如下:

                     .....
         Camera.Size   mCameraResolution = findCloselySize(displayMetrics.widthPixels, displayMetrics.heightPixels,
                    parameters.getSupportedPreviewSizes());
                    ......
    
         Camera.Parameters parameters = camera.getParameters();
         parameters.setPreviewSize(mCameraResolution.width, mCameraResolution.height);
    
        /**
         * 通过对比得到与宽高比最接近的尺寸(如果有相同尺寸,优先选择)
         *
         * @param surfaceWidth  需要被进行对比的原宽
         * @param surfaceHeight 需要被进行对比的原高
         * @param preSizeList   需要对比的预览尺寸列表
         * @return 得到与原宽高比例最接近的尺寸
         */
        protected Camera.Size findCloselySize(int surfaceWidth, int surfaceHeight, List<Camera.Size> preSizeList) {
            Collections.sort(preSizeList, new SizeComparator(surfaceWidth, surfaceHeight));
            return preSizeList.get(0);
        }
    
      /**
         * 预览尺寸与给定的宽高尺寸比较器。首先比较宽高的比例,在宽高比相同的情况下,根据宽和高的最小差进行比较。
         */
        private static class SizeComparator implements Comparator<Camera.Size> {
    
            private final int width;
            private final int height;
            private final float ratio;
    
            SizeComparator(int width, int height) {
                if (width < height) {
                    this.width = height;
                    this.height = width;
                } else {
                    this.width = width;
                    this.height = height;
                }
                this.ratio = (float) this.height / this.width;
            }
    
            @Override
            public int compare(Camera.Size size1, Camera.Size size2) {
                int width1 = size1.width;
                int height1 = size1.height;
                int width2 = size2.width;
                int height2 = size2.height;
    
                float ratio1 = Math.abs((float) height1 / width1 - ratio);
                float ratio2 = Math.abs((float) height2 / width2 - ratio);
                int result = Float.compare(ratio1, ratio2);
                if (result != 0) {
                    return result;
                } else {
                    int minGap1 = Math.abs(width - width1) + Math.abs(height - height1);
                    int minGap2 = Math.abs(width - width2) + Math.abs(height - height2);
                    return minGap1 - minGap2;
                }
            }
        }

    同样相机的图片尺寸参数设置类似,利用相机支持的图片尺寸parameters.getSupportedPictureSizes() 与预览尺寸,找到最接近的尺寸,然后设置相机的最适合的图片尺寸parameters.setPictureSize()

    3.2 设置适合的放大倍数

    当我们对准二维码时候发现,相机离二维码比较远时,预览的二维码比较小;当相机靠近时,预览的二维码比较大。当我们的二维码过小时,发现条码很难扫出来。另外测试发现每个手机的放大倍数不是都是相同的,这可能与各个手机的信号相关。如果直接设置为一个固定值,这可能会在某些手机上过度放大,某些手机上放大的倍数不够。索性相机的参数设定里给我们提供了最大的放大倍数值,通过取放大倍数值的N分之一作为当前的放大倍数,就完美地解决了手机的适配问题。

    如果应用使用过程中,扫码二维码比较远时,有必要将放大倍数设置稍微大些,笔者app 在智能眼镜上使用,距离要扫码的二维码比较远,就是这种情况。

        private static final int TEN_DESIRED_ZOOM = 27;
    
        private void setZoom(Camera.Parameters parameters) {
    
            String zoomSupportedString = parameters.get("zoom-supported");
            if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) {
                return;
            }
    
            int tenDesiredZoom = TEN_DESIRED_ZOOM;
    
            String maxZoomString = parameters.get("max-zoom");
            if (maxZoomString != null) {
                try {
                    int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString));
                    if (tenDesiredZoom > tenMaxZoom) {
                        tenDesiredZoom = tenMaxZoom;
                    }
                } catch (NumberFormatException nfe) {
                    Log.e(TAG, "Bad max-zoom: " + maxZoomString);
                }
            }
    
            String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max");
            if (takingPictureZoomMaxString != null) {
                try {
                    int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString);
                    if (tenDesiredZoom > tenMaxZoom) {
                        tenDesiredZoom = tenMaxZoom;
                    }
                } catch (NumberFormatException nfe) {
                    Log.e(TAG, "Bad taking-picture-zoom-max: " + takingPictureZoomMaxString);
                }
            }
    
            String motZoomValuesString = parameters.get("mot-zoom-values");
            if (motZoomValuesString != null) {
                tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom);
            }
    
            String motZoomStepString = parameters.get("mot-zoom-step");
            if (motZoomStepString != null) {
                try {
                    double motZoomStep = Double.parseDouble(motZoomStepString.trim());
                    int tenZoomStep = (int) (10.0 * motZoomStep);
                    if (tenZoomStep > 1) {
                        tenDesiredZoom -= tenDesiredZoom % tenZoomStep;
                    }
                } catch (NumberFormatException nfe) {
                    // continue
                }
            }
    
            // Set zoom. This helps encourage the user to pull back.
            // Some devices like the Behold have a zoom parameter
            // if (maxZoomString != null || motZoomValuesString != null) {
            // parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0));
            // }
            if (parameters.isZoomSupported()) {
                Log.e(TAG, "max-zoom:" + parameters.getMaxZoom());
                Log.i("0000", "tenDesiredZoom:" + tenDesiredZoom);
                parameters.setZoom(parameters.getMaxZoom() / tenDesiredZoom);
            } else {
                Log.e(TAG, "Unsupported zoom.");
            }
    
            // Most devices, like the Hero, appear to expose this zoom parameter.
            // It takes on values like "27" which appears to mean 2.7x zoom
            // if (takingPictureZoomMaxString != null) {
            // parameters.set("taking-picture-zoom", tenDesiredZoom);
            // }
        }

    3.3 缩短聚焦时间

    Zxing 默认的聚焦间隔时间是2000毫秒。扫码是在每一次调用相机聚焦完成后触发回调取图解析的。在这里缩短聚焦时间会提高解析频率,扫码性能自然就提升了。当然也有不好的地方,提高了聚焦的频率,对手机电量的消耗自然增加了。我这里是把聚焦间隔修改成了1000毫秒,这个依据手机硬件的性能修改,不同厂家的手机对相机聚焦的处理是不同的,如果你设置的这个聚焦间隔时间小于了手机厂家默认设计的相机聚焦间隔就会导致程序的崩溃。这个设置请慎重使用。聚焦时间的调整也很简单,在AutoFocusCallback这个类里,调整AUTO_FOCUS_INTERVAL_MS这个值就可以了。

    3.4 设置自动对焦区域

    我们对焦过程发现有时经常对不准二维码,导致扫描比较慢。Android 4.0 以后我们可以通过camera.setFocusAreas设置对焦区域,提高对焦效果。

             Camera.Parameters params = camera.getParameters();
            if (parameters.getMaxNumFocusAreas() > 0) {
                List<Camera.Area> focusAreas = new ArrayList<>();
                Rect focusRect = new Rect(-100, -100, 100, 100);
                focusAreas.add(new Camera.Area(focusRect, 1000));
                parameters.setFocusAreas(focusAreas);
            }
    
            if (parameters.getMaxNumMeteringAreas() > 0) {
                List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
                Rect meteringRect = new Rect(-100, -100, 100, 100);
                meteringAreas.add(new Camera.Area(meteringRect, 1000));
                parameters.setMeteringAreas(meteringAreas);
            }

    3.5 调整合理扫描区域

    扫码时候我们经常调整手机,让扫码的二维码完全填充在扫描框里面,否则很难解析出来,而这个过程蛮花费时间的。如果我们增大扫码区域,那二维码更容易落在扫描框里面,能够缩短扫码的时间。

    官方为了减少解码的数据,提高解码效率和速度,采用了裁剪无用区域的方式。这样会带来一定的问题,整个二维码数据需要完全放到聚焦框里才有可能被识别。我们可以在DecodeHandler这个类中buildLuminanceSource(byte[],int,int)这个方法中,调整裁剪区域。

     public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
            // 扫码区域大小,可以调整扫码区域大小
            Rect rect = activity.getCropRect();
            if (rect == null) {
                return null;
            }
            // Go ahead and assume it's YUV rather than die.
            return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, rect.width(), rect
                    .height(), false);
        }

    甚至我们可以不用裁剪数据,而是采用全幅图像的数据,当然这种做法会对解码施加压力。读者可以按照自己的需求适当的调整裁剪区域。

    4. 其他优化措施

    现在市场上有很多的扫码的外设,他们使用方便,而且有专门芯片,性能强悍
    ,扫码效率很好。

    另外二维码的复杂度与里面的内容相关的,如果app自己生成二维码图片,可以考虑缩短二维码内容长度,避免生成较复杂的二维码,导致不好解析。

    demo 见:https://github.com/jinwong001/QRScanner

    参考

    展开全文
  • camera二维码扫码实例

    2018-11-19 10:02:22
    随着二维码的广泛应用,APP开发中,也越来越多的需求需要用到二维码的扫描功能,以下就针对h5+的二维码扫描功能做一些简单的介绍。
  • 二维码扫码和相册二维码提取的方法在原生系统 AVFoundation 的 SDK 中提供了摄像头设备扫描捕获和检测提取的相应方法,具体方法 code 如下: 注:如下方法需在 iOS7 系统之后,通过系统中 AVMetadataObject 提供的...

    二维码扫码和相册二维码提取的方法在原生系统 AVFoundation 的 SDK 中提供了摄像头设备扫描捕获和检测提取的相应方法,具体方法 code 如下:
    注:如下方法需在 iOS7 系统之后,通过系统中 AVMetadataObject 提供的方法,从而解析二维码

    QRCScan Github

     

    首先,通过相机摄像头扫描部分

    #pragma mark - 扫描
    - (void)beginScanning {
        //获取摄像设备
        AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        //创建输入流
        AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
        if (!input) return;
        //创建输出流
        AVCaptureMetadataOutput * output = [[AVCaptureMetadataOutput alloc]init];
        //设置代理 在主线程里刷新
        [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
        //设置有效扫描区域
        CGRect scanCrop=[self getScanCrop:_scanWindow.bounds readerViewBounds:self.view.frame];
        output.rectOfInterest = scanCrop;
        //初始化链接对象
        _session = [[AVCaptureSession alloc]init];
        //高质量采集率
        [_session setSessionPreset:AVCaptureSessionPresetHigh];
        
        [_session addInput:input];
        [_session addOutput:output];
        //设置扫码支持的编码格式(如下设置条形码和二维码兼容)
        output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode,
                                       AVMetadataObjectTypeEAN13Code,
                                       AVMetadataObjectTypeEAN8Code,
                                       AVMetadataObjectTypeCode128Code
        ];
        
        AVCaptureVideoPreviewLayer * layer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
        layer.videoGravity=AVLayerVideoGravityResizeAspectFill;
        layer.frame=self.view.layer.bounds;
        [self.view.layer insertSublayer:layer atIndex:0];
        //开始捕获
        [_session startRunning];
    }
    
    - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
        if (metadataObjects.count > 0) {
            [_session stopRunning];
            AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0];
            self.result = metadataObject.stringValue;
            [self.Args setValue:self.result forKey:@"QrCode"]; // 将结果拼装并回调
            if (self.delegate && [self.delegate respondsToSelector:@selector(QRCScanCallBack:)]) {
                [self.delegate QRCScanCallBack:self.Args];
            }
        }
    }

    其次,通过相册选择二维码图片后检测并校验提取其中的数据

    #pragma mark - Delegate
    - (void)YHCameraCallBack:(UIImage *)image {
        NSLog(@"相册回调:%@", image);
        // 初始化检测器
        CIDetector*detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy : CIDetectorAccuracyHigh }];
        // 监测到的结果数组
        NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]];
        if (features.count >=1) {
            /** 结果对象 */
            CIQRCodeFeature *feature = [features objectAtIndex:0];
            NSString *scannedRes = feature.messageString;
            [self disMiss];
            NSLog(@"二维码扫码结果:%@", scannedRes);
            [self.Args setValue:scannedRes forKey:@"QrCode"]; // 将结果拼装并回调
            if (self.delegate && [self.delegate respondsToSelector:@selector(QRCScanCallBack:)]) {
                [self.delegate QRCScanCallBack:self.Args];
            }
        } else {
            UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"提示" message:@"该图片没有包含一个二维码" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
            [alertView show];
        }
    }

    通过如上两个 code 片段即可实现对二维码的识别和提取操作,具体还有一些详细的属性和方法可以从其提供的 SDK 接口中挑选配置;

    最后,如下是一个完整的 demo 可供参考:

    #import "FYHBaseViewController.h"
    typedef void(^returnQRCScanRsultBlock)(NSString *result);
    @protocol QRCScanViewControllerDelegate <NSObject>
    
    - (void)QRCScanCallBack:(NSMutableDictionary *)Dic;
    
    @end
    @interface QRCScanViewController : FYHBaseViewController
    
    @property (nonatomic, strong) NSMutableDictionary *Args;
    @property (nonatomic, assign) id<QRCScanViewControllerDelegate>delegate;
    @property (nonatomic, copy) returnQRCScanRsultBlock QRCScanRsultBlock;
    
    - (void)setQRCScanRsultBlock:(returnQRCScanRsultBlock)QRCScanRsultBlock;
    - (returnQRCScanRsultBlock)QRCScanRsultBlock;
    
    @end
    #import "QRCScanViewController.h"
    #import <AVFoundation/AVFoundation.h>
    #import "UIView+Exttension.h"
    #import "UIImage+FYH.h"
    #import "YHCameraManager.h"
    
    @interface QRCScanViewController () <AVCaptureMetadataOutputObjectsDelegate, UIAlertViewDelegate, YHCameraManagerDelegate>
    
    @property (nonatomic, strong) AVCaptureSession *session;
    @property (nonatomic, strong) UIImageView *scanLineImageView;
    @property (nonatomic, strong) UIView *scanWindow;
    @property (nonatomic, strong) UIView *maskView;
    
    @property (nonatomic, copy) NSString *result;
    @end
    
    @implementation QRCScanViewController
    
    - (void)viewWillAppear:(BOOL)animated{
        [super viewWillAppear:animated];
    //    self.navigationController.navigationBar.hidden = YES;
    //    [self leftNavButtonType:NavLeftButtonTypeBack];
        [self basicConfig];
        [self resumeAnimation];
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self setupMaskView];
        [self setupScanWindow];
        [self beginScanning];
        [kNotificationCenter addObserver:self
                                selector:@selector(resumeAnimation)
                                    name:@"EnterForeground"
                                  object:nil];
    }
    
    - (void)viewDidDisappear:(BOOL)animated{
        [super viewDidDisappear:animated];
    //    self.navigationController.navigationBar.hidden = NO;
    //    [self.navigationController setNavigationBarHidden:YES animated:YES];
    }
    
    - (void)basicConfig {
    //    self.tabBarController.hidesBottomBarWhenPushed = YES;
    //    [self setupNavView]; // 自定义导航
        [self.navigationController setNavigationBarHidden:NO animated:YES];
        self.navigationController.navigationBar.translucent = NO;
        [self.navigationController.navigationBar setBackgroundImage:[UIImage imageWithColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.7]]
                                                      forBarMetrics:UIBarMetricsDefault];
        [self leftNavButtonType:NavButtonStyleBackWhite];
        [self settingNavRightButton];
    }
    
    - (void)settingNavRightButton {
        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
        btn.titleLabel.font = [UIFont systemFontOfSize:14.f];
        [btn setTitle:@"相册" forState:UIControlStateNormal];
        [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [btn addTarget:self action:@selector(btnClickSelPhoto:) forControlEvents:UIControlEventTouchUpInside];
        UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:btn];
        self.navigationItem.rightBarButtonItem = item;
    }
    
    - (void)btnClickSelPhoto:(UIButton *)btn {
        NSLog(@"调用系统相册");
        YHCameraManager *cameraMag = [YHCameraManager shareInstance];
        cameraMag.delegate = self;
        [cameraMag openPhotoLibraryWithController:self];
    }
    
    - (void)dealloc {
        [kNotificationCenter removeObserver:self name:@"EnterForeground" object:nil];
    }
    
    
    
    #pragma mark - 自定义导航视图 Btn(注:若不需要相册二维码识别,也可使用该方法)
    -(void)setupNavView {
        UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.width, 64)];
        bgView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
        bgView.userInteractionEnabled = YES;
        //1.返回
        UIButton *backBtn=[UIButton buttonWithType:UIButtonTypeCustom];
        backBtn.frame = CGRectMake(20, 30, 25, 25);
        [backBtn setBackgroundImage:[[UIImage imageNamed:@"navBack"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
                           forState:UIControlStateNormal];
    //    backBtn.contentMode = UIViewContentModeScaleAspectFit;
        [backBtn addTarget:self action:@selector(disMiss) forControlEvents:UIControlEventTouchUpInside];
        [bgView addSubview:backBtn];
        [self.view addSubview:bgView];
    }
    
    
    
    #pragma mark - UI
    - (void)setupMaskView {
        CGFloat Margin = 30; //
        CGFloat scanWindowH = self.view.width - 30 * 2;
    //    CGFloat scanWindowW = self.view.height - 30 * 2;
        
    //    UIView *topBackgroundView = [[UIView alloc]initWithFrame:CGRectMake(0, 64, self.view.width, 100)]; // 无系统导航版本
        UIView *topBackgroundView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.width, 100)];
        topBackgroundView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
        [self.view addSubview:topBackgroundView];
        
        UIView *leftBackgroundView = [[UIView alloc]initWithFrame:CGRectMake(0, CGRectGetMaxY(topBackgroundView.frame), Margin, scanWindowH)];
        leftBackgroundView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
        [self.view addSubview:leftBackgroundView];
        
        UIView *rightBackgroundView = [[UIView alloc]initWithFrame:CGRectMake(self.view.width - Margin, leftBackgroundView.y, leftBackgroundView.width, leftBackgroundView.height)];
        rightBackgroundView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
        [self.view addSubview:rightBackgroundView];
        
        UIView *bottmBackgroundView = [[UIView alloc]initWithFrame:CGRectMake(0, CGRectGetMaxY(rightBackgroundView.frame), self.view.width, self.view.height - CGRectGetMaxY(rightBackgroundView.frame))];
        bottmBackgroundView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
        [self.view addSubview:bottmBackgroundView];
    }
    
    
    
    #pragma mark - 设置相机 UI
    - (void)setupScanWindow {
        CGFloat kMargin = 30;
        CGFloat scanWindowH = self.view.width - kMargin * 2;
        CGFloat scanWindowW = self.view.width - kMargin * 2;
        _scanWindow = [[UIView alloc] initWithFrame:CGRectMake(kMargin, 100, scanWindowW, scanWindowH)];
        _scanWindow.clipsToBounds = YES;
        [self.view addSubview:_scanWindow];
        
        self.scanLineImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"scan_net"]];
        CGFloat buttonWH = 18;
        
        UIButton *topLeft = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, buttonWH, buttonWH)];
        [topLeft setImage:[UIImage imageNamed:@"scan_1"] forState:UIControlStateNormal];
        [_scanWindow addSubview:topLeft];
        
        UIButton *topRight = [[UIButton alloc] initWithFrame:CGRectMake(scanWindowW - buttonWH, 0, buttonWH, buttonWH)];
        [topRight setImage:[UIImage imageNamed:@"scan_2"] forState:UIControlStateNormal];
        [_scanWindow addSubview:topRight];
        
        UIButton *bottomLeft = [[UIButton alloc] initWithFrame:CGRectMake(0, scanWindowH - buttonWH, buttonWH, buttonWH)];
        [bottomLeft setImage:[UIImage imageNamed:@"scan_3"] forState:UIControlStateNormal];
        [_scanWindow addSubview:bottomLeft];
        
        UIButton *bottomRight = [[UIButton alloc] initWithFrame:CGRectMake(topRight.x, bottomLeft.y, buttonWH, buttonWH)];
        [bottomRight setImage:[UIImage imageNamed:@"scan_4"] forState:UIControlStateNormal];
        [_scanWindow addSubview:bottomRight];
        
        UILabel * tipLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_scanWindow.frame) + 20, self.view.bounds.size.width, 12)];
        tipLabel.text = @"将取景框对准二维码,即可自动扫描";
        tipLabel.textColor = [UIColor whiteColor];
        tipLabel.textAlignment = NSTextAlignmentCenter;
        tipLabel.lineBreakMode = NSLineBreakByWordWrapping;
        tipLabel.numberOfLines = 2;
        tipLabel.font=[UIFont systemFontOfSize:12];
        tipLabel.backgroundColor = [UIColor clearColor];
        [self.view addSubview:tipLabel];
    }
    
    - (void)resumeAnimation {
        CAAnimation *anim = [self.scanLineImageView.layer animationForKey:@"translationAnimation"];
        if(anim){
            // 1. 将动画的时间偏移量作为暂停时的时间点
            CFTimeInterval pauseTime = self.scanLineImageView.layer.timeOffset;
            // 2. 根据媒体时间计算出准确的启动动画时间,对之前暂停动画的时间进行修正
            CFTimeInterval beginTime = CACurrentMediaTime() - pauseTime;
            
            // 3. 要把偏移时间清零
            [self.scanLineImageView.layer setTimeOffset:0.0];
            // 4. 设置图层的开始动画时间
            [self.scanLineImageView.layer setBeginTime:beginTime];
            
            [self.scanLineImageView.layer setSpeed:1.0];
        } else {
            CGFloat scanNetImageViewH = 241;
            CGFloat scanWindowH = self.view.width - 30 * 2;
            CGFloat scanNetImageViewW = _scanWindow.width;
            
            self.scanLineImageView.frame = CGRectMake(0, -scanNetImageViewH, scanNetImageViewW, scanNetImageViewH);
            CABasicAnimation *scanNetAnimation = [CABasicAnimation animation];
            scanNetAnimation.keyPath = @"transform.translation.y";
            scanNetAnimation.byValue = @(scanWindowH);
            scanNetAnimation.duration = 1.5;
            scanNetAnimation.repeatCount = MAXFLOAT;
            [self.scanLineImageView.layer addAnimation:scanNetAnimation forKey:@"translationAnimation"];
            [_scanWindow addSubview:self.scanLineImageView];
        }
    }
    
    
    
    #pragma mark - 扫描
    - (void)beginScanning {
        //获取摄像设备
        AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        //创建输入流
        AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
        if (!input) return;
        //创建输出流
        AVCaptureMetadataOutput * output = [[AVCaptureMetadataOutput alloc]init];
        //设置代理 在主线程里刷新
        [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
        //设置有效扫描区域
        CGRect scanCrop=[self getScanCrop:_scanWindow.bounds readerViewBounds:self.view.frame];
        output.rectOfInterest = scanCrop;
        //初始化链接对象
        _session = [[AVCaptureSession alloc]init];
        //高质量采集率
        [_session setSessionPreset:AVCaptureSessionPresetHigh];
        
        [_session addInput:input];
        [_session addOutput:output];
        //设置扫码支持的编码格式(如下设置条形码和二维码兼容)
        output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode,
                                       AVMetadataObjectTypeEAN13Code,
                                       AVMetadataObjectTypeEAN8Code,
                                       AVMetadataObjectTypeCode128Code
        ];
        
        AVCaptureVideoPreviewLayer * layer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
        layer.videoGravity=AVLayerVideoGravityResizeAspectFill;
        layer.frame=self.view.layer.bounds;
        [self.view.layer insertSublayer:layer atIndex:0];
        //开始捕获
        [_session startRunning];
    }
    
    
    
    #pragma mark - 获取扫描区域的比例关系
    - (CGRect)getScanCrop:(CGRect)rect readerViewBounds:(CGRect)readerViewBounds {
        CGFloat x,y,width,height;
        x = (CGRectGetHeight(readerViewBounds)-CGRectGetHeight(rect))/2/CGRectGetHeight(readerViewBounds);
        y = (CGRectGetWidth(readerViewBounds)-CGRectGetWidth(rect))/2/CGRectGetWidth(readerViewBounds);
        width = CGRectGetHeight(rect)/CGRectGetHeight(readerViewBounds);
        height = CGRectGetWidth(rect)/CGRectGetWidth(readerViewBounds);
        
        return CGRectMake(x, y, width, height);
    }
    
    - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
        if (metadataObjects.count > 0) {
            [_session stopRunning];
            AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0];
            self.result = metadataObject.stringValue;
            [self disMiss];
            [self.Args setValue:self.result forKey:@"QrCode"];
            if (self.delegate && [self.delegate respondsToSelector:@selector(QRCScanCallBack:)]) {
                [self.delegate QRCScanCallBack:self.Args];
            }
        }
    }
    
    //- (void)setArgs:(NSMutableDictionary *)Args
    //{
    //    if (self.Args != Args)
    //    {
    //        self.Args = Args;
    //    }
    //
    //}
    
    - (void)setQRCScanRsultBlock:(returnQRCScanRsultBlock)QRCScanRsultBlock {
        if (self.QRCScanRsultBlock != QRCScanRsultBlock) {
            self.QRCScanRsultBlock = QRCScanRsultBlock;
        }
    }
    
    - (returnQRCScanRsultBlock)QRCScanRsultBlock {
        return self.QRCScanRsultBlock;
    }
    
    - (void)disMiss {
        [self.navigationController popViewControllerAnimated:YES];
    }
    
    
    
    #pragma mark - 提示框
    - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
        if (buttonIndex == 0) {
            [_session startRunning];
        } else if (buttonIndex == 1) {
            [self disMiss];
            [self.Args setValue:self.result forKey:@"QrCode"];
            if (self.delegate && [self.delegate respondsToSelector:@selector(QRCScanCallBack:)]) {
                [self.delegate QRCScanCallBack:self.Args];
            }
        }
    }
    
    
    
    #pragma mark - Delegate
    - (void)YHCameraCallBack:(UIImage *)image {
        NSLog(@"相册回调:%@", image);
        // 初始化检测器
        CIDetector*detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy : CIDetectorAccuracyHigh }];
        // 监测到的结果数组
        NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]];
        if (features.count >=1) {
            /** 结果对象 */
            CIQRCodeFeature *feature = [features objectAtIndex:0];
            NSString *scannedRes = feature.messageString;
            [self disMiss];
            NSLog(@"二维码扫码结果:%@", scannedRes);
            [self.Args setValue:scannedRes forKey:@"QrCode"];
            if (self.delegate && [self.delegate respondsToSelector:@selector(QRCScanCallBack:)]) {
                [self.delegate QRCScanCallBack:self.Args];
            }
        } else {
            UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"提示" message:@"该图片没有包含一个二维码" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
            [alertView show];
        }
    }
    
    @end

     

    拓展:
    1.实现中背景色部分应用到了 Color 转 Image 的方法具体如下:

    + (UIImage *)imageWithColor:(UIColor *)color {
        CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
        UIGraphicsBeginImageContext(rect.size);
        CGContextRef context = UIGraphicsGetCurrentContext();
        
        CGContextSetFillColorWithColor(context, [color CGColor]);
        CGContextFillRect(context, rect);
        
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        return image;
    }

    2.调用相册的功能封装成了单独的 基于 PickerController 功能模块封装相关 - iOS 类,具体方法实现如下:

    /**
     调用相册
     
     @param controller 当前 VC 控件
     */
    - (void)openPhotoLibraryWithController:(UIViewController *)controller {
        if (@available(iOS 11, *)) {
            UIScrollView.appearance.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentAutomatic;
        }
        
        if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
            UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
            imagePicker.allowsEditing = YES;
            imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
            imagePicker.delegate = self;
            
            [controller presentViewController:imagePicker animated:YES completion:^{
                NSLog(@"调用了 --- 相册");
            }];
        } else {
            [MBProgressHUD showCommonHudWithAlertString:@"无法打开相册" afterDelay:2.0 toView:controller.view];
        }
    }

     


    以上便是此次分享的全部内容,希望能对大家有所帮助!

    展开全文
  • TCPIP远程网络电子健康码扫码设备|二维码扫码门禁机HX-QR86L-IP是一款铝合金材质、带液晶显示屏,一机两用,即可做门禁读头使用,也可以做电子健康码数据采集使用。可支持静态、手机动态二维码识别、支持电子健康...

          TCPIP远程网络电子健康码扫码设备|二维码扫码门禁机HX-QR86L-IP是一款铝合金材质、带液晶显示屏,一机两用,即可做门禁读头使用,也可以做电子健康码数据采集使用。可支持静态、手机动态二维码识别、支持电子健康码识别,也可支持感应IC卡、二代证等识别,采用TCP|IP网口通讯,支持数据上传至云平台、远程服务器、数据中心,可远程实现电子健康码识别、二维码身份识别 及数据交互 。

         疫情的转播,导致人员出门不方便,而“健康码”能实时记录你的行程,比如你今天去了哪里等等都能记录到位,“电子健康码”也在每个城市上线及普及。新冠肺炎疫情防控进入关键期,按照各地的新冠肺炎疫情防控指挥部有关要求,将继续严格实行社区(小区、村组、居民点)封控管理。为提高小区、校园封闭管理水平,“电子健康码”仍然是行之有效的身份识别与健康识别的有效管理工具。 

         

         随着各地复工复学的启动,疫情防疫也进入关键期,实时动态监控学生、教职工、访客的身心健康是学校管理层面临的重中之重的问题。考虑到校园出入及复产复学的实际需求,做好人员信息甄别和跟踪是保障安全的关键所在。当下结合防疫需要,出入校区的人员都要展示“电子健康码”,以此确认学生、教职工、访客人员健康信息。TCPIP远程网络电子健康码扫码设备|二维码扫码门禁机HX-QR86L-IP可将“门禁码”+“电子健康码”合二为一,实现智能化校园实名制门禁管理,让管理难题迎刃而解。

           可行性方案只需在校园智能化门禁系统基础上加装上TCPIP远程网络电子健康码扫码设备|二维码扫码门禁机HX-QR86L-IP。学生、教职工、访客只需在校园的出入大门时,扫码手持的“电子健康码”,即可对申请的实名信息,健康信息进行数据提取与识别,通过和后台实名制数据比对后,即可获得当日有效的临时出入权限。

           如此一来,校园的安全管控得到了物联网技术与线上互联网监控的双重加持,有效解决头疼的疫情防疫的问题,实现疫情防疫的大数据化管理。

     

     

    展开全文
  • 通过一个聚合二维码,支付宝扫码进入到生活号的首页,微信扫码进入微信公众号关注界面 思路: 判断用户使用的支付宝扫码还是微信扫码。这个比较容易,根据浏览器请求头里面的信息就可以识别 获取生活号和公众号首页...
  • 我在实际使用的时候遇到一个问题,就是生成的二维码是有问题的,扫码无效果。。。 我的二维码展示的时候背景是个黑色,生成是黑白相间的二维码,展示是没问题的,尝试修改找寻问题。 发现问题的原因竟然是我的...
  • 微信二维码扫码获取openid

    万次阅读 2018-05-31 11:24:08
    扫描二维码后,通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑。第一步 确定回调域名,即扫描二维码后你需要跳转的后台URL,例如:...
  • 基于浏览器实现二维码扫码增强版-带视频演示Safari浏览器亲测效果基于H5流媒体,调用手机摄像头实现扫码基于URL Scheme,调用第三方APP实现扫码 模拟app扫码效果,支持前置摄像头后置摄像头切换,纯js+h5+css3实现,...
  • androidstudio基于华为hms scankit实现二维码扫码功能 一、配置 1,在根目录build.gradle添加: buildscript { repositories { google() jcenter() maven {url ‘https://developer.huawei.com/repo/’} } ...
  • 文章目录1、二维码应用场景及安全问题2、二维码登录的本质3、二维码验证机制的原理解析4、深入理解二维码在登录的交互过程5、总结感悟 1、二维码应用场景及安全问题 二维码使用广泛,生活处处都有二维码的使用场景。...
  • 史上最全的支付宝二维码扫码优化技术方案](https://upload-images.jianshu.io/upload_images/23124486-f13a636642fe1e68.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 优化策略 通过修改长宽比的判定...
  • 扫码的过程中,大家可能会有疑问:这二维码安全吗?会不会泄漏我的个人信息?更深度的用户还会考虑:我的系统是不是也可以搞一个二维码来推广呢? 这时候就需要了解一下二维码背后的技术和逻辑了!
  • 1,QQ扫码界面2,支付宝扫码界面3,微信扫码界面 其他设置参数自定义效果 可以在扫描框周围设置背景色 扫描码框颜色也可以设置 扫描码盒可以设置4个角的颜色,可以设置大小 只能设置为识别图像区域中的扫描代码框 ...
  • 干货 | 史上最全的支付宝二维码扫码优化技术方案兔子酱 2018-06-04 22:23:24 浏览1537 评论1算法 配置 测试摘要: ​​小蚂蚁说: 二维码又称二维条码,常见的二维码为QR Code,QR全称Quick Response,是一个...
  • Flutter扫码识别二维码内容

    千次阅读 2019-09-25 03:56:46
    前面一篇写了生成二维码图片,这篇来写使用相机扫描识别二维码 识别二维码需要用到插件barcode_scan 首先在pubspec.yaml文件中添加以下依赖,添加依赖后在pubspec.yaml运行flutter packages get或 使用IDE更新...
  • 因为公司业务需求,需要在Windows系统下调用摄像头识别二维码需求,就有了这个功能。 我根据网上网友提供的一些资料,自己整合应用到项目中,效果还不错(就是感觉像素不是太好) 现在将调用摄像头+识别二维码这两个...
  • 条形码识别 二维码识别 输入商品名或条码对应数字串查询 比价记录 浏览记录 二维码下载管理 软件适配: symbian第三版、symbian第五版、android、iphone 码上淘手机扫码软件是目前市场上适配机型最全面的扫码软件...
  • 背景 前些日子当前端面试官,问了一个问题:“你了解过canvas吗?” “这个我知道,我有做过DEMO,...“二维码的生成和扫码识别如何实现?” “图片的粒子爆炸效果呢?” “......” 因此,打算写一系列关于 canva...
  • 因为公司业务需求,需要在Windows系统下调用摄像头识别二维码需求,就有了这个功能。 我根据网上网友提供的一些资料,自己整合应用到项目中,效果还不错(就是感觉像素不是太好) 现在将调用摄像头+识别二维码这两个...
  • 在我们的生活场景中扫码已经无处... 今天让我们自己动手,一起做一个扫码以及生成二维码的工具来剥离他的骄傲,还原他的本质。首先大家要了解一下Zxing这个开源库,ZXing是一个开放源码的,用Java实现的多种格式的1D
  • 先前写了一个关于二维码扫描自动识别设备系统,并自动去下载相应版本的APP, 前一段时间微信扫描后,则不可再下载,原因是微信屏蔽了,只能提示用户从浏览器打开,并自动下载; 下载的界面效果: 下载的 ...
  • “码上淘”手机软件是易拍酷推出的一款针对条码和二维码扫码识别手机应用软件。通过该软件可实现淘宝比价及资源下载的双重功能,为用户提供线下购物时的价格参考及在没有数据线或蓝牙的情况下实现直接下载网络资源到...
  • 二维码,通过草料二维码生成的,这个网站挺好的,用起来比较简单方便,可以直接输入文字生成二维码,也可以放入链接生成二维码。 草料二维码:https://cli.im/ index.wxml &lt;view class="...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,301
精华内容 2,920
关键字:

二维码扫码识别应用