ZXing 创建及识别二维码
生成二维码
目标
- 能够生成任意大小的二维码
- 生成的二维码可调整背景颜色和码点的颜色
- 生成的二维码中心可带有小Icon
- 生成的二维码可带边框并可调整边框宽度和颜色
实现
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;}}
}
结果
达成全部既定目标
识别二维码
目标
- 能够快速识别二维码内容
- 识别二维码时可定位二维码中心位置
- 多码共存时可多码识别并定位
实现
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);}
}
结果
能够正常识别二维码,也可多识别,也能够进行定位,但是定位准确度有待提高。