using System; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; //using Curtain.Helpers; using ZXing; using ZXing.QrCode; using ZXing.QrCode.Internal; namespace Dongke.WinForm.Controls.InvoiceLayout.DrawBarcode.QRCode { /// /// 二维码生成 /// public sealed class QRCodeHelper { /// /// 原始二维码 /// /// /// /// public static QRCodeData Encode(string contents, QRCodeEncodingOptions encodingOptions = null) { if (encodingOptions == null) { encodingOptions = new QRCodeEncodingOptions(); } QrCodeEncodingOptions qroptions = new QrCodeEncodingOptions { DisableECI = encodingOptions.DisableECI, CharacterSet = encodingOptions.CharacterSet, ErrorCorrection = GetErrorCorrectionLevel(encodingOptions.ECLevel), QrVersion = encodingOptions.Version }; ZXing.QrCode.Internal.QRCode qrcode = null; try { qrcode = ZXing.QrCode.Internal.Encoder.encode(contents, qroptions.ErrorCorrection, qroptions.Hints); } catch (WriterException wex) { if (encodingOptions.Version.HasValue && wex.Message.Contains("Data too big for requested version")) { qroptions.QrVersion = null; try { qrcode = ZXing.QrCode.Internal.Encoder.encode(contents, qroptions.ErrorCorrection, qroptions.Hints); } catch { } } } if (qrcode == null) { return null; } ByteMatrix bm = qrcode.Matrix; int size = bm.Width; QRCodeData data = new QRCodeData(size) { Text = contents, MaskPattern = qrcode.MaskPattern, ModeName = qrcode.Mode.Name.ToString(), Version = qrcode.Version.VersionNumber, Options = encodingOptions, Width = size, Height = size, }; for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { data[x, y] = (bm[x, y] == 1); } } return data; } /// /// 按比例放大的原始二维码 /// /// /// /// /// /// public static QRCodeData Encode(string contents, int width, int height, QRCodeEncodingOptions encodingOptions = null) { QRCodeData data = Encode(contents, encodingOptions); if (data == null) { return null; } return Encode(data, width, height); } /// /// 按比例放大的原始二维码 /// /// /// /// /// public static QRCodeData Encode(QRCodeData data, int width, int height) { if (data == null) { return null; } data.Width = width; data.Height = height; bool isHorizontal = (width > height); int qrSize = (isHorizontal ? height : width); //if (qrSize < data.Size) //{ // throw new ArgumentOutOfRangeException((isHorizontal? "barcode height" : "barcode width"), (isHorizontal ? height : width), $"data size is {data.Size}"); //} if (qrSize <= data.Size) { return data; } int multiple = (qrSize / data.Size); if (multiple == 1) { return data; } int qrDataSize = data.Size * multiple; QRCodeData qrData = new QRCodeData(qrDataSize) { Text = data.Text, MaskPattern = data.MaskPattern, ModeName = data.ModeName, Version = data.Version, Options = data.Options, Width = width, Height = height, }; for (int y = 0; y < data.Size; y++) { int w = y * multiple; for (int x = 0; x < data.Size; x++) { int h = x * multiple; for (int j = w; j < w + multiple; j++) { for (int i = h; i < h + multiple; i++) { qrData[i, j] = data[x, y]; } } } } return qrData; } /// /// 直接绘制条码 /// /// /// /// public static void DrawQRCode(string contents, QRCodeDrawingOptions options, QRCodeEncodingOptions encodingOptions = null) { if (options?.DrawGraphics == null) { throw new ArgumentNullException("QRCodeDrawingOptions.DrawGraphics"); } QRCodeData data = Encode(contents, encodingOptions); // 条码范围 int width = options.ImageRect.Width - options.Margin.Horizontal; int height = options.ImageRect.Height - options.Margin.Vertical; data = Encode(data, width, height); DrawQRCode(data, options.DrawGraphics, options); } /// /// 直接绘制条码 /// /// /// public static void DrawQRCode(QRCodeData data, QRCodeDrawingOptions options) { if (options?.DrawGraphics == null) { throw new ArgumentNullException("QRCodeDrawingOptions.DrawGraphics"); } //// 条码范围 //int width = options.ImageRect.Width - options.Margin.Horizontal; //int height = options.ImageRect.Height - options.Margin.Vertical; //if (data.Width != width || data.Height != height) //{ // data = Encode(data, width, height); //} DrawQRCode(data, options.DrawGraphics, options); } /// /// 直接绘制条码 /// /// /// /// private static void DrawQRCode(QRCodeData imageData, Graphics graphics, QRCodeDrawingOptions options) { // 条码范围 using (Image image = GetQRCodeSource(imageData, options)) { Rectangle rect = new Rectangle( options.ImageRect.Left + options.Margin.Left, options.ImageRect.Top + options.Margin.Top, //imageData.Width, //imageData.Height); options.ImageRect.Width - options.Margin.Horizontal, options.ImageRect.Height - options.Margin.Vertical); if (options.ShowType == BarcodeShowType.Zoom) { graphics.DrawImage(image, rect); } else if (options.ShowType == BarcodeShowType.Show) { ImageHelper.Show(image, graphics, rect, ContentAlignment.MiddleCenter, false); } else { ImageHelper.Show(image, graphics, rect, ContentAlignment.TopLeft, false); } // TODO LOGO // TODO TEXT } } /// /// 条码图片 /// /// /// /// /// public static Image GetQRCodeImage(string contents, QRCodeDrawingOptions options, QRCodeEncodingOptions encodingOptions = null) { if (options == null) { throw new ArgumentNullException("QRCodeDrawingOptions"); } QRCodeData data = Encode(contents, encodingOptions); // 条码范围 int width = options.ImageRect.Width - options.Margin.Horizontal; int height = options.ImageRect.Height - options.Margin.Vertical; QRCodeData imageData = Encode(data, width, height); return GetQRCodeImage(imageData, options); } /// /// 条码图片 /// /// /// /// public static Image GetQRCodeImage(QRCodeData data, QRCodeDrawingOptions options) { if (options == null) { throw new ArgumentNullException("QRCodeDrawingOptions"); } if (options.ShowType == BarcodeShowType.Original) { return GetQRCodeSource(data, options); } Bitmap dataImage = new Bitmap(options.ImageRect.Width, options.ImageRect.Height); if (options.DpiX.HasValue) { dataImage.SetResolution(options.DpiX.Value, (options.DpiY) ?? options.DpiX.Value); } using (Graphics graphics = Graphics.FromImage(dataImage)) { graphics.Clear(options.BackColor); DrawQRCode(data, graphics, options); } return dataImage; } /// /// 原始条码图片 /// /// /// /// public static Image GetQRCodeSource(QRCodeData data, QRCodeDrawingOptions options) { Bitmap dataImage = new Bitmap(data.Size, data.Size); if (options != null && options.DpiX.HasValue) { dataImage.SetResolution(options.DpiX.Value, (options.DpiY) ?? options.DpiX.Value); } Rectangle rectImage = new Rectangle(0, 0, data.Size, data.Size); BitmapData bmpData = dataImage.LockBits(rectImage, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); try { byte[] pixels = new byte[bmpData.Stride * bmpData.Height]; int index = 0; for (int y = 0; y < data.Size; y++) { for (int x = 0; x < data.Size; x++) { Color color = (data[x, y] ? options.ForeColor : options.BackColor); pixels[index++] = color.B; pixels[index++] = color.G; pixels[index++] = color.R; pixels[index++] = color.A; } } Marshal.Copy(pixels, 0, bmpData.Scan0, pixels.Length); } finally { dataImage.UnlockBits(bmpData); } return dataImage; } /// /// 转换为zxing Level /// /// /// private static ErrorCorrectionLevel GetErrorCorrectionLevel(QRECLevel level) { switch (level) { case QRECLevel.H: return ErrorCorrectionLevel.H; case QRECLevel.L: return ErrorCorrectionLevel.L; case QRECLevel.Q: return ErrorCorrectionLevel.Q; case QRECLevel.M: return ErrorCorrectionLevel.M; default: return ErrorCorrectionLevel.H; } } /// /// 二维码版本对应像素 /// /// /// public static int VersionToPixel(int version) { return (version - 1) * 4 + 21; } } }