二维码扫描_二维码扫描模块 - CSDN
精华内容
参与话题
  • 完整的二维码扫描解决方案

    千次阅读 2018-04-24 12:09:27
    现在的应用都有自己的二维码扫描工具,最近接手的项目也不例外,集成了ZXing二维码扫描,但是用起来却实在差强人意,后来看到QrCodeReaderView效果不错,识别速度上有明显提高,而且使用也非常简单,于是便迅速集成...

    现在的应用都有自己的二维码扫描工具,最近接手的项目也不例外,集成了ZXing二维码扫描,但是用起来却实在差强人意,后来看到QrCodeReaderView效果不错,识别速度上有明显提高,而且使用也非常简单,于是便迅速集成,唯独对扫码界面定制不够,于是再对ZXing中的自定义View修改,便得到较为完整的二维码扫描解决方案:

    • 二维码扫描框
    • 自定义属性
    • 颜色资源
    • 图片资源
    • 生成二维码
    • 二维码生成工具类

    二维码扫描框

    /*
     * Copyright (C) 2008 ZXing authors
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.apple.widget;
    
    import android.content.Context;
    import android.content.res.Resources;
    import android.content.res.TypedArray;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.graphics.drawable.Drawable;
    import android.util.AttributeSet;
    import android.view.View;
    
    import com.apple.lottle.R;
    
    import java.util.Collection;
    import java.util.HashSet;
    
    /**
     * 自定义组件实现,扫描功能
     */
    public final class ViewfinderView extends View {
    
        private static final long ANIMATION_DELAY = 100L;
        private static final int OPAQUE = 0xFF;
    
        public static int FRAME_WIDTH = -1;
        public static int FRAME_HEIGHT = -1;
        public static int FRAME_MARGINTOP = -1;
        private final Paint paint;
        private final int maskColor;
        private final int resultColor;
        private final int resultPointColor;
        private int screenWidthPx;
        private int screenHeightPx;
        private Bitmap resultBitmap;
        private Collection<ResultPoint> possibleResultPoints;
        private Collection<ResultPoint> lastPossibleResultPoints;
        private Rect framingRect;
        //扫描区域提示文本
        private String labelText;
        //扫描区域提示文本颜色
        private int labelTextColor;
        private float labelTextSize;
        // 扫描线移动的y
        private int scanLineTop;
        // 扫描线移动速度
        private int SCAN_VELOCITY;
        // 扫描线
        private Bitmap scanLight;
        // 是否展示小圆点
        private boolean isCircle;
        // 扫描框边角颜色
        private int innercornercolor;
        // 扫描框边角长度
        private int innercornerlength;
        // 扫描框边角宽度
        private int innercornerwidth;
    
        public ViewfinderView(Context context) {
            this(context, null);
        }
    
        public ViewfinderView(Context context, AttributeSet attrs) {
            this(context, attrs, -1);
        }
    
        public ViewfinderView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            paint = new Paint();
            Resources resources = getResources();
            maskColor = resources.getColor(R.color.viewfinder_mask);
            resultColor = resources.getColor(R.color.result_view);
            resultPointColor = resources.getColor(R.color.possible_result_points);
            possibleResultPoints = new HashSet<>(5);
            screenWidthPx = context.getResources().getDisplayMetrics().widthPixels;
            screenHeightPx = context.getResources().getDisplayMetrics().heightPixels;
            scanLight = BitmapFactory.decodeResource(resources, R.drawable.scan_light);
    
            initInnerRect(context, attrs);
        }
    
        /**
         * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
         */
        public static int dip2px(Context context, float dpValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (dpValue * scale + 0.5f);
        }
    
        /**
         * 初始化内部框的大小
         *
         * @param context
         * @param attrs
         */
        private void initInnerRect(Context context, AttributeSet attrs) {
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ViewfinderView);
            // 扫描框距离顶部
            float innerMarginTop = ta.getDimension(R.styleable.ViewfinderView_inner_margintop, -1);
            if (innerMarginTop != -1) {
                FRAME_MARGINTOP = (int) innerMarginTop;
            }
            // 扫描框的宽度
            FRAME_WIDTH = (int) ta.getDimension(R.styleable.ViewfinderView_inner_width, screenWidthPx * 2 / 3);
            // 扫描框的高度
            FRAME_HEIGHT = (int) ta.getDimension(R.styleable.ViewfinderView_inner_height, screenWidthPx * 2 / 3);
            // 扫描框边角颜色
            innercornercolor = ta.getColor(R.styleable.ViewfinderView_inner_corner_color, Color.parseColor("#45DDDD"));
            // 扫描框边角长度
            innercornerlength = (int) ta.getDimension(R.styleable.ViewfinderView_inner_corner_length, 65);
            // 扫描框边角宽度
            innercornerwidth = (int) ta.getDimension(R.styleable.ViewfinderView_inner_corner_width, 15);
            labelTextColor = ta.getColor(R.styleable.ViewfinderView_label_text_color, 0x90FFFFFF);
            labelText = ta.getString(R.styleable.ViewfinderView_label_text);
            labelTextSize = ta.getFloat(R.styleable.ViewfinderView_label_text_size, 36);
            // 扫描bitmap
            Drawable drawable = ta.getDrawable(R.styleable.ViewfinderView_inner_scan_bitmap);
            if (drawable != null) {
            }
            // 扫描控件
            scanLight = BitmapFactory.decodeResource(getResources(), ta.getResourceId(R.styleable.ViewfinderView_inner_scan_bitmap, R.drawable.scan_light));
            // 扫描速度
            SCAN_VELOCITY = ta.getInt(R.styleable.ViewfinderView_inner_scan_speed, 5);
            isCircle = ta.getBoolean(R.styleable.ViewfinderView_inner_scan_iscircle, true);
            ta.recycle();
        }
    
        /**
         * Calculates the framing rect which the UI should draw to show the user where to place the
         * barcode. This target helps with alignment as well as forces the user to hold the device
         * far enough away to ensure the image will be in focus.
         *
         * @return The rectangle to draw on screen in window coordinates.
         */
        public Rect getFramingRect() {
            try {
                int leftOffset = (screenWidthPx - FRAME_WIDTH) / 2;
    
                int topOffset;
                if (FRAME_MARGINTOP != -1) {
                    topOffset = FRAME_MARGINTOP;
                } else {
                    topOffset = (screenHeightPx - FRAME_HEIGHT) / 3;
                }
                framingRect = new Rect(leftOffset, topOffset, leftOffset + FRAME_WIDTH, topOffset + FRAME_HEIGHT);
                // }
                return framingRect;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
        @Override
        public void onDraw(Canvas canvas) {
            Rect frame = getFramingRect();
            if (frame == null) {
                return;
            }
            int width = canvas.getWidth();
            int height = canvas.getHeight();
    
            // Draw the exterior (i.e. outside the framing rect) darkened
            paint.setColor(resultBitmap != null ? resultColor : maskColor);
            canvas.drawRect(0, 0, width, frame.top, paint);
            canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
            canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
            canvas.drawRect(0, frame.bottom + 1, width, height, paint);
    
            if (resultBitmap != null) {
                // Draw the opaque result bitmap over the scanning rectangle
                paint.setAlpha(OPAQUE);
                canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
            } else {
                drawFrameBounds(canvas, frame);
                drawScanLight(canvas, frame);
                //绘制提示信息
                drawTextInfo(canvas, frame);
                Collection<ResultPoint> currentPossible = possibleResultPoints;
                Collection<ResultPoint> currentLast = lastPossibleResultPoints;
                if (currentPossible.isEmpty()) {
                    lastPossibleResultPoints = null;
                } else {
                    possibleResultPoints = new HashSet<ResultPoint>(5);
                    lastPossibleResultPoints = currentPossible;
                    paint.setAlpha(OPAQUE);
                    paint.setColor(resultPointColor);
    
                    if (isCircle) {
                        for (ResultPoint point : currentPossible) {
                            canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 6.0f, paint);
                        }
                    }
                }
                if (currentLast != null) {
                    paint.setAlpha(OPAQUE / 2);
                    paint.setColor(resultPointColor);
    
                    if (isCircle) {
                        for (ResultPoint point : currentLast) {
                            canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 3.0f, paint);
                        }
                    }
                }
                postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);
            }
        }
    
        /**
         * 绘制移动扫描线
         *
         * @param canvas
         * @param frame
         */
        private void drawScanLight(Canvas canvas, Rect frame) {
            if (scanLineTop == 0) {
                scanLineTop = frame.top;
            }
            if (scanLineTop >= frame.bottom - 30) {
                scanLineTop = frame.top;
            } else {
                scanLineTop += SCAN_VELOCITY;
            }
            Rect scanRect = new Rect(frame.left, scanLineTop, frame.right,
                    scanLineTop + 30);
            canvas.drawBitmap(scanLight, null, scanRect, paint);
        }
    
        /**
         * 绘制取景框边框
         *
         * @param canvas
         * @param frame
         */
        private void drawFrameBounds(Canvas canvas, Rect frame) {
            paint.setColor(innercornercolor);
            paint.setStyle(Paint.Style.FILL);
            int corWidth = innercornerwidth;
            int corLength = innercornerlength;
            // 左上角
            canvas.drawRect(frame.left, frame.top, frame.left + corWidth, frame.top + corLength, paint);
            canvas.drawRect(frame.left, frame.top, frame.left + corLength, frame.top + corWidth, paint);
            // 右上角
            canvas.drawRect(frame.right - corWidth, frame.top, frame.right, frame.top + corLength, paint);
            canvas.drawRect(frame.right - corLength, frame.top, frame.right, frame.top + corWidth, paint);
            // 左下角
            canvas.drawRect(frame.left, frame.bottom - corLength, frame.left + corWidth, frame.bottom, paint);
            canvas.drawRect(frame.left, frame.bottom - corWidth, frame.left + corLength, frame.bottom, paint);
            // 右下角
            canvas.drawRect(frame.right - corWidth, frame.bottom - corLength, frame.right, frame.bottom, paint);
            canvas.drawRect(frame.right - corLength, frame.bottom - corWidth, frame.right, frame.bottom, paint);
        }
    
        //绘制文本
        private void drawTextInfo(Canvas canvas, Rect frame) {
            paint.setColor(labelTextColor);
            paint.setTextSize(labelTextSize);
            paint.setTextAlign(Paint.Align.CENTER);
            canvas.drawText(labelText, frame.left + frame.width() / 2, frame.bottom + innercornerlength * 1.5f, paint);
        }
    
        public void drawViewfinder() {
            resultBitmap = null;
            invalidate();
        }
    
        public void addPossibleResultPoint(ResultPoint point) {
            possibleResultPoints.add(point);
        }
    }

    自定义属性

    <declare-styleable name="ViewfinderView">
        <attr name="inner_width" format="dimension"/>
        <attr name="inner_height" format="dimension"/>
        <attr name="inner_margintop" format="dimension" />
        <attr name="inner_corner_color" format="color" />
        <attr name="inner_corner_length" format="dimension" />
        <attr name="inner_corner_width" format="dimension" />
        <attr name="inner_scan_bitmap" format="reference" />
        <attr name="inner_scan_speed" format="integer" />
        <attr name="inner_scan_iscircle" format="boolean" />
        <attr name="label_text_color" format="color"/>
        <attr name="label_text" format="string"/>
        <attr name="label_text_size" format="integer"/>
    </declare-styleable>

    颜色资源

    <!-- 二维码扫描 -->
    <color name="viewfinder_mask">#60000000</color>
    <color name="result_view">#b0000000</color>
    <color name="possible_result_points">#c0ffff00</color>

    图片资源

    扫描线

    生成二维码

    Bitmap bitmap = QrCodeUtils.createImage(jsonObject.toString(), 400, 400, null);
    imageView.setImageBitmap(bitmap);

    二维码生成工具类

    package com.apple.utils;
    
    import android.app.Activity;
    import android.content.Context;
    import android.content.res.AssetFileDescriptor;
    import android.graphics.Bitmap;
    import android.graphics.Matrix;
    import android.media.AudioManager;
    import android.media.MediaPlayer;
    import android.os.Vibrator;
    import android.text.TextUtils;
    
    import com.google.zxing.BarcodeFormat;
    import com.google.zxing.EncodeHintType;
    import com.google.zxing.WriterException;
    import com.google.zxing.common.BitMatrix;
    import com.google.zxing.qrcode.QRCodeWriter;
    import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
    import com.zhcx.doctorgh.R;
    
    import java.io.IOException;
    import java.util.Hashtable;
    
    /**
     * 二维码扫描工具类
     */
    public class QrCodeUtils {
    
        /**
         * 生成二维码图片
         *
         * @param text
         * @param w
         * @param h
         * @param logo
         * @return
         */
        public static Bitmap createImage(String text, int w, int h, Bitmap logo) {
            if (TextUtils.isEmpty(text)) {
                return null;
            }
            try {
                Bitmap scaleLogo = getScaleLogo(logo, w, h);
    
                int offsetX = w / 2;
                int offsetY = h / 2;
    
                int scaleWidth = 0;
                int scaleHeight = 0;
                if (scaleLogo != null) {
                    scaleWidth = scaleLogo.getWidth();
                    scaleHeight = scaleLogo.getHeight();
                    offsetX = (w - scaleWidth) / 2;
                    offsetY = (h - scaleHeight) / 2;
                }
                Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
                hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
                //容错级别
                hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
                //设置空白边距的宽度
                hints.put(EncodeHintType.MARGIN, 0);
                BitMatrix bitMatrix = new QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, w, h, hints);
                int[] pixels = new int[w * h];
                for (int y = 0; y < h; y++) {
                    for (int x = 0; x < w; x++) {
                        if (x >= offsetX && x < offsetX + scaleWidth && y >= offsetY && y < offsetY + scaleHeight) {
                            int pixel = scaleLogo.getPixel(x - offsetX, y - offsetY);
                            if (pixel == 0) {
                                if (bitMatrix.get(x, y)) {
                                    pixel = 0xff000000;
                                } else {
                                    pixel = 0xffffffff;
                                }
                            }
                            pixels[y * w + x] = pixel;
                        } else {
                            if (bitMatrix.get(x, y)) {
                                pixels[y * w + x] = 0xff000000;
                            } else {
                                pixels[y * w + x] = 0xffffffff;
                            }
                        }
                    }
                }
                Bitmap bitmap = Bitmap.createBitmap(w, h,
                        Bitmap.Config.ARGB_8888);
                bitmap.setPixels(pixels, 0, w, 0, 0, w, h);
                return bitmap;
            } catch (WriterException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        private static Bitmap getScaleLogo(Bitmap logo, int w, int h) {
            if (logo == null) return null;
            Matrix matrix = new Matrix();
            float scaleFactor = Math.min(w * 1.0f / 5 / logo.getWidth(), h * 1.0f / 5 / logo.getHeight());
            matrix.postScale(scaleFactor, scaleFactor);
            Bitmap result = Bitmap.createBitmap(logo, 0, 0, logo.getWidth(), logo.getHeight(), matrix, true);
            return result;
        }
    }

    展开全文
  • 二维码扫描实现

    千次阅读 2017-05-03 16:06:24
    二维码扫描实现二维码原理 三个回形大方块,是为了给相机定位的;中间的黑白块,黑块代表1,白块代表0,八个一组,组成二进制信息。二维码原理 这个小视频,简单的介绍了下二维码iOS简单的实现二维码扫描知道二维码...

    二维码扫描实现

    二维码原理

    二维码扫描过程示意图
    三个回形大方块,是为了给相机定位的;中间的黑白块,黑块代表1,白块代表0,八个一组,组成二进制信息。二维码原理 这个小视频,简单的介绍了下二维码

    iOS简单的实现二维码扫描

    知道二维码的原理后,就可以简单的实现一下二维码扫描。在iOS7之前,二维码扫描大多数采用的是zxing这个第三方库ZXing和zbar,但是使用的时候会遇到很多坑,之后,苹果自己实现了二维码的扫描方法,扫描迅速识别率高,现在看看如何简单的实现。

    实现步骤

    //1.获取摄像设备
    let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)!
    //2.创建输入流
    var input: AVCaptureDeviceInput?
    do {
        input = try AVCaptureDeviceInput.init(device: device)
    } catch  {
    
    }
    //3.判断输入流是否可用
    guard input != nil else {
         return
     }
     //4.创建输入流
     let output = AVCaptureMetadataOutput.init()
     //5.设置代理,在主线程里刷新,注意此时self要签AVCaptureMetadataOutputObjectsDelegate协议
     output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
     //6.创建连接对象,添加输入输出流
     session = AVCaptureSession.init()
     //高质量采集率
     session?.canSetSessionPreset(AVCaptureSessionPresetHigh)
     if (session?.canAddInput(input))! {
         session?.addInput(input)
     }
     if (session?.canAddOutput(output))! {
         session?.addOutput(output)
     }
     //7.设置扫码支持的编码格式
     output.metadataObjectTypes = [AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]
     //8.设置扫描范围(每一个取值0~1,以屏幕的右上角为原点,扫描的图像其实是旋转了90度)
     output.rectOfInterest = CGRect.init(x: (scanY)/APP_HEIGHT, y: (scanX)/APP_WIDTH, width: scanH/APP_HEIGHT, height: scanW/APP_WIDTH)
     //9.扫描区域大小的设置(扫描时候可以看见的背景视图,这部分也可以自定义,显示自己想要的布局)
     let layer = AVCaptureVideoPreviewLayer.init(session: session)
     layer.frame = self.view.frame
     layer.session = session
     layer.videoGravity = AVLayerVideoGravityResizeAspectFill
     self.view.layer.insertSublayer(layer, at: 0)
     //10.开始捕获对象
     session?.startRunning()
    
     //11.实现代理方法          
     extension ViewController: AVCaptureMetadataOutputObjectsDelegate {
    //扫描结果
    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
        if metadataObjects.count > 0 {
            //获取到信息后停止扫描
            session?.stopRunning()
            let metaDataObject = metadataObjects.first as! AVMetadataMachineReadableCodeObject
            //输出扫描字符串
            print("stringValue:\(metaDataObject.stringValue)")
            //移除扫描视图
            let layer = self.view.layer.sublayers?.first as! AVCaptureVideoPreviewLayer
            layer.removeFromSuperlayer()
        }
    }
    

    }

    自定义二维码扫描

    上面的方式只能初步学习使用,而实际上的应用开发需要像微信或者支付宝那样的样式,所以需要进一步的开发出我们想要的样式。

    扫描区域背景

    观察微信的扫描界面发现,除了中间的扫描框之外,周围有一层半透明的视图,所以首先想到的办法是:去除中间的扫描区域,将图像分为四个部分,设置统一的颜色和透明度,添加进view。这种方法当然能实现想要的效果,但是明显不够优雅,所以考虑另一种方法,将当前view的某一区域设置为透明,这样就可以达到想要的效果了。
    UIGraphicsGetCurrentContext()对象有一个clear(_ rect: CGRect)方法,将指定的区域设置为透明,UIGraphicsGetCurrentContext方法获取上下文,只有在draw(_ rect: CGRect)方法中才能获取到。

    let context = UIGraphicsGetCurrentContext()
        if let context = context {
            context.setFillColor(red: 40/255.0, green: 40/255.0, blue: 40/255.0, alpha: 0.5)
            context.fill(CGRect.init(x: 0, y: 0, width: self.frame.width, height: self.frame.size.height))
            context.clear(CGRect.init(x: 100, y: 0, width: 50, height: 50))
        }
    

    扫描线

    扫描线使用UIView的动画就可以实现了:

    //扫描线动画效果
    func scanLineAnimation() {
        UIView.animate(withDuration: 3, delay: 0, options: .repeat, animations: {
            self.lineView.frame.origin.y += (self.scanH - 1)
        }) { (finished) in
        }
    }
    

    四个角的边框

    在扫描框上添加白色的边框,用来突出扫描框:

    //添加白色边框
    func addWhiteRect(context: CGContext, rect: CGRect) {
        context.stroke(rect)
        context.setStrokeColor(red: 1, green: 1, blue: 1, alpha: 1)
        context.setLineWidth(0.8)
        context.addRect(rect)
        context.strokePath()
    }
    

    添加四个角的边框,以顶点为起点,分别向两边延伸一段距离,然后连线,填充颜色:

    //扫描框的实现
    func addCornerLine(context: CGContext, rect: CGRect) {
        //画四个边角
        context.setLineWidth(2)
        context.setStrokeColor(red: 83/255.0, green: 239/255.0, blue: 111/255.0, alpha: 1)
    
        //左上角
        let pointsTopLeftA = [
            CGPoint.init(x: rect.origin.x, y: rect.origin.y),
            CGPoint.init(x: rect.origin.x + borderWidth, y: rect.origin.y)
        ]
        let pointsTopLeftB: Array = [
            CGPoint.init(x: rect.origin.x, y: rect.origin.y),
            CGPoint.init(x: rect.origin.x, y: rect.origin.y + borderWidth)
        ]
        addLine(pointA: pointsTopLeftA, pointB: pointsTopLeftB, context: context)
    
        //左下角
        let pointsBottomLeftA = [
            CGPoint.init(x: rect.origin.x, y: rect.maxY),
            CGPoint.init(x: rect.origin.x + borderWidth, y: rect.maxY)
        ]
        let pointsBottomLeftB = [
            CGPoint.init(x: rect.origin.x, y: rect.maxY),
            CGPoint.init(x: rect.origin.x, y: rect.maxY - borderWidth)
        ]
        addLine(pointA: pointsBottomLeftA, pointB: pointsBottomLeftB, context: context)
    
        //右上角
        let pointsTopRightA = [
            CGPoint.init(x: rect.maxX, y: rect.origin.y),
            CGPoint.init(x: rect.maxX - borderWidth, y: rect.origin.y)
        ]
        let pointsTopRightB = [
            CGPoint.init(x: rect.maxX, y: rect.origin.y),
            CGPoint.init(x: rect.maxX, y: rect.origin.y + borderWidth)
        ]
        addLine(pointA: pointsTopRightA, pointB: pointsTopRightB, context: context)
    
        //右下角
        let pointsBottomRightA = [
            CGPoint.init(x: rect.maxX, y: rect.maxY),
            CGPoint.init(x: rect.maxX - borderWidth, y: rect.maxY)
        ]
        let pointsBottomRightB = [
            CGPoint.init(x: rect.maxX, y: rect.maxY),
            CGPoint.init(x: rect.maxX, y: rect.maxY - borderWidth)
        ]
        addLine(pointA: pointsBottomRightA, pointB: pointsBottomRightB, context: context)
    
        context.strokePath()
    }
    
    private func addLine(pointA: [CGPoint], pointB: [CGPoint], context: CGContext) {
        context.addLines(between: pointA)
        context.addLines(between: pointB)
    }
    

    横竖屏

    如果当前页面要适应横竖屏的情况的话,目前还没想到什么比较好的方式,因为如果在背景图上采用autosizing的画,屏幕旋转后扫描框和扫描线会发生形变,跟预期不太一致,所以只能设置屏幕不能旋转

    识别相册中的二维码

    主要用到CIDetecor,将图片转成CIImage,通过features(in image: CIImage) -> [CIFeature]方法获取CIFeature的数组对象

    func readQRCode(qrImage: UIImage?, _ handle: @escaping completionHandle) {
        guard let qrImage = qrImage else {
            return
        }
        let context = CIContext.init(options: nil)
        let detector = CIDetector.init(ofType: CIDetectorTypeQRCode, context: context, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])
        let image = CIImage.init(cgImage: qrImage.cgImage!)
        let features = detector?.features(in: image)
        let feature: CIQRCodeFeature = features?.first as! CIQRCodeFeature
        let result = feature.messageString
        handle(result!)
    }
    

    生成二维码

    首先将需要的信息转成data,然后使用CIFilter输出图像,再将CIImage转换成UIImage,并放大显示

    func createCodeImage(string: String) -> UIImage? {
        guard !string.isEmpty else {
            return nil
        }
        //二维码滤镜
        let filter = CIFilter.init(name: "CIQRCodeGenerator")
        //恢复滤镜的默认属性
        filter?.setDefaults()
        //将字符串转换成NSData
        let data = string.data(using: String.Encoding.utf8)
        //通过KVC设置滤镜inputMessage数据
        filter?.setValue(data, forKey: "inputMessage")
        //获得滤镜输出的图像
        let outImage = filter?.outputImage
        //将CIImage转换成UIImage,并放大显示
        let image = createNonInterpolatedUIImageFormCIImage(image: outImage!, size: 200)
        return image
    }
    
    ///改变二维码大小
    private func createNonInterpolatedUIImageFormCIImage(image: CIImage, size: CGFloat) -> UIImage? {
        let extent = image.extent.integral
        let scale = min(size/extent.width, size/extent.height)
        //创建bitmap
        let width: size_t = size_t(extent.width * scale)
        let height: size_t = size_t(extent.height * scale)
        let cs = CGColorSpaceCreateDeviceGray()
        let bitmapRef = CGContext.init(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 0, space: cs, bitmapInfo: CGImageAlphaInfo.none.rawValue)
        let context = CIContext.init(options: nil)
        let bitmapImage = context.createCGImage(image, from: extent)
        bitmapRef?.interpolationQuality = .high
        bitmapRef?.scaleBy(x: scale, y: scale)
        bitmapRef?.draw(bitmapImage!, in: extent)
        //保存bitmap到图片
        let scaledImage = bitmapRef!.makeImage()
        return UIImage.init(cgImage:scaledImage!)
    }
    

    小结

    将二维码的需求分割后,就可以根据需求自定义想要的样式了,这里是我封装的一个二维码的库XELQRCode

    参考链接

    再见ZXing 使用系统原生代码处理QRCode

    展开全文
  • Qt实现二维码扫描

    千次下载 热门讨论 2020-07-30 23:32:29
    Qt实现的一个二维码扫描器,利用QZXing库进行解码。 更多信息请参考:http://blog.sina.com.cn/s/blog_a6fb6cc90101gng5.html
  • ctf隐写题经常出现二维码的题目,可以直接使用这个进行查看
  • 二维码扫描的一些代码

    千次阅读 2018-09-19 10:13:10
    // 扫描、生成二维码 // 扫描按钮布局文件 &amp;lt;Relativelayout android:id=&quot;@+id/ll_title_address&quot; android:layout_width=&quot;match_parent&quot; android:layout_...
    // 扫描、生成二维码
    
    // 扫描按钮布局文件
    <Relativelayout
    	android:id="@+id/ll_title_address"
    	android:layout_width="match_parent"
    	android:layout_height="60dp"
    	android:background="@color/red">
    	
    	<ImagiveView
    		android:id="@+id/imgv_saoma"
    		android:layout_width="wrap_content"
    		android:layout_height="wrap_content"
    		android:layout_alignParentleft="true"
    		android:layout_centerVertical="true"
    		android:paddingBottom="2dp"
    		android:paddingLeft="20dp"
    		android:paddingRight="15dp"
    		android:paddingTop="2dp"
    		android:src="@drawable/imgv_saoma">
    		
    	...
    	
    </Relativelayout>
    
    // 开启扫描类文件
    
    public class SaoMa{
    	
    	@OnClick({R.id.imgv_saoma})
    	public void btnClick(View view){
    		switch(view.getId()){
    			case R.id.imgv_saoma:
    			if(PermissionsUtil.is6){// 如果安卓系统大于6
    			// 开启相机
    				PermissionsUtil.checkPermissionBy6(this, Mainfest.permission.CAMERA);
    			} else if(PermissionsUtil.checkPermission(Mainfest.permission.CAMERA)){
    				// 如果6.0以下授权了
    				startActivity(MineScanAty.class, null);
    			} else {
    				showToast("未开启相机权限");
    			}
    		}
    	}
    }
    
    // 扫描二维码布局文件,比较简单就两个
    <?xml version="1.0" encoding="utf-8"?>
    <Relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
    	xmlns:app="http://schemas.android.com/apk/rea-auto"
    	android:layout_width="match_parent"
    	android:layout_height="match_parent"
    	android:background="@color/app_bg">
    	
    	<cn.bingoogolapple.qrcode.zxing.ZXingView
    		android:id="@+id/zxingview"
    		android:layout_width="match_parent"
    		android:layout_height="match_parent"
    		android:layout_centerInParent="true"
    		app:qrcv_animTime="1000"
    		app:qrcv_borderColor="@android:color/white"
    		app:qrcv_borderSize="1dp"
    		app:qrcv_cornerColor="#98FC95"
    		app:qrcv_cornerLength="20dp"
    		app:qrcv_cornerSize="3dp"
    		app:qrcv_maskColor="#33FFFFFF"
    		app:qrcv_rectWidth="200dp"
    		app:qrcv_scanLineColor="#98FC95"
    		app:qrcv_sacnSize="1dp"
    		app:qrcv_top0ffest="160dp"/>
    		
    	<ImagiveView
    		android:id="@+id/iv_finish"
    		android:layout_width="wrap_content"
    		android:layout_height="wrap_content"
    		android:padding="30dp"
    		android:src="@drawable/iv_finish"/>
    
    // 扫码的逻辑
    public class MineScanAty extends BaseAty implements QRCCodeView.Delegate{
    	
    	@Bind(R.id.zxingview)
    	QRCodeView mQRCodeView;
    	
    	@Bind(R.id.iv_finish)
    	ImagiveView mIvFinish;
    	
    	@Override
    	public int getLayoutId(){
    		return R.layout.scan_code_layout;
    	}
    	
    	@Override
    	public void initData(){
    		mQRCodeView.setResultHandler(this);
    		mIvFinish.setOnClickListener(new View.OnClickListener(){
    			@Override
    			public void onClick(View v){
    				finish();
    			}
    		});
    	}
    	
    	@Override
    	protected void onStart(){
    		super.onStart();
    		// 显示扫描框,并延迟1.5秒后开始识别
    		mQRCodeView.startSpotAndShowRect();
    	}
    	
    	@Override
    	protected void onStop(){
    		mQRCodeView.stopCamera();
    		super.onStop();		
    	}
    	
    	// 假如扫描成功了
    	@Override
    	public void onScanQRCodeSuccess(String result){
    		Log.i("result","result="+result);
    		// 收摊子
    		mQRCodeView.stopSpotAndHiddenRect();
    		showLoadingDialog(null);
    		// 上传扫到的结果
    		doHttp(RetrofitUtils.createApi(ModileApi.class).scan(UserManager.getUserId(), result), 1);
    		finish();
    	}
    	
    	// 上传解析成功
    	@Override
    	public void onSuccess(String result, Call<ResponseBody> call, Response<ResponseBody> response, int what){
    		showToast("成功!");
    		finish();
    		super.onSuccess(result, call, response, what);
    	}
    } 
    
    
    
    展开全文
  • 实现网站二维码扫描登录

    万次阅读 多人点赞 2014-03-31 10:37:01
    总体来看,扫描二维码实现网站的登录并不是太困难的事情。首先来看一下二维码登录的整体架构: 在整个架构中,主要包含了几个模块:手机App、浏览器、Web服务器以及存储服务(session服务)。整个方

    在尝试使用网页版微信时,发现微信的登录方式比较酷。区别与常用的用户名和密码的登录方式,网页微信登录只需要轻轻一扫,即可方便的实现登录功能。


    下面尝试根据个人的理解对其可能的架构猜测一番。总体来看,扫描二维码实现网站的登录并不是太困难的事情。首先来看一下二维码登录的整体架构:
    在整个架构中,主要包含了几个模块:手机App、浏览器、Web服务器以及存储服务(session服务)。整个方案的主要流程如下:

    1)获取二维码
    在打开weixin.qq.com整个页面之后,会在浏览器端种下sessionid,其中sessionid与浏览器中展示的二维码已经了映射关系。如方案一架构图所示:Web服务器接收到浏览器的<1.获取二维码>请求之后,生成与这个连接对应的session以及二维码图片,同时存储sessionid与二维码图片的一一映射关系(必须保证二维码图片与sessionid的唯一性,后面流程中,需要根据二维码图片来检索sessionid以实现通知该浏览器实现登录);

    2)扫描二维码
    手机App扫描浏览器的二维码图片,在手机App上完成确认授权之后,自动将手机App的登录态信息提交给Web服务器。Web服务确认提交等手机登录态合法之后,根据二维码检索出浏览器的链接信息即sessionid,与之对应的sessionid被设置为已经完成登录,同时绑定合法的浏览器端的用户登录态信息;

    3)通知浏览器完成登录
    浏览器如何及时的获取已经完成授权登录了呢?其实,针对这类问题主要有两种解决方案:
    a)ajax异步定时轮训请求
    采用这种方法技术实现成本比较低,伪实时,实时性的程度取决于ajax请求的频繁程度,高频度的请求无疑会给服务器带来不小的开销,所幸的是,针对这个登录场景并发请求量不会太高;
    b)Http comet实时推送
    采用comet实时推送给的方案,就是下图方案二所示,手机App确认授权之后,推送服务会将浏览器的登录信息实时推送给浏览器,这种方案的实时性无疑是最高的,在网页聊天、即时监控等场景下比较使用,用户的产品体验也会非常高,带来的问题在于:高昂的技术实现成本。



    4)本地浏览器绑定cookie
    浏览器接收到通知之后,架构用户信息关键是用户登录凭证写入到浏览器的Cookie中,在后续请求其他服务的过程中,作为最基本的请求参数进行传递;


    关于Comet推送的技术请参见:

    其实,上面写的都是错的,我压根没有做过类似的服务。


    展开全文
  • 二维码扫描、生成

    2019-01-13 20:41:06
    添加权限 &lt;uses-permission android:name="android.permission.CAMERA" /&gt; &lt;uses-permission android:name="android.permission.VIBRATE" /&gt;...
  • 二维码如何判断已被扫描

    万次阅读 2018-06-15 14:20:34
    前端界面如何检测二维码扫描或未被扫描而提醒“该二维码已过期请重试”?1、前端点击生成二维码按钮或点击相关链接2、该网页生成唯一个id的二维码,关闭该页面或每次刷新后都会改变。3、浏览器把这个id通知给...
  • web/html5调用摄像头实现二维码扫描

    万次阅读 热门讨论 2015-11-10 20:08:19
    利用html5(navigator.getUserMedia)调用摄像头抓拍图片媒体流,通过php调用java接口解析图片二维码,实现二维码解析,可结合自己的业务!不过目前支持的浏览器不多是个问题。
  • 微信扫描二维码获取用户的信息(网页授权) 文章目录微信扫描二维码获取用户的信息(网页授权)一、需求解说二、步骤准备1.内网穿透1.1内网穿透工具natapp1.2启动natapp2.微信公众号测试号2.1申请测试号2.2接口配置...
  • 二维码扫描优化

    2020-07-30 00:04:55
    zxing是一款跨平台的基于Java实现的处理一维或二维条码的库。支持多种格式,一维条码支持UPC-A,UPC-E,EAN-8,Code 39,Code 93等格式,二维条码支持QR C...
  • 我用的是草料二维码扫描器:https://cli.im/deqr 生成新的二维码 把你二维码扫描结果辅助粘贴到生成器,点击生成即可 我用的腾讯高级产品经理@太空小孩做的在线二维码生成器:...
  • 为了实现app扫描二维码,我想了很多办法,最后还是用原生的来挑战自己,下面是链接 http://www.html5plus.org/doc/zh_cn/barcode.html
  • 二维码解码工具

    万次阅读 2017-04-01 11:47:19
    http://tool.chinaz.com/qrcode/?jdfwkey=weexu
  • 如何使用电脑扫描二维码

    万次阅读 2017-09-25 20:09:42
    1.打开电脑上的任何一个浏览器,在地址栏输入网址:cdn.malu.me/qrdecode/ 2.进入网站后点击网页中间的上传图标... 3.上传完成之后系统就会自动识别出来二维码的信息,点击下方[打开此链接]就可以实现二维码扫描
  • Android 二维码扫描,识别率非常高

    万次阅读 热门讨论 2017-05-23 19:47:02
    这是我在GitHub看到的一个开源二维码扫描例子,识别率非常高。支出二维码,条形码,以及图片识别。 效果图与示例 apk   点击下载 ZXingDemo.apk或扫描下面的二维码安装 点击下载 ZBarDemo.apk或...
  • H5+ 二维码扫描功能

    万次阅读 2017-06-19 12:58:39
    二维码在生活中的使用越来越广泛,APP开发中,也越来越多的需求需要用到二维码的扫描功能,以下就针对h5+的二维码扫描功能做一些简单的介绍; 1. var bc = new plus.barcode.Barcode( id, filters, styles ); ...
  • 1. 二维码在线生成: 1.1 浏览器测试:http://api.online-service.vip/qr/create?w=150&h=150&c=test 1.2 可在html的img标签src属性中直接引用; 如果二维码的属性相对固定, 可以把二维码保存下来, 二维码...
  • 如题如何,二维码生成用的是QrCode,里面放了一个地址。扫描后可以挑战到二维码中存储的那个地址。 请教一下。我跳转到我指定的请求地址的时候如何获取扫描用户的openid
  • 现在在做的一个项目需要做一个手机浏览器上扫描二维码的功能,自己在网上找了很多,但还是不行,求大神指点。谢谢!谢谢!
1 2 3 4 5 ... 20
收藏数 102,421
精华内容 40,968
关键字:

二维码扫描