Unity利用ZXing库 生成和识别二维码

发布时间:2023年12月18日

ZXing 创建及识别二维码

生成二维码

目标

  1. 能够生成任意大小的二维码
  2. 生成的二维码可调整背景颜色和码点的颜色
  3. 生成的二维码中心可带有小Icon
  4. 生成的二维码可带边框并可调整边框宽度和颜色

实现

using System.Collections.Generic;
using UnityEngine;
using ZXing;
using ZXing.Common;

namespace S
{
    public class QRCreater
    {
        /// <summary>
        /// 二维码信息
        /// </summary>
        public string Content;
        /// <summary>
        /// 二维码宽度
        /// </summary>
        public int Width=256;
        /// <summary>
        /// 二维码高度
        /// </summary>
        public int Height=256;
        /// <summary>
        /// 二维码外边距
        /// </summary>
        public int Margin=1;
        /// <summary>
        /// 二维码背景颜色
        /// </summary>
        public Color BgColor=Color.white;
        /// <summary>
        /// 二维码内容颜色
        /// </summary>
        public Color ContentColor=Color.black;

        private Texture2D mIcon;
        /// <summary>
        /// 二维码中间小图标
        /// </summary>
        public Texture2D Icon
        {
            get { return mIcon; }
            set
            {
                mIcon = value;
                if (mIcon.width>Width*0.2f||mIcon.height>Height*0.2f)
                {
                    Debug.LogWarning("小图标大小超过二维码大小的1/5,识别精度降低,或可能无法被识别!!!");
                }
            }
        }

        /// <summary>
        /// 编码方式
        /// </summary>
        public string Encode = "UTF-8";

        /// <summary>
        /// 边界线宽度
        /// </summary>
        public int BorderWidth = 0;

        /// <summary>
        /// 边界线颜色
        /// </summary>
        public Color BorderColor = Color.black;

        /// <summary>
        /// 二维码容错级别
        /// </summary>
        private ZXing.QrCode.Internal.ErrorCorrectionLevel ErrorCorrectionLevel =
            ZXing.QrCode.Internal.ErrorCorrectionLevel.M;

        public QRCreater()
        {
        }

        public QRCreater(int width,int height,string content)
        {
            Width = width;
            Height = height;
            Content = content;
        }
        public QRCreater(int width,int height,string content,Texture2D icon)
        {
            Width = width;
            Height = height;
            Content = content;
            Icon = icon;
        }
        
        private BitMatrix GetBitMatrix()
        {
            MultiFormatWriter mw = new MultiFormatWriter();
            Dictionary<EncodeHintType, object> hints = new Dictionary<EncodeHintType, object>()
            {
                {EncodeHintType.CHARACTER_SET, Encode},
                {EncodeHintType.MARGIN, Margin},
                {EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel}
            };
            BitMatrix bitMatrix = mw.encode(Content, BarcodeFormat.QR_CODE, Width, Height, hints);
            return bitMatrix;
        }

        /// <summary>
        /// 是否是边界线区域
        /// </summary>
        /// <param name="x">像素x坐标</param>
        /// <param name="y">像素y坐标</param>
        public bool IsBorderArea(int x,int y)
        {
            if (BorderWidth <= 0) return false;
            bool xTrue = x <= BorderWidth || x >= Width - BorderWidth;
            bool yTrue = y <= BorderWidth || y >= Height - BorderWidth;
            return xTrue || yTrue;
        }

        /// <summary>
        /// 是否是Icon区域
        /// </summary>
        /// <param name="x">像素x坐标</param>
        /// <param name="y">像素y坐标</param>
        /// <param name="color">Icon对应的像素颜色</param>
        public bool IsIconArea(int x,int y,out Color color)
        {
            color = default;
            if (Icon == null) return false;
            int halfWidth = (int) (Width * 0.5f);
            int halfHeight = (int) (Height * 0.5f);
            int iconHalfWidth = (int) (Icon.width * 0.5f);
            int iconHalfHeight = (int) (Icon.height * 0.5f);
            int minX = halfWidth - iconHalfWidth;
            int maxX = halfWidth + iconHalfWidth;
            int minY = halfHeight - iconHalfHeight;
            int maxY = halfHeight + iconHalfHeight;
            if (x < minX || x > maxX || y < minY || y > maxY) return false;
            color = Icon.GetPixel(x - minX, y - minY);
            return true;
        }
        
        /// <summary>
        /// 创建二维码的Texture2D
        /// </summary>
        /// <returns>二维码的Texture2D</returns>
        public Texture2D CreateTexture2D()
        {
            Texture2D texture2D=new Texture2D(Width,Height);
            BitMatrix bitMatrix = GetBitMatrix();
            Color iconColor;
            for (int i = 0; i < bitMatrix.Width; i++)
            {
                for (int j = 0; j < bitMatrix.Height; j++)
                {
                    if (IsBorderArea(i,j))//在边界线区域内
                    {
                        texture2D.SetPixel(i,j,BorderColor);
                    }
                    else if (IsIconArea(i,j,out iconColor))//在Icon区域内
                    {
                        if (iconColor.a==0)//icon 透明处填充背景色
                        {
                            texture2D.SetPixel(i, j, BgColor);
                        }
                        else//写入icon像素颜色
                        {
                            texture2D.SetPixel(i, j, iconColor);
                        }
                    }
                    else// 不在Icon区域内
                    {
                        if (bitMatrix[i, j]) texture2D.SetPixel(i, j, ContentColor);
                        else texture2D.SetPixel(i, j, BgColor);
                    }
                }
            }

            texture2D.Apply();
            return texture2D;
        }

        /// <summary>
        /// 创建二维码的Sprite
        /// </summary>
        /// <returns>二维码的Sprite</returns>
        public Sprite CreateSprite()
        {
            Texture2D texture2D = CreateTexture2D();
            if (texture2D == null) return null;
            return Sprite.Create(texture2D,new Rect(0,0,texture2D.width,texture2D.height),Vector2.zero);
        }

        public void Dispose()
        {
            Width = 0;
            Height = 0;
            Margin = 0;
            BorderWidth = 0;
            Encode = null;
            Icon = null;
        }
    }
}

结果

达成全部既定目标

识别二维码

目标

  1. 能够快速识别二维码内容
  2. 识别二维码时可定位二维码中心位置
  3. 多码共存时可多码识别并定位

实现

using System.Text;
using UnityEngine;
using UnityEngine.UI;
using ZXing;
public class QRScan:MonoBehaviour
{
    [SerializeField]
    private Button scanBtn;
    [SerializeField]
    private RawImage cameraImg;
    
    private WebCamTexture webCamTexture;
    
    public bool IsScaning { get; private set; }
    public float Interval = 0.1f;
    
    private float curInterval;
    private BarcodeReader barCodeReader;
    private Color32[] scanData;


    private void Start()
    {
        WebCamDevice[] devices = WebCamTexture.devices;
        string deviceName = devices[0].name;
        Vector2 cameraImgSize = (cameraImg.transform as RectTransform).sizeDelta;
        webCamTexture=new WebCamTexture(deviceName,(int)cameraImgSize.x,(int)cameraImgSize.y);
        barCodeReader=new BarcodeReader();
        scanBtn.onClick.AddListener(Open);
    }

    public void Update()
    {
        if (IsScaning)
        {
            curInterval += Time.deltaTime;
            if (curInterval>Interval)
            {
                curInterval = 0;
                Scan();
            }
        }
    }

    public void Open()
    {
        webCamTexture.Play();
        cameraImg.texture = webCamTexture;
        cameraImg.SetNativeSize();
        IsScaning = true;
    }

    public void Close()
    {
        webCamTexture.Stop();
        IsScaning = false;
    }
    
    void Scan()
    {
        if (!IsScaning) return;
        scanData = webCamTexture.GetPixels32();
        Result[] results = barCodeReader.DecodeMultiple(scanData, webCamTexture.width,webCamTexture.height);
        if (results!=null)
        {
            ScanSuccess(results);
        }
    }


    void ScanSuccess(Result[] results)
    {
        Close();
        StringBuilder resultSb = new StringBuilder();
        resultSb.Append("识别结果为:");
        foreach (var result in results)
        {
            resultSb.Append($"【{result.Text}】 ");
        }
        Debug.Log(resultSb);
        cameraImg.texture = CreateResultTexture(results);
    }

    /// <summary>
    /// 创建带有定位点的Texture2D
    /// </summary>
    /// <param name="results"></param>
    /// <returns></returns>
    Texture2D CreateResultTexture(Result[] results)
    {
        Texture2D tex = new Texture2D(webCamTexture.width,webCamTexture.height);
        tex.SetPixels32(scanData);
        Color[] pointColors = new Color[100];
        for (int i = 0; i < pointColors.Length; i++)
        {
            pointColors[i] = Color.red;
        }
        foreach (var result in results)
        {
            Vector2 centerPos = GetCenterPos(result);
            tex.SetPixels((int)centerPos.x,(int)centerPos.y,10,10,pointColors);
        }
        tex.Apply();
        return tex;
        
    }

    public Vector2 GetCenterPos(Result result)
    {
        if (result == null) return default;
        float totalX=0, totalY=0;
        int Count = result.ResultPoints.Length;
        foreach (var position in result.ResultPoints)
        {
            totalX += position.X;
            totalY += position.Y;
        }
        return new Vector2(totalX/Count,totalY/Count);
    }
}

结果

能够正常识别二维码,也可多识别,也能够进行定位,但是定位准确度有待提高。

文章来源:https://blog.csdn.net/weixin_42498461/article/details/135011588
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。