以前做工厂项目,用到条码工具,从网上找了个开源的,后来发现兼容性并不好,于是自己网上搜搜文章,就开始动手自己干。关于128码的原理介绍可以看看这个:
CODE 128和GS1-128|条码基本知识|学习条码规格和读取技术的站点“条码讲座”|基恩士
其实条形码的生成,都是差不多的思路,每个字符都是由几个不同宽窄的条形符号代表的,多个字符从而有更多的条形符号组合在一起形成1个条形码。字符串越长,生成的条形码就越长。
代码思路也很简单:
1、构建code128,字符(字母、数字、特殊符号)对应的条码描述,初始化条码生成的一些自定义设置
2、输入字符,根据每给字符根据字典映射对应的条码描述符,根据描述符依次绘制条形码。
3、输出图片,就结束了。
废话不多说,上代码:
## 辅助代码
public class BarCode128Settings
{
public float NarrowWidth { get; set; } = 2f;
public Color BackColor { get; set; } = Color.White;
public Color BarColor { get; set; } = Color.Black;
public float Height { get; set; } = 60f;
/// <summary>
/// 上据顶部的边距/条码与文本中之间的边距/文本或条码据下部的边距
/// </summary>
public float Gutter { get; set; } = 5f;
public int Width { get; set; }
public bool DisplayText { get; set; } = true;
public Font TextFont { get; set; } = new Font("宋体", 12);
}
public interface IBarCodeEntity
{
}
public abstract class AbsBarCodeEntity
{
public byte Id { get; set; }
public string BandCode { get; set; }
}
public class BarCode128Entity: AbsBarCodeEntity
{
public BarCode128Entity()
{
}
public BarCode128Entity(byte id, string codeA, string codeB, string codeC, string bandCode)
{
Id = id;
CodeA = codeA;
CodeB = codeB;
CodeC = codeC;
BandCode = bandCode;
}
public string CodeA { get; set; }
public string CodeB { get; set; }
public string CodeC { get; set; }
}
## 代码主题
/// <summary>
/// code128条码生成器
/// </summary>
public class BarCodeCreator
{
public const byte Code128StartA = 103;
public const byte Code128StartB = 104;
public const byte Code128StartC = 105;
public const string EndBandCode = "2331112";
/// <summary>
/// CodeA、CodeB转CodeC
/// </summary>
public const byte CodeC = 99;
/// <summary>
/// CodeA、CodeC转CodeB
/// </summary>
public const byte CodeB = 100;
/// <summary>
/// CodeB、CodeC转CodeA
/// </summary>
public const byte CodeA = 101;
private List<BarCode128Entity> _code128Tables = new List<BarCode128Entity>(107);
private BarCode128Settings _settings;
private void AddBarCode128Entity(byte id, string codeA, string codeB, string codeC, string bandCode)
{
_code128Tables.Add(new BarCode128Entity(id, codeA, codeB, codeC, bandCode));
}
public BarCodeCreator(BarCode128Settings settings)
{
_settings = settings;
if (_settings.NarrowWidth < 1) throw new FormatException(#34;{nameof(_settings.NarrowWidth)}值不能小于1");
#region 构建数据表
AddBarCode128Entity(0, " ", " ", "00", "212222");
AddBarCode128Entity(1, "!", "!", "01", "222122");
AddBarCode128Entity(2, "\"", "\"", "02", "222221");
AddBarCode128Entity(3, "#", "#", "03", "121223");
AddBarCode128Entity(4, "#34;, "#34;, "04", "121322");
AddBarCode128Entity(5, "%", "%", "05", "131222");
AddBarCode128Entity(6, "&", "&", "06", "122213");
AddBarCode128Entity(7, "'", "'", "07", "122312");
AddBarCode128Entity(8, "(", "(", "08", "132212");
AddBarCode128Entity(9, ")", ")", "09", "221213");
AddBarCode128Entity(10, "*", "*", "10", "221312");
AddBarCode128Entity(11, "+", "+", "11", "231212");
AddBarCode128Entity(12, ",", ",", "12", "112232");
AddBarCode128Entity(13, "-", "-", "13", "122132");
AddBarCode128Entity(14, ".", ".", "14", "122231");
AddBarCode128Entity(15, "/", "/", "15", "113222");
AddBarCode128Entity(16, "0", "0", "16", "123122");
AddBarCode128Entity(17, "1", "1", "17", "123221");
AddBarCode128Entity(18, "2", "2", "18", "223211");
AddBarCode128Entity(19, "3", "3", "19", "221132");
AddBarCode128Entity(20, "4", "4", "20", "221231");
AddBarCode128Entity(21, "5", "5", "21", "213212");
AddBarCode128Entity(22, "6", "6", "22", "223112");
AddBarCode128Entity(23, "7", "7", "23", "312131");
AddBarCode128Entity(24, "8", "8", "24", "311222");
AddBarCode128Entity(25, "9", "9", "25", "321122");
AddBarCode128Entity(26, ":", ":", "26", "321221");
AddBarCode128Entity(27, ";", ";", "27", "312212");
AddBarCode128Entity(28, "<", "<", "28", "322112");
AddBarCode128Entity(29, "=", "=", "29", "322211");
AddBarCode128Entity(30, ">", ">", "30", "212123");
AddBarCode128Entity(31, "?", "?", "31", "212321");
AddBarCode128Entity(32, "@", "@", "32", "232121");
AddBarCode128Entity(33, "A", "A", "33", "111323");
AddBarCode128Entity(34, "B", "B", "34", "131123");
AddBarCode128Entity(35, "C", "C", "35", "131321");
AddBarCode128Entity(36, "D", "D", "36", "112313");
AddBarCode128Entity(37, "E", "E", "37", "132113");
AddBarCode128Entity(38, "F", "F", "38", "132311");
AddBarCode128Entity(39, "G", "G", "39", "211313");
AddBarCode128Entity(40, "H", "H", "40", "231113");
AddBarCode128Entity(41, "I", "I", "41", "231311");
AddBarCode128Entity(42, "J", "J", "42", "112133");
AddBarCode128Entity(43, "K", "K", "43", "112331");
AddBarCode128Entity(44, "L", "L", "44", "132131");
AddBarCode128Entity(45, "M", "M", "45", "113123");
AddBarCode128Entity(46, "N", "N", "46", "113321");
AddBarCode128Entity(47, "O", "O", "47", "133121");
AddBarCode128Entity(48, "P", "P", "48", "313121");
AddBarCode128Entity(49, "Q", "Q", "49", "211331");
AddBarCode128Entity(50, "R", "R", "50", "231131");
AddBarCode128Entity(51, "S", "S", "51", "213113");
AddBarCode128Entity(52, "T", "T", "52", "213311");
AddBarCode128Entity(53, "U", "U", "53", "213131");
AddBarCode128Entity(54, "V", "V", "54", "311123");
AddBarCode128Entity(55, "W", "W", "55", "311321");
AddBarCode128Entity(56, "X", "X", "56", "331121");
AddBarCode128Entity(57, "Y", "Y", "57", "312113");
AddBarCode128Entity(58, "Z", "Z", "58", "312311");
AddBarCode128Entity(59, "[", "[", "59", "332111");
AddBarCode128Entity(60, "\\", "\\", "60", "314111");
AddBarCode128Entity(61, "]", "]", "61", "221411");
AddBarCode128Entity(62, "^", "^", "62", "431111");
AddBarCode128Entity(63, "_", "_", "63", "111224");
AddBarCode128Entity(64, "NUL", "`", "64", "111422");
AddBarCode128Entity(65, "SOH", "a", "65", "121124");
AddBarCode128Entity(66, "STX", "b", "66", "121421");
AddBarCode128Entity(67, "ETX", "c", "67", "141122");
AddBarCode128Entity(68, "EOT", "d", "68", "141221");
AddBarCode128Entity(69, "ENQ", "e", "69", "112214");
AddBarCode128Entity(70, "ACK", "f", "70", "112412");
AddBarCode128Entity(71, "BEL", "g", "71", "122114");
AddBarCode128Entity(72, "BS", "h", "72", "122411");
AddBarCode128Entity(73, "HT", "i", "73", "142112");
AddBarCode128Entity(74, "LF", "j", "74", "142211");
AddBarCode128Entity(75, "VT", "k", "75", "241211");
AddBarCode128Entity(76, "FF", "l", "76", "221114");
AddBarCode128Entity(77, "CR", "m", "77", "413111");
AddBarCode128Entity(78, "SO", "n", "78", "241112");
AddBarCode128Entity(79, "SI", "o", "79", "134111");
AddBarCode128Entity(80, "DLE", "p", "80", "111242");
AddBarCode128Entity(81, "DC1", "q", "81", "121142");
AddBarCode128Entity(82, "DC2", "r", "82", "121241");
AddBarCode128Entity(83, "DC3", "s", "83", "114212");
AddBarCode128Entity(84, "DC4", "t", "84", "124112");
AddBarCode128Entity(85, "NAK", "u", "85", "124211");
AddBarCode128Entity(86, "SYN", "v", "86", "411212");
AddBarCode128Entity(87, "ETB", "w", "87", "421112");
AddBarCode128Entity(88, "CAN", "x", "88", "421211");
AddBarCode128Entity(89, "EM", "y", "89", "212141");
AddBarCode128Entity(90, "SUB", "z", "90", "214121");
AddBarCode128Entity(91, "ESC", "{", "91", "412121");
AddBarCode128Entity(92, "FS", "|", "92", "111143");
AddBarCode128Entity(93, "GS", "}", "93", "111341");
AddBarCode128Entity(94, "RS", "~", "94", "131141");
AddBarCode128Entity(95, "US", "DEL", "95", "114113");
AddBarCode128Entity(96, "FNC3", "FNC3", "96", "114311");
AddBarCode128Entity(97, "FNC2", "FNC2", "97", "411113");
AddBarCode128Entity(98, "SHIFT", "SHIFT", "98", "411311");
AddBarCode128Entity(99, "CODEC", "CODEC", "99", "113141");
AddBarCode128Entity(100, "CODEB", "FNC4", "CODEB", "114131");
AddBarCode128Entity(101, "FNC4", "CODEA", "CODEA", "311141");
AddBarCode128Entity(102, "FNC1", "FNC1", "FNC1", "411131");
AddBarCode128Entity(103, "StartA", "StartA", "StartA", "211412");
AddBarCode128Entity(104, "StartB", "StartB", "StartB", "211214");
AddBarCode128Entity(105, "StartC", "StartC", "StartC", "211232");
AddBarCode128Entity(106, "Stop", "Stop", "Stop", "2331112");
#endregion
}
/// <summary>
/// 生成128条码
/// </summary>
/// <param name="barCodeText">条码文本数据</param>
/// <param name="barCodeEncode">条码编码方式</param>
/// <returns>图形</returns>
public Bitmap GeneratorCodeImage(string barCodeText, BarCodeEncode barCodeEncode)
{
string displayText = barCodeText + ""; //可视条码
StringBuilder bandCode = new StringBuilder(); //转换成bar(b)/space(s)的代码。如:212423 表示:bbsbbssssbbsss
IList<int> displayTextIds = new List<int>(); //可视条码对应的id值集合
int startCode = Code128StartB; //起始位
var regNum = new Regex("\\d{2}");
switch (barCodeEncode)
{
case BarCodeEncode.Code128Auto:
{
var currentEncode = BarCodeEncode.Code128C; //当前编码类型
startCode = Code128StartC; //起始码值
if (barCodeText.Length < 2 || !regNum.IsMatch(barCodeText.Substring(0, 2)))
{
currentEncode = BarCodeEncode.Code128B;
startCode = Code128StartB;
}
while (barCodeText.Length != 0)
{
if (currentEncode == BarCodeEncode.Code128C)
{
if (barCodeText.Length >= 2)
{
//还有很多,且当前2位是数字
var numbers = barCodeText.Substring(0, 2);
if (regNum.IsMatch(numbers))
{
var entity = FindEntity(currentEncode, numbers);
displayTextIds.Add(entity.Id);
bandCode.Append(entity.BandCode);
barCodeText = barCodeText.Remove(0, 2);
}
else //当前2位不是数字 转CodeB
{
currentEncode = BarCodeEncode.Code128B;
var entity = FindEntity(CodeB);
displayTextIds.Add(entity.Id);
bandCode.Append(entity.BandCode);
}
}
else
{
//最后1个字符 转CodeB
currentEncode = BarCodeEncode.Code128B;
var entity = FindEntity(CodeB);
displayTextIds.Add(entity.Id);
bandCode.Append(entity.BandCode);
//最后1位处理
entity = FindEntityThrowNull(x => x.CodeB == barCodeText.Substring(0, 1), #34;没有找到代码({barCodeText.Substring(0, 1)})对应的实体对象");
displayTextIds.Add(entity.Id);
bandCode.Append(entity.BandCode);
barCodeText = barCodeText.Remove(0, 1);
break;
}
}
else if (currentEncode == BarCodeEncode.Code128B)
{
if (barCodeText.Length >= 2)
{
//还有很多,且当前2位是数字 转CodeC
if (regNum.IsMatch(barCodeText.Substring(0, 2)))
{
currentEncode = BarCodeEncode.Code128C;
var entity = FindEntity(CodeC);
displayTextIds.Add(entity.Id);
bandCode.Append(entity.BandCode);
}
else //当前2位不是数字 获取1位
{
var entity = FindEntityThrowNull(x => x.CodeB == barCodeText.Substring(0, 1), #34;没有找到代码({barCodeText.Substring(0, 1)})对应的实体对象");
displayTextIds.Add(entity.Id);
bandCode.Append(entity.BandCode);
barCodeText = barCodeText.Remove(0, 1);
}
}
else
{
//最后1个字符
var entity = FindEntityThrowNull(x => x.CodeB == barCodeText.Substring(0, 1), #34;没有找到代码({barCodeText.Substring(0, 1)})对应的实体对象");
displayTextIds.Add(entity.Id);
bandCode.Append(entity.BandCode);
barCodeText = barCodeText.Remove(0, 1);
}
}
}
}
break;
case BarCodeEncode.Code128C:
case BarCodeEncode.EAN128:
{
startCode = Code128StartC;
if (barCodeText.Length % 2 == 1) throw new Exception("字符长度必须是偶数");
if (barCodeEncode == BarCodeEncode.EAN128)
{//增加Fun1
displayTextIds.Add(102);
bandCode.Append("411131");
}
while (barCodeText.Length != 0)
{
var numbers = barCodeText.Substring(0, 2);
if (!regNum.IsMatch(numbers))
{
throw new Exception(#34;字符{numbers}不是数字!");
}
var entity = FindEntity(BarCodeEncode.Code128C, numbers);
bandCode.Append(entity.BandCode);
displayTextIds.Add(entity.Id);
barCodeText = barCodeText.Remove(0, 2);
}
}
break;
//CodeA/CodeB
case BarCodeEncode.Code128A:
case BarCodeEncode.Code128B:
{
startCode = barCodeEncode == BarCodeEncode.Code128A
? Code128StartA
: Code128StartB;
while (barCodeText.Length != 0)
{
var entity = FindEntity(barCodeEncode, barCodeText.Substring(0, 1));
bandCode.Append(entity.BandCode);
displayTextIds.Add(entity.Id);
barCodeText = barCodeText.Remove(0, 1);
}
}
break;
default:
throw new NotImplementedException("不受支持的编码类型!");
}
if (displayTextIds.Count == 0) throw new Exception("错误的编码,无数据");
//获得校验位
var startEntity = FindEntity(startCode);
var check = startEntity.Id + 0;
for (int i = 0; i < displayTextIds.Count; i++)
{
check += displayTextIds[i] * (i + 1);
}
check = check % 103;
bandCode.Insert(0, startEntity.BandCode);
bandCode.Append(FindEntity(check).BandCode); //增加 校验位 BandCode
bandCode.Append(EndBandCode); //增加结束位 BandCode
Bitmap barCodeImage = DrawImage(bandCode.ToString());
DrawBarCodeText(barCodeImage, displayText);
return barCodeImage;
}
/// <summary>
/// 获取目标对应的数据
/// </summary>
/// <param name="barCodeEncode">编码类别</param>
/// <param name="codeValue">数值 A b 30</param>
/// <returns>编码</returns>
private BarCode128Entity FindEntity(BarCodeEncode barCodeEncode, string codeValue)
{
if (_code128Tables == null || _code128Tables.Count == 0)
{
throw new ArgumentNullException("code128映射表为空!");
}
switch (barCodeEncode)
{
case BarCodeEncode.Code128A:
{
foreach (var entity in _code128Tables)
{
if (entity.CodeA == codeValue)
return entity;
}
}
break;
case BarCodeEncode.Code128B:
{
foreach (var entity in _code128Tables)
{
if (entity.CodeB == codeValue)
return entity;
}
}
break;
case BarCodeEncode.Code128C:
case BarCodeEncode.EAN128:
{
foreach (var entity in _code128Tables)
{
if (entity.CodeC == codeValue)
return entity;
}
}
break;
case BarCodeEncode.Code128Auto:
throw new ArgumentException("字符对应的真实编码不能为Auto!");
default:
break;
}
throw new ArgumentNullException(#34;没有找到对应到编码数值,当前文本非法({codeValue})");
}
/// <summary>
/// 根据编号获得条纹
/// </summary>
/// <param name="codeId"></param>
/// <returns></returns>
private BarCode128Entity FindEntity(int codeId)
{
return FindEntityThrowNull(x => x.Id == codeId, #34;没有找到id({codeId})对应的实体对象");
}
private BarCode128Entity FindEntityThrowNull(Predicate<BarCode128Entity> predicate,
string throwMessage = "根据条件没有找到实体对象!", bool throwable = true)
{
foreach (var entity in _code128Tables)
{
if (predicate.Invoke(entity)) return entity;
}
if (throwable) throw new Exception(throwMessage);
return null;
}
/// <summary>
/// 获得条码图形
/// </summary>
/// <param name="bandCode">编码后的文字类似于:1233412312312314123123124</param>
/// <returns>图形</returns>
private Bitmap DrawImage(string bandCode)
{
var margin = _settings.Gutter;
var barHeight = _settings.Height - margin * 2;
char[] everyBandCode = bandCode.ToCharArray();
float barCodeWidth = 0;
for (int i = 0; i < everyBandCode.Length; i++)
{
barCodeWidth += Int32.Parse(everyBandCode[i].ToString()) * _settings.NarrowWidth;
}
var marginLR = 2 * 10 * _settings.NarrowWidth;
barCodeWidth += marginLR;//左右两边空白
Bitmap codeImage = new Bitmap((int)barCodeWidth, (int)(_settings.Height));
using (Graphics g = Graphics.FromImage(codeImage))
{
float offsetX = marginLR / 2;//沿着X轴向右平移
g.Clear(_settings.BackColor);
var barBrush = new SolidBrush(_settings.BarColor);
for (int i = 0; i < everyBandCode.Length; i++)
{
float width = Int32.Parse(everyBandCode[i].ToString()) * _settings.NarrowWidth; //获取宽度
if (!((i & 1) == 0))//space
{
//g.FillRectangle(Brushes.White, new RectangleF(offsetX, (int)margin, width, height));
}
else //Bar
{
g.FillRectangle(barBrush, new RectangleF(offsetX, (int)margin, width, barHeight));
}
offsetX += width;
}
//g.FillRectangle(Brushes.White, new RectangleF(offsetX, (int)margin, gutter/2, height));
g.Flush();
}
return codeImage;
}
/// <summary>
/// 显示可见条码文字 如果小于40 不显示文字
/// </summary>
/// <param name="bitmap">图形</param>
private void DrawBarCodeText(Bitmap bitmap, string displayText)
{
if (_settings.TextFont == null || _settings.DisplayText == false) return;
using (Graphics g = Graphics.FromImage(bitmap))
{
SizeF drawSize = g.MeasureString(displayText, _settings.TextFont);
if (drawSize.Height > bitmap.Height - 10 || drawSize.Width > bitmap.Width)
{
g.Flush();
g.Dispose();
return;
}
int starY = bitmap.Height - (int)drawSize.Height - (int)_settings.Gutter;
g.FillRectangle(new SolidBrush(_settings.BackColor), new Rectangle(0, starY, bitmap.Width, (int)drawSize.Height));
g.DrawString(displayText, _settings.TextFont, new SolidBrush(_settings.BarColor),
new RectangleF(0, starY + _settings.Gutter, bitmap.Width, drawSize.Height),
new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
g.Flush();
g.Dispose();
}
}
}
/// <summary>
/// 条码编码类别
/// </summary>
public enum BarCodeEncode
{
Code128A,
Code128B,
Code128C,
EAN128,
Code128Auto
}