You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1302 lines
56 KiB
C#

2 months ago
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace NetLibrary.Express
{
/// <summary>
/// 条形码接口
/// </summary>
public interface IBarCode
{
string RawData { get; }
/// <summary>
/// 条形码对应的数据
/// </summary>
string EncodedData { get; }
/// <summary>
/// 当前条形码标准
/// </summary>
string BarCodeType { get; }
/// <summary>
/// 得到条形码对应的图片
/// </summary>
/// <returns></returns>
Image GetBarCodeImage();
}
/// <summary>
/// Code128抽象类
/// </summary>
public abstract class absCode128 : IBarCode
{
protected string _encodedData;//编码数据
protected string _rawData;//原始数据
protected string _presentationData = null;//在条形码下面显示给人看的数据,如果为空,则取原始数据
protected bool _dataDisplay = true;//是否显示字体
protected byte _barCellWidth = 1;//模块单位宽度单位Pix 默认1
protected bool _showBlank = true;//是否显示左右空白
protected byte _horizontalMulriple = 10;//水平左右空白对应模块的倍数
protected byte _verticalMulriple = 8;//垂直上下空白对应模块的倍数
protected byte _barHeight = 32;//条码高度单位Pix 默认32
protected Color _backColor = Color.White;//条码背景色
protected Color _barColor = Color.Black;//条码颜色
protected byte _fontPadding;//字体与条形码的空间间隔
protected float _emSize;//字体大小
protected FontFamily _fontFamily;//字体样式
protected FontStyle _fontStyle;//字体样式
protected StringAlignment _textAlignment;//字体布局位置
protected Color _fontColor;//字体颜色
protected bool _fontPositionOnBottom;//字体位置是否是底部,如果不是,则在顶部
/// <summary>
/// 当前条形码种类
/// </summary>
public string BarCodeType
{
get
{
return System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name;
}
}
/// <summary>
/// 原始数据
/// </summary>
public string RawData
{
get { return this._rawData; }
}
/// <summary>
/// 条码展示数据
/// </summary>
public string PresentationData
{
get { return string.IsNullOrEmpty(this._presentationData) ? this._rawData : this._presentationData; }
}
/// <summary>
/// 条形码对应的编码数据
/// </summary>
public string EncodedData
{
get { return this._encodedData; }
}
/// <summary>
/// 是否在条形码上显示展示数据
/// </summary>
public bool DataDisplay
{
get { return this._dataDisplay; }
set { this._dataDisplay = value; }
}
/// <summary>
/// 条码高度必须至少是条码宽度的0.15倍或6.35mm,两者取大者
/// 默认按照实际为32,单位mm
/// </summary>
public byte BarHeight
{
get { return this._barHeight; }
set
{
this._barHeight = value;
}
}
/// <summary>
/// 模块宽度 单位pix
/// 默认宽度 1pix
/// </summary>
public byte BarCellWidth
{
get { return this._barCellWidth; }
set
{
if (value == 0)
{
this._barCellWidth = 1;
}
else
{
this._barCellWidth = value;
}
}
}
/// <summary>
/// 是否显示左右空白,默认标准显示
/// </summary>
public bool ShowBlank
{
get { return this._showBlank; }
set
{
this._showBlank = value;
}
}
/// <summary>
/// 左右空白对应模块宽度的倍数,国际标准最小为10如果低于10则取10
/// </summary>
public byte HorizontalMulriple
{
get { return this._horizontalMulriple; }
set
{
if (value < 10)
{
this._horizontalMulriple = 10;
}
else
{
this._horizontalMulriple = value;
}
}
}
/// <summary>
/// 水平空白pix
/// </summary>
public int HorizontalMargin
{
get
{
if (this.ShowBlank)
{
return this._barCellWidth * this._horizontalMulriple;
}
else
{
return 0;
}
}
}
/// <summary>
/// 垂直上下空白对应模块的倍数
/// </summary>
public byte VerticalMulriple
{
get { return this._verticalMulriple; }
set
{
this._verticalMulriple = value;
}
}
/// <summary>
/// 垂直空白
/// </summary>
public int VerticalMargin
{
get
{
if (this.ShowBlank)
{
return this._barCellWidth * this._verticalMulriple;
}
else
{
return 0;
}
}
}
/// <summary>
/// 字体与条形码的空间间隔,单位Pix
/// </summary>
public byte FontPadding
{
get { return this._fontPadding; }
set
{
this._fontPadding = value;
}
}
/// <summary>
/// 字体大小
/// </summary>
public float FontSize
{
get { return this._emSize; }
set { this._emSize = value; }
}
/// <summary>
/// 字体样式
/// </summary>
public FontFamily FontFamily
{
get { return this._fontFamily; }
set { this._fontFamily = value; }
}
/// <summary>
/// 字体样式
/// </summary>
public FontStyle FontStyle
{
get { return this._fontStyle; }
set { this._fontStyle = value; }
}
/// <summary>
/// 字体布局位置
/// </summary>
public StringAlignment TextAlignment
{
get { return this._textAlignment; }
set { this._textAlignment = value; }
}
/// <summary>
/// 字体颜色
/// </summary>
public Color FontColor
{
get { return this._fontColor; }
set { this._fontColor = value; }
}
public absCode128(string rawData)
{
this._rawData = rawData;
if (string.IsNullOrEmpty(this._rawData))
{
throw new Exception("空字符串无法生成条形码");
}
this._rawData = this._rawData.Trim();
if (!this.RawDataCheck())
{
throw new Exception(rawData + " 不符合 " + this.BarCodeType + " 标准");
}
this._encodedData = this.GetEncodedData();
//是否加入检验可编码最大字符数超出标准48貌似只在EAN128中有规定必须不超出48
this.FontInit();
}
/// <summary>
/// 字体初始化
/// </summary>
private void FontInit()
{
this._fontPadding = 4;
this._emSize = 12;
this._fontFamily = new FontFamily("Times New Roman");
this._fontStyle = FontStyle.Regular;
this._textAlignment = StringAlignment.Center;
this._fontColor = Color.Black;
}
protected int GetBarCodePhyWidth()
{
//在212222这种BS单元下要计算bsGroup对应模块宽度的倍率
//应该要将总长度减去1因为Stop对应长度为7然后结果乘以11再除以6与左右空白相加后再加上2Stop比正常的BS多出2个模块组
int bsNum = (this._encodedData.Length - 1) * 11 / 6 + 2;//+ (this._showBlank ? this._blankMulriple * 2 : 0)
return bsNum * this._barCellWidth;
}
/// <summary>
/// 数据输入正确性验证
/// </summary>
/// <returns></returns>
protected abstract bool RawDataCheck();
/// <summary>
/// 获取当前Data对应的编码数据(条空组合)
/// </summary>
/// <returns></returns>
protected abstract string GetEncodedData();
#region 注销
///// <summary>
///// 得到条形码对应的图片,Graphics画图的读不出来
///// </summary>
///// <returns></returns>
//public Image GetBarCodeImage()
//{
// float x, y;
// x = this._blockWidth * this._blankMulriple;
// y = x;
// Bitmap image = new Bitmap((int)this.GetBarCodePhyWidth() + 1, (int)(this._barHeight + y * 2) + 1);
// Graphics g = Graphics.FromImage(image);
// g.Clear(this._backColor);//清除背景
// g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// g.PageUnit = GraphicsUnit.Display;
// Pen p = new Pen(this._barColor);
// for (int i = 0; i < this._encodedData.Length; i++)
// {
// byte num = (byte)char.GetNumericValue(this._encodedData[i]);
// if (i % 2 == 0)
// {
// //偶数位为bar,奇数位为sp,除了最后一个Stop其他每个字符都是6位
// p.Width = num * this._blockWidth;
// g.DrawLine(p, x, y, x, y + this._barHeight);
// }
// x += num * this._blockWidth;
// }
// System.IO.MemoryStream ms = new System.IO.MemoryStream();
// image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
// //结束绘制
// p.Dispose();
// g.Dispose();
// image.Dispose();
// return Image.FromStream(ms);
//}
#endregion
/// <summary>
/// 获取完整的条形码
/// </summary>
/// <returns></returns>
public Image GetBarCodeImage()
{
Image barImage = this.GetBarOnlyImage();
int width = barImage.Width;
int height = barImage.Height;
width += this.HorizontalMargin * 2;
height += this.VerticalMargin * 2;
if (this._dataDisplay)
{
height += this._fontPadding + (int)this._emSize;
}
Image image = new Bitmap(width, height);
Graphics g = Graphics.FromImage(image);
g.Clear(this._backColor);
g.DrawImage(barImage, this.HorizontalMargin, this.VerticalMargin, barImage.Width, barImage.Height);
if (this._dataDisplay)
{
Font drawFont = new Font(this._fontFamily, this._emSize, this._fontStyle, GraphicsUnit.Pixel);
Brush drawBrush = new SolidBrush(this._fontColor);
StringFormat drawFormat = new StringFormat();
drawFormat.Alignment = this._textAlignment;
RectangleF reF = new RectangleF(0, barImage.Height + this.VerticalMargin + this._fontPadding, width, this._emSize);
g.DrawString(this.PresentationData, drawFont, drawBrush, reF, drawFormat);
drawFont.Dispose();
drawBrush.Dispose();
drawFormat.Dispose();
}
System.IO.MemoryStream ms = new System.IO.MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
//结束绘制
g.Dispose();
image.Dispose();
return Image.FromStream(ms);
}
/// <summary>
/// 获取仅包含条形码的图像
/// </summary>
/// <returns></returns>
private Image GetBarOnlyImage()
{
int width = (int)this.GetBarCodePhyWidth();
Bitmap image = new Bitmap(width, this._barHeight);
int ptr = 0;
for (int i = 0; i < this._encodedData.Length; i++)
{
int w = (int)char.GetNumericValue(this._encodedData[i]);
w *= this._barCellWidth;
Color c = i % 2 == 0 ? this._barColor : this._backColor;
for (int j = 0; j < w; j++)
{
for (int h = 0; h < this._barHeight; h++)
{
image.SetPixel(ptr, h, c);
}
ptr++;
}
}
return image;
}
}
/// <summary>
/// Code128基础相关类
/// </summary>
internal static class Code128
{
/*
* 128
* x 1.016mm0.250mm x 1mm,0.25~1.2
* 10x
* 32mm
*
* 165mm48使FNC1
*
* AIFNC1使
*
* ASCII
* 0~31 StartA
* 96~127 StartB
*
* EAN128使ASCII32
*/
/// <summary>
/// Code128条空排列集合1代表条b0代表空sIndex对应符号字符值S
/// </summary>
internal static readonly List<string> BSList = new List<string>()
{
"212222" , "222122" , "222221" , "121223" , "121322" , "131222" , "122213" , "122312" , "132212" , "221213" ,
"221312" , "231212" , "112232" , "122132" , "122231" , "113222" , "123122" , "123221" , "223211" , "221132" ,
"221231" , "213212" , "223112" , "312131" , "311222" , "321122" , "321221" , "312212" , "322112" , "322211" ,
"212123" , "212321" , "232121" , "111323" , "131123" , "131321" , "112313" , "132113" , "132311" , "211313" ,
"231113" , "231311" , "112133" , "112331" , "132131" , "113123" , "113321" , "133121" , "313121" , "211331" ,
"231131" , "213113" , "213311" , "213131" , "311123" , "311321" , "331121" , "312113" , "312311" , "332111" ,
"314111" , "221411" , "431111" , "111224" , "111422" , "121124" , "121421" , "141122" , "141221" , "112214" ,
"112412" , "122114" , "122411" , "142112" , "142211" , "241211" , "221114" , "413111" , "241112" , "134111" ,
"111242" , "121142" , "121241" , "114212" , "124112" , "124211" , "411212" , "421112" , "421211" , "212141" ,
"214121" , "412121" , "111143" , "111341" , "131141" , "114113" , "114311" , "411113" , "411311" , "113141" ,
"114131" , "311141" , "411131" , "211412" , "211214" , "211232" , "2331112"
};
#region 条空排列集合
//{
// "11011001100" , "11001101100" , "11001100110" , "10010011000" , "10010001100" ,
// "10001001100" , "10011001000" , "10011000100" , "10001100100" , "11001001000" ,
// "11001000100" , "11000100100" , "10110011100" , "10011011100" , "10011001110" ,
// "10111001100" , "10011101100" , "10011100110" , "11001110010" , "11001011100" ,
// "11001001110" , "11011100100" , "11001110100" , "11101101110" , "11101001100" ,
// "11100101100" , "11100100110" , "11101100100" , "11100110100" , "11100110010" ,
// "11011011000" , "11011000110" , "11000110110" , "10100011000" , "10001011000" ,
// "10001000110" , "10110001000" , "10001101000" , "10001100010" , "11010001000" ,
// "11000101000" , "11000100010" , "10110111000" , "10110001110" , "10001101110" ,
// "10111011000" , "10111000110" , "10001110110" , "11101110110" , "11010001110" ,
// "11000101110" , "11011101000" , "11011100010" , "11011101110" , "11101011000" ,
// "11101000110" , "11100010110" , "11101101000" , "11101100010" , "11100011010" ,
// "11101111010" , "11001000010" , "11110001010" , "10100110000" , "10100001100" ,
// "10010110000" , "10010000110" , "10000101100" , "10000100110" , "10110010000" ,
// "10110000100" , "10011010000" , "10011000010" , "10000110100" , "10000110010" ,
// "11000010010" , "11001010000" , "11110111010" , "11000010100" , "10001111010" ,
// "10100111100" , "10010111100" , "10010011110" , "10111100100" , "10011110100" ,
// "10011110010" , "11110100100" , "11110010100" , "11110010010" , "11011011110" ,
// "11011110110" , "11110110110" , "10101111000" , "10100011110" , "10001011110" ,
// "10111101000" , "10111100010" , "11110101000" , "11110100010" , "10111011110" ,
// "10111101110" , "11101011110" , "11110101110" , "11010000100" , "11010010000" ,
// "11010011100" , "1100011101011"
//};
#endregion
internal const byte FNC3_AB = 96, FNC2_AB = 97, SHIFT_AB = 98, CODEC_AB = 99, CODEB_AC = 100, CODEA_BC = 101;
internal const byte FNC4_A = 101, FNC4_B = 100;
internal const byte FNC1 = 102, StartA = 103, StartB = 104, StartC = 105;
internal const byte Stop = 106;
/// <summary>
/// 获取字符在字符集A中对应的符号字符值S
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
internal static byte GetSIndexFromA(char c)
{
byte sIndex = (byte)c;
//字符集A中 符号字符值S 若ASCII<32,则 S=ASCII+64 ,若95>=ASCII>=32,则S=ASCII-32
if (sIndex < 32)
{
sIndex += 64;
}
else if (sIndex < 96)
{
sIndex -= 32;
}
else
{
throw new NotImplementedException();
}
return sIndex;
}
/// <summary>
/// 获取字符在字符集B中对应的符号字符值S
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
internal static byte GetSIndexFromB(char c)
{
byte sIndex = (byte)c;
if (sIndex > 31 && sIndex < 128)
{
sIndex -= 32;//字符集B中ASCII码 减去32后就等于符号字符值
}
else
{
throw new NotImplementedException();
}
return sIndex;
}
internal static byte GetSIndex(CharacterSet characterSet, char c)
{
switch (characterSet)
{
case CharacterSet.A:
return GetSIndexFromA(c);
case CharacterSet.B:
return GetSIndexFromB(c);
default:
throw new NotImplementedException();
}
}
/// <summary>
/// 判断指定字符是否仅属于指定字符集
/// </summary>
/// <param name="characterSet"></param>
/// <param name="c"></param>
/// <returns></returns>
internal static bool CharOnlyBelongsTo(CharacterSet characterSet, char c)
{
switch (characterSet)
{
case CharacterSet.A:
return (byte)c < 32;
case CharacterSet.B:
return (byte)c > 95 && (byte)c < 128;
default:
throw new NotImplementedException();
}
}
/// <summary>
/// 判断指定字符是否不属于指定字符集
/// </summary>
/// <param name="characterSet"></param>
/// <param name="c"></param>
/// <returns></returns>
internal static bool CharNotBelongsTo(CharacterSet characterSet, char c)
{
switch (characterSet)
{
case CharacterSet.A:
return (byte)c > 95;
case CharacterSet.B:
return (byte)c < 32 && (byte)c > 127;
default:
throw new NotImplementedException();
}
}
/// <summary>
/// 当编码转换时,获取相应的切换符对应的符号字符值
/// </summary>
/// <param name="newCharacterSet"></param>
/// <returns></returns>
internal static byte GetCodeXIndex(CharacterSet newCharacterSet)
{
switch (newCharacterSet)
{
case CharacterSet.A:
return CODEA_BC;
case CharacterSet.B:
return CODEB_AC;
default:
return CODEC_AB;
}
}
/// <summary>
/// 获取转换后的字符集
/// </summary>
/// <param name="characterSet"></param>
/// <returns></returns>
internal static CharacterSet GetShiftCharacterSet(CharacterSet characterSet)
{
switch (characterSet)
{
case CharacterSet.A:
return CharacterSet.B;
case CharacterSet.B:
return CharacterSet.A;
default:
throw new NotImplementedException();
}
}
/// <summary>
/// 获取指定字符串应该采用的起始符对应的符号字符值
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
internal static byte GetStartIndex(string data, out CharacterSet startCharacterSet)
{
startCharacterSet = GetCharacterSet(data, 0);
switch (startCharacterSet)
{
case CharacterSet.A:
return StartA;
case CharacterSet.B:
return StartB;
default:
return StartC;
}
}
/// <summary>
/// 获取应采用的字符集
/// </summary>
/// <param name="data"></param>
/// <param name="startIndex">判断开始位置</param>
/// <returns></returns>
internal static CharacterSet GetCharacterSet(string data, int startIndex)
{
CharacterSet returnSet = CharacterSet.B;
if (Regex.IsMatch(data.Substring(startIndex), @"^\d{4,}"))
{
returnSet = CharacterSet.C;
}
else
{
byte byteC = GetProprietaryChar(data, startIndex);
returnSet = byteC < 32 ? CharacterSet.A : CharacterSet.B;
}
return returnSet;
}
/// <summary>
/// 从指定位置开始返回第一个大于95(并且小于128)或小于32的字符对应的值
/// </summary>
/// <param name="data"></param>
/// <param name="startIndex"></param>
/// <returns>如果没有任何字符匹配则返回255</returns>
internal static byte GetProprietaryChar(string data, int startIndex)
{
byte returnByte = byte.MaxValue;
for (int i = startIndex; i < data.Length; i++)
{
byte byteC = (byte)data[i];
if (byteC < 32 || byteC > 95 && byteC < 128)
{
returnByte = byteC;
break;
}
}
return returnByte;
}
/// <summary>
/// 获取字符串从指定位置开始连续出现数字的个数
/// </summary>
/// <param name="data"></param>
/// <param name="startIndex"></param>
/// <returns></returns>
internal static int GetDigitLength(string data, int startIndex)
{
int digitLength = data.Length - startIndex;//默认设定从起始位置开始至最后都是数字
for (int i = startIndex; i < data.Length; i++)
{
if (!char.IsDigit(data[i]))
{
digitLength = i - startIndex;
break;
}
}
return digitLength;
}
/// <summary>
/// 通用方法
/// </summary>
/// <param name="tempBuilder"></param>
/// <param name="sIndex"></param>
/// <param name="nowWeight"></param>
/// <param name="checkNum"></param>
internal static void EncodingCommon(StringBuilder tempBuilder, byte sIndex, ref int nowWeight, ref int checkNum)
{
tempBuilder.Append(BSList[sIndex]);
checkNum += nowWeight * sIndex;
nowWeight++;
}
/// <summary>
/// 获取原始数据对应的编码后数据(不包括起始符、特殊符(EAN128时)、检验符、终止符)
/// </summary>
/// <param name="rawData">编码对应的原始数据</param>
/// <param name="tempBuilder">编码数据容器</param>
/// <param name="nowCharacterSet">当前字符集</param>
/// <param name="i">字符串索引</param>
/// <param name="nowWeight">当前权值</param>
/// <param name="checkNum">当前检验值总和</param>
internal static void GetEncodedData(string rawData, StringBuilder tempBuilder, ref CharacterSet nowCharacterSet, ref int i, ref int nowWeight, ref int checkNum)
{//因为可能存在字符集C所以i与nowWeight可能存在不一致关系所以要分别定义
byte sIndex;
switch (nowCharacterSet)
{
case CharacterSet.A:
case CharacterSet.B:
for (; i < rawData.Length; i++)
{
if (char.IsDigit(rawData[i]))
{
//数字
int digitLength = GetDigitLength(rawData, i);
if (digitLength >= 4)
{
//转入CodeC
if (digitLength % 2 != 0)
{//奇数位数字在第一个数字之后插入CodeC字符
sIndex = GetSIndex(nowCharacterSet, (rawData[i]));
EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum);
i++;
}
nowCharacterSet = CharacterSet.C;
sIndex = GetCodeXIndex(nowCharacterSet);//插入CodeC切换字符
EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum);
GetEncodedData(rawData, tempBuilder, ref nowCharacterSet, ref i, ref nowWeight, ref checkNum);
return;
}
else
{
//如果小于4位数字则直接内部循环结束
for (int j = 0; j < digitLength; j++)
{
sIndex = GetSIndex(nowCharacterSet, (rawData[i]));
EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum);
i++;
}
i--;//因为上面循环结束后继续外部循环会导致i多加了1所以要减去1
continue;
}
}
else if (CharNotBelongsTo(nowCharacterSet, rawData[i]))
{//当前字符不属于目前的字符集
byte tempByte = GetProprietaryChar(rawData, i + 1);//获取当前字符后第一个属于A,或B的字符集
CharacterSet tempCharacterSet = GetShiftCharacterSet(nowCharacterSet);
if (tempByte != byte.MaxValue && CharOnlyBelongsTo(nowCharacterSet, (char)tempByte))
{
//加入转换符
sIndex = SHIFT_AB;
EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum);
sIndex = GetSIndex(tempCharacterSet, rawData[i]);
EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum);
continue;
}
else
{
//加入切换符
nowCharacterSet = tempCharacterSet;
sIndex = GetCodeXIndex(nowCharacterSet);
EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum);
GetEncodedData(rawData, tempBuilder, ref nowCharacterSet, ref i, ref nowWeight, ref checkNum);
return;
}
}
else
{
sIndex = GetSIndex(nowCharacterSet, rawData[i]);
EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum);
}
}
break;
default:
for (; i < rawData.Length; i += 2)
{
if (i != rawData.Length - 1 && char.IsDigit(rawData, i) && char.IsDigit(rawData, i + 1))
{
sIndex = byte.Parse(rawData.Substring(i, 2));
EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum);
}
else
{
nowCharacterSet = GetCharacterSet(rawData, i);
//插入转换字符
sIndex = GetCodeXIndex(nowCharacterSet);
EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum);
GetEncodedData(rawData, tempBuilder, ref nowCharacterSet, ref i, ref nowWeight, ref checkNum);
return;
}
}
break;
}
}
}
/// <summary>
/// Code128字符集
/// </summary>
internal enum CharacterSet
{
A,
B,
C
}
/// <summary>
/// 商品应用标识符标准 GBT 16986-2009
/// </summary>
internal static class AI
{
/// <summary>
/// GBT 16986-2009 定义的应用标识符集合
/// </summary>
public static readonly List<ApplicationIdentifier> AIList = new List<ApplicationIdentifier>()
{
//20系列货运包装箱代码
new ApplicationIdentifier("00", new List<DataFormat>(){ new DataFormat(new byte[]{18})}),
//01全球贸易项目代码
new ApplicationIdentifier("01", new List<DataFormat>(){ new DataFormat(new byte[]{14})}),
//02物流单元内贸易项目的GTIN
new ApplicationIdentifier("02", new List<DataFormat>(){ new DataFormat(new byte[]{14})}),
//10批号
new ApplicationIdentifier("10", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,20})}),
//11生产日期YYMMDD
new ApplicationIdentifier("11", new List<DataFormat>(){ new DataFormat(new byte[]{6})}),
//12付款截止日期YYMMDD
new ApplicationIdentifier("12", new List<DataFormat>(){ new DataFormat(new byte[]{6})}),
//13包装日期YYMMDD
new ApplicationIdentifier("13", new List<DataFormat>(){ new DataFormat(new byte[]{6})}),
//15保质期YYMMDD
new ApplicationIdentifier("15", new List<DataFormat>(){ new DataFormat(new byte[]{6})}),
//17有效期YYMMDD
new ApplicationIdentifier("17", new List<DataFormat>(){ new DataFormat(new byte[]{6})}),
//20产品变体
new ApplicationIdentifier("20", new List<DataFormat>(){ new DataFormat(new byte[]{2})}),
//21系列号
new ApplicationIdentifier("21", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,20})}),
//22医疗卫生行业产品二级数据
new ApplicationIdentifier("22", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,29})}),
//240附加产品标识
new ApplicationIdentifier("240", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//241客户方代码
new ApplicationIdentifier("241", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//242定制产品代码
new ApplicationIdentifier("242", new List<DataFormat>(){ new DataFormat(new byte[]{1,6})}),
//250二级系列号
new ApplicationIdentifier("250", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//251源实体参考代码
new ApplicationIdentifier("251", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//253全球文件/单证类型代码
new ApplicationIdentifier("253", new List<DataFormat>(){ new DataFormat(new byte[]{13}),new DataFormat(new byte[]{1,17})}),
//254GLN扩展部分代码
new ApplicationIdentifier("254", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,20})}),
//30可变数量
new ApplicationIdentifier("30", new List<DataFormat>(){ new DataFormat(new byte[]{1,8})}),
//31nn 贸易与物流量度
new ApplicationIdentifier("31", 4, new List<DataFormat>(){ new DataFormat(new byte[]{6})}),
//32nn 贸易与物流量度
new ApplicationIdentifier("32", 4, new List<DataFormat>(){ new DataFormat(new byte[]{6})}),
//33nn 贸易与物流量度
new ApplicationIdentifier("33", 4, new List<DataFormat>(){ new DataFormat(new byte[]{6})}),
//34nn 贸易与物流量度
new ApplicationIdentifier("34", 4, new List<DataFormat>(){ new DataFormat(new byte[]{6})}),
//35nn 贸易与物流量度
new ApplicationIdentifier("35", 4, new List<DataFormat>(){ new DataFormat(new byte[]{6})}),
//36nn 贸易与物流量度
new ApplicationIdentifier("36", 4, new List<DataFormat>(){ new DataFormat(new byte[]{6})}),
//37物流单元内贸易项目数量
new ApplicationIdentifier("37", new List<DataFormat>(){ new DataFormat(new byte[]{1,8})}),
//390n单一货币区内应付款金额
new ApplicationIdentifier("390", 4, new List<DataFormat>(){ new DataFormat(new byte[]{1,15})}),
//391n具有ISO货币代码的应付款金额
new ApplicationIdentifier("391", 4, new List<DataFormat>(){ new DataFormat(new byte[]{3}),new DataFormat(new byte[]{1,15})}),
//392n单一货币区内变量贸易项目应付款金额
new ApplicationIdentifier("392", 4, new List<DataFormat>(){ new DataFormat(new byte[]{1,15})}),
//393n具有ISO货币代码的变量贸易项目应付款金额
new ApplicationIdentifier("393", 4, new List<DataFormat>(){ new DataFormat(new byte[]{3}),new DataFormat(new byte[]{1,15})}),
//400客户订购单代码
new ApplicationIdentifier("400", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//401货物托运代码
new ApplicationIdentifier("401", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//402 装运标识代码
new ApplicationIdentifier("402", new List<DataFormat>(){ new DataFormat(new byte[]{17})}),
//403路径代码
new ApplicationIdentifier("403", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//410 交货地全球位置码
new ApplicationIdentifier("410", new List<DataFormat>(){ new DataFormat(new byte[]{13})}),
//411 受票方全球位置码
new ApplicationIdentifier("411", new List<DataFormat>(){ new DataFormat(new byte[]{13})}),
//412 最终目的地全球位置码
new ApplicationIdentifier("412", new List<DataFormat>(){ new DataFormat(new byte[]{13})}),
//413 交货地全球位置码
new ApplicationIdentifier("413", new List<DataFormat>(){ new DataFormat(new byte[]{13})}),
//414 标志物理位置的全球位置码
new ApplicationIdentifier("414", new List<DataFormat>(){ new DataFormat(new byte[]{13})}),
//415 开票方全球位置码
new ApplicationIdentifier("415", new List<DataFormat>(){ new DataFormat(new byte[]{13})}),
//420 同一邮政行政区域内交货地邮政编码
new ApplicationIdentifier("420", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//421 具有3位ISO国家(或地区)代码的交货地邮政编码
new ApplicationIdentifier("421", new List<DataFormat>(){ new DataFormat(new byte[]{3}),new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,9})}),
//422 贸易项目原产国(或地区)
new ApplicationIdentifier("422", new List<DataFormat>(){ new DataFormat(new byte[]{3})}),
//423 贸易项目初始加工国(或地区)
new ApplicationIdentifier("423", new List<DataFormat>(){ new DataFormat(new byte[]{3}),new DataFormat(new byte[]{1,12})}),
//424 贸易项目加工国(或地区)
new ApplicationIdentifier("424", new List<DataFormat>(){ new DataFormat(new byte[]{3})}),
//425 贸易项目拆分国(或地区)
new ApplicationIdentifier("425", new List<DataFormat>(){ new DataFormat(new byte[]{3})}),
//426 全程加工贸易项目的国家(或地区)
new ApplicationIdentifier("426", new List<DataFormat>(){ new DataFormat(new byte[]{3})}),
//7001 北约物资代码
new ApplicationIdentifier("7001", new List<DataFormat>(){ new DataFormat(new byte[]{13})}),
//7002 UN/ECE胴体肉与分割品分类
new ApplicationIdentifier("7002", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//7003 产品的有效日期和时间
new ApplicationIdentifier("7003", new List<DataFormat>(){ new DataFormat(new byte[]{8}),new DataFormat(new byte[]{1,2})}),
//703s 具有3位ISO国家(或地区)代码的加工者核准号码
new ApplicationIdentifier("703", new List<DataFormat>(){ new DataFormat(new byte[]{3}),new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,27})}),
//8001 卷装产品
new ApplicationIdentifier("8001", new List<DataFormat>(){ new DataFormat(new byte[]{14})}),
//8002 蜂窝移动电话标识符
new ApplicationIdentifier("8002", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,20})}),
//8003 全球可回收资产标识符
new ApplicationIdentifier("8003", new List<DataFormat>(){ new DataFormat(new byte[]{14}),new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,16})}),
//8004 全球单个资产标识符
new ApplicationIdentifier("8004", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//8005 单价
new ApplicationIdentifier("8005", new List<DataFormat>(){ new DataFormat(new byte[]{6})}),
//8006 贸易项目组件的标识符
new ApplicationIdentifier("8006", new List<DataFormat>(){ new DataFormat(new byte[]{14}),new DataFormat(new byte[]{2}),new DataFormat(new byte[]{2})}),
//8007 国际银行账号代码
new ApplicationIdentifier("8007", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//8008 产品生产的日期和时间
new ApplicationIdentifier("8008", new List<DataFormat>(){ new DataFormat(new byte[]{8}),new DataFormat(new byte[]{1,4})}),
//8018 全球服务关系代码
new ApplicationIdentifier("8018", new List<DataFormat>(){ new DataFormat(new byte[]{18})}),
//8020 付款单代码
new ApplicationIdentifier("8020", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,25})}),
//8100 GS1-128优惠券扩展代码-NSC+Offer Code
new ApplicationIdentifier("8100", new List<DataFormat>(){ new DataFormat(new byte[]{1}),new DataFormat(new byte[]{5})}),
//8101 GS1-128优惠券扩展代码-NSC+Offer Code + end of offer code
new ApplicationIdentifier("8101", new List<DataFormat>(){ new DataFormat(new byte[]{1}),new DataFormat(new byte[]{5}),new DataFormat(new byte[]{4})}),
//8102 GS1-128优惠券扩展代码-NSC
new ApplicationIdentifier("8102", new List<DataFormat>(){ new DataFormat(new byte[]{1}),new DataFormat(new byte[]{1})}),
//90 贸易伙伴之间相互约定的信息
new ApplicationIdentifier("90", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//91 公司内部信息
new ApplicationIdentifier("91", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//92 公司内部信息
new ApplicationIdentifier("92", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//93 公司内部信息
new ApplicationIdentifier("93", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//94 公司内部信息
new ApplicationIdentifier("94", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//95 公司内部信息
new ApplicationIdentifier("95", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//96 公司内部信息
new ApplicationIdentifier("96", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//97 公司内部信息
new ApplicationIdentifier("97", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//98 公司内部信息
new ApplicationIdentifier("98", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}),
//99 公司内部信息
new ApplicationIdentifier("99", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})})
};
/// <summary>
/// 需要遵循的预定义长度的应用标识符及其对应的总长度
/// </summary>
public static readonly List<KeyValuePair<string, byte>> PredefinedAILength = new List<KeyValuePair<string, byte>>()
{
new KeyValuePair<string,byte>("00",20),new KeyValuePair<string,byte>("01",16),new KeyValuePair<string,byte>("02",16),new KeyValuePair<string,byte>("03",16),
new KeyValuePair<string,byte>("04",18),new KeyValuePair<string,byte>("11",8),new KeyValuePair<string,byte>("12",8),new KeyValuePair<string,byte>("13",8),
new KeyValuePair<string,byte>("14",8),new KeyValuePair<string,byte>("15",8),new KeyValuePair<string,byte>("16",8),new KeyValuePair<string,byte>("17",8),
new KeyValuePair<string,byte>("18",8),new KeyValuePair<string,byte>("19",8),new KeyValuePair<string,byte>("20",4),new KeyValuePair<string,byte>("31",10),
new KeyValuePair<string,byte>("32",10),new KeyValuePair<string,byte>("33",10),new KeyValuePair<string,byte>("34",10),new KeyValuePair<string,byte>("35",10),
new KeyValuePair<string,byte>("36",10),new KeyValuePair<string,byte>("41",16)
};
/// <summary>
/// 获取字符串对应的 第一个 商品应用标识
/// </summary>
/// <param name="rawData"></param>
/// <returns></returns>
internal static ApplicationIdentifier GetAI(string rawData)
{
return AIList.Where(ai => rawData.StartsWith(ai.AI)).FirstOrDefault();
}
/// <summary>
/// 判断指定字符串是否是预定义长度应用标识符
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
internal static bool IsPredefinedAI(string data)
{
KeyValuePair<string, byte> temp = PredefinedAILength.Where(ai => data.StartsWith(ai.Key) && data.Length == ai.Value).FirstOrDefault();
return !string.IsNullOrEmpty(temp.Key);
}
/// <summary>
/// 判断指定字符串是否是符合指定应用标识规范
/// </summary>
/// <param name="ai"></param>
/// <param name="aiStr"></param>
/// <returns></returns>
internal static bool IsRight(ApplicationIdentifier ai, string aiStr)
{
//标识符部分字符串必须以相同的AI开头
if (!aiStr.StartsWith(ai.AI) || aiStr.Length > ai.MaxLength || aiStr.Length < ai.MinLength)
{
return false;
}
//如果AILength与ai对应的AI长度不一致时还需检验后续几个字符是否是数字
for (int i = ai.AI.Length; i < ai.AILength; i++)
{
if (!char.IsDigit(aiStr[i]))
{
return false;
}
}
int ptr = ai.AILength;
for (int i = 0; i < ai.DataWithoutAI.Count; i++)
{
DataFormat df = ai.DataWithoutAI[i];
for (int j = 0; j < df.Length[df.Length.Length - 1]; j++)
{
if ((df.Character == AICharacter.n && !char.IsDigit(aiStr[ptr])) || (byte)aiStr[ptr] < 33 || (byte)aiStr[ptr] > 126)
{
return false;
}
ptr++;
if (ptr >= aiStr.Length)
{
break;
}
}
}
return true;
}
}
/// <summary>
/// 商品标识符的数据类型范围
/// </summary>
[Flags]
internal enum AICharacter
{
/// <summary>
/// 数字
/// </summary>
n = 1,
/// <summary>
/// 字母
/// </summary>
a = 2
}
/// <summary>
/// 商品应用标识
/// </summary>
internal sealed class ApplicationIdentifier
{
private bool _isFixedLength;
private string _ai;
private byte _aiLength;
private List<DataFormat> _dataWithoutAI;
private byte _minLength;
private byte _maxLength;
public ApplicationIdentifier(string ai, List<DataFormat> dataWithoutAI)
: this(ai, (byte)ai.Length, dataWithoutAI)
{
}
public ApplicationIdentifier(string ai, byte aiLength, List<DataFormat> dataWithoutAI)
{
this._ai = ai;
this._aiLength = aiLength;
this._dataWithoutAI = dataWithoutAI;
this._minLength = aiLength;
this._maxLength = aiLength;
for (int i = 0; i < this._dataWithoutAI.Count; i++)
{
byte[] temp = this._dataWithoutAI[i].Length;
this._minLength += temp[0];
this._maxLength += temp[temp.Length - 1];
}
this._isFixedLength = this._minLength == this._maxLength;
}
/// <summary>
/// 商品应用标识符
/// </summary>
public string AI
{
get { return this._ai; }
}
/// <summary>
/// 标识符长度
/// </summary>
public byte AILength
{
get { return this._aiLength; }
}
/// <summary>
/// 排除标识符后字符串的数据格式
/// </summary>
public List<DataFormat> DataWithoutAI
{
get { return this._dataWithoutAI; }
}
/// <summary>
/// 是否定长
/// </summary>
public bool IsFixedLength
{
get { return this._isFixedLength; }
}
/// <summary>
/// 获取该商品应用标识允许的最小长度(包含AI)
/// </summary>
/// <returns></returns>
public byte MinLength
{
get { return this._minLength; }
}
/// <summary>
/// 获取该商品应用标识允许的最大长度(包含AI)
/// </summary>
/// <returns></returns>
public byte MaxLength
{
get { return this._maxLength; }
}
}
/// <summary>
/// 数据格式
/// </summary>
internal sealed class DataFormat
{
private AICharacter _character;
private byte[] _length;
/// <summary>
/// 默认数据格式为数字
/// </summary>
/// <param name="length"></param>
public DataFormat(byte[] length)
: this(AICharacter.n, length)
{
}
public DataFormat(AICharacter character, byte[] length)
{
this._character = character;
this._length = length;
}
/// <summary>
/// 数据类型
/// </summary>
public AICharacter Character
{ get { return this._character; } }
/// <summary>
/// 数据长度数组长度为1时表示定长
/// </summary>
public byte[] Length
{ get { return this._length; } }
}
/// <summary>
/// GS1-128(UCC/EAN128)条形码遵循标准GB/T 16986-2009
/// </summary>
public class GS1_128 : absCode128
{
private List<string> _aiList = new List<string>();//rawData分割后符合商品应用标识规范的字符串集合
/// <summary>
/// GS1-128(UCC/EAN128)条形码,非定长标识符后面必须跟空格,定长标识符带不带无所谓
/// </summary>
/// <param name="rawData">包含ASCII码表32~126其中32对应的空格sp用来通知生成FNC1分割符</param>
public GS1_128(string rawData)
: base(rawData)
{
}
/// <summary>
/// 对应的ASCII码范围为32~126,其中32对应的空格sp用来通知生成FNC1分割符
/// </summary>
/// <returns></returns>
protected override bool RawDataCheck()
{
this._presentationData = string.Empty;
string[] tempArray = this._rawData.Split((char)32);//以空格为分隔符将字符串进行分割
foreach (string ts in tempArray)
{
int ptr = 0;
do
{
string tempStr;
ApplicationIdentifier ai = AI.GetAI(ts.Substring(ptr));
int residuelength = ts.Length - ptr;//剩余字符串长度
if (ai == null || residuelength < ai.MinLength || (!ai.IsFixedLength && residuelength > ai.MaxLength))
{//第三个判定条件:因为不定长,而且经过空格分割,所以此时如果出现剩余字符串长度超出标识符最大长度规定,则认为错误
return false;
}
else
{
int length = Math.Min(ai.MaxLength, residuelength);
tempStr = ts.Substring(ptr, length);
ptr += length;
}
if (!AI.IsRight(ai, tempStr))
{
return false;
}
//展示数据加上括号
this._presentationData += string.Format("({0}){1}", tempStr.Substring(0, ai.AILength), tempStr.Substring(ai.AILength));
#region 修改为遵循预定义长度的AI后面才不加上FNC1,而不是实际定长的就不加上FNC1
//if (!ai.IsFixedLength)
//{
// tempStr += (char)32;//为不定长AI加上空格以便生成条形码时确认需要在此部分后面加入分隔符FNC1
//}
#endregion
this._aiList.Add(tempStr);
}
while (ptr < ts.Length);
}
//是否要将_aiList进行排序将预定长的放在前面以符合 先定长后变长 原则
//如果修改,则需将展示数据部分重新处理
return true;
}
protected override string GetEncodedData()
{
StringBuilder tempBuilder = new StringBuilder();
CharacterSet nowCharacterSet;
//校验字符
int checkNum = Code128.GetStartIndex(this._aiList[0], out nowCharacterSet);
tempBuilder.Append(Code128.BSList[checkNum]);//加上起始符
tempBuilder.Append(Code128.BSList[Code128.FNC1]);//加上第一个FNC1表示当前是GS1-128
checkNum += Code128.FNC1;
int nowWeight = 2;//当前权值
for (int i = 0; i < this._aiList.Count; i++)
{
string tempStr = this._aiList[i];
int nowIndex = 0;
#region 修改为遵循预定义长度的AI后面才不加上FNC1,而不是实际定长的就不加上FNC1
//bool isEndWithSP = tempStr[tempStr.Length - 1] == (char)32;
//if (isEndWithSP)
//{
// tempStr = tempStr.Substring(0, tempStr.Length - 1);
//}
#endregion
Code128.GetEncodedData(tempStr, tempBuilder, ref nowCharacterSet, ref nowIndex, ref nowWeight, ref checkNum);
#region 修改为遵循预定义长度的AI后面才不加上FNC1,而不是实际定长的就不加上FNC1
//if (isEndWithSP && i != this._aiList.Count - 1)
//{
// //非定长标识符后面加上FNC1此时FNC1作为分隔符存在
// Code128.EncodingCommon(tempBuilder, Code128.FNC1, ref nowWeight, ref checkNum);
//}
#endregion
if (!AI.IsPredefinedAI(tempStr) && i != this._aiList.Count - 1)
{
//非预定长标识符后面加上FNC1此时FNC1作为分隔符存在
Code128.EncodingCommon(tempBuilder, Code128.FNC1, ref nowWeight, ref checkNum);
}
}
checkNum %= 103;
tempBuilder.Append(Code128.BSList[checkNum]);//加上校验符
tempBuilder.Append(Code128.BSList[Code128.Stop]);//加上结束符
return tempBuilder.ToString();
}
}
}