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;
}
}
}