1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Drawing;
5 using System.Linq;
6 using System.Text;
7 using System.Threading.Tasks;
8
9 namespace JXUtil
10 {
11 public class BarCode
12 {
13 private Hashtable _Code39 = new Hashtable();
14
15 /// <summary>
16 /// 内容
17 /// </summary>
18 public string Text { get; set; }
19
20 /// <summary>
21 /// 放大倍数
22 /// </summary>
23 public byte Magnify { get; set; }
24
25 /// <summary>
26 /// 图形高
27 /// </summary>
28 public int Height { get; set; }
29
30 /// <summary>
31 /// 字体大小
32 /// </summary>
33 public Font ViewFont { get; set; }
34
35 public BarCode()
36 {
37 _Code39.Add("A", "1101010010110");
38 _Code39.Add("B", "1011010010110");
39 _Code39.Add("C", "1101101001010");
40 _Code39.Add("D", "1010110010110");
41 _Code39.Add("E", "1101011001010");
42 _Code39.Add("F", "1011011001010");
43 _Code39.Add("G", "1010100110110");
44 _Code39.Add("H", "1101010011010");
45 _Code39.Add("I", "1011010011010");
46 _Code39.Add("J", "1010110011010");
47 _Code39.Add("K", "1101010100110");
48 _Code39.Add("L", "1011010100110");
49 _Code39.Add("M", "1101101010010");
50 _Code39.Add("N", "1010110100110");
51 _Code39.Add("O", "1101011010010");
52 _Code39.Add("P", "1011011010010");
53 _Code39.Add("Q", "1010101100110");
54 _Code39.Add("R", "1101010110010");
55 _Code39.Add("S", "1011010110010");
56 _Code39.Add("T", "1010110110010");
57 _Code39.Add("U", "1100101010110");
58 _Code39.Add("V", "1001101010110");
59 _Code39.Add("W", "1100110101010");
60 _Code39.Add("X", "1001011010110");
61 _Code39.Add("Y", "1100101101010");
62 _Code39.Add("Z", "1001101101010");
63 _Code39.Add("0", "1010011011010");
64 _Code39.Add("1", "1101001010110");
65 _Code39.Add("2", "1011001010110");
66 _Code39.Add("3", "1101100101010");
67 _Code39.Add("4", "1010011010110");
68 _Code39.Add("5", "1101001101010");
69 _Code39.Add("6", "1011001101010");
70 _Code39.Add("7", "1010010110110");
71 _Code39.Add("8", "1101001011010");
72 _Code39.Add("9", "1011001011010");
73 _Code39.Add("+", "1001010010010");
74 _Code39.Add("-", "1001010110110");
75 _Code39.Add("*", "1001011011010");
76 _Code39.Add("/", "1001001010010");
77 _Code39.Add("%", "1010010010010");
78 _Code39.Add("&", "1001001001010");
79 _Code39.Add(".", "1100101011010");
80 _Code39.Add(" ", "1001101011010");
81 }
82
83 public enum Code39Model
84 {
85 /// <summary>
86 /// 基本类别 1234567890ABC
87 /// </summary>
88 Code39Normal,
89 /// <summary>
90 /// 全ASCII方式 +A+B 来表示小写
91 /// </summary>
92 Code39FullAscII
93 }
94
95 /// <summary>
96 /// 获得条码图形
97 /// </summary>
98 /// <param name="text">文字信息</param>
99 /// <param name="model">类别</param>
100 /// <param name="stat">是否增加前后*号</param>
101 /// <returns>图形</returns>
102 public Bitmap GetCodeImage(Code39Model model, bool star)
103 {
104 string textVal = "";
105 string textCode = "";
106 char[] charVal = null;
107 switch (model)
108 {
109 case Code39Model.Code39Normal:
110 textVal = Text.ToUpper();
111 break;
112 default:
113 charVal = Text.ToCharArray();
114 for (int i = 0; i != charVal.Length; i++)
115 {
116 if ((int)charVal[i] >= 97 && (int)charVal[i] <= 122)
117 {
118 textVal += "+" + charVal[i].ToString().ToUpper();
119
120 }
121 else
122 {
123 textVal += charVal[i].ToString();
124 }
125 }
126 break;
127 }
128 charVal = textVal.ToCharArray();
129 if (star == true) textCode += _Code39["*"];
130 for (int i = 0; i != charVal.Length; i++)
131 {
132 if (star == true && charVal[i] == '*') throw new Exception("带有起始符号不能出现*");
133 object _CharCode = _Code39[charVal[i].ToString()];
134 if (_CharCode == null) throw new Exception("不可用的字符" + charVal[i].ToString());
135 textCode += _CharCode.ToString();
136 }
137 if (star == true) textCode += _Code39["*"];
138 Bitmap bmp = GetImage(textCode);
139 GetViewImage(bmp, Text);
140 return bmp;
141 }
142
143 /// <summary>
144 /// 绘制编码图形
145 /// </summary>
146 /// <param name="text">编码</param>
147 /// <returns>图形</returns>
148 private Bitmap GetImage(string text)
149 {
150 char[] val = text.ToCharArray();
151
152 //宽 == 需要绘制的数量*放大倍数 + 两个字的宽
153 Bitmap codeImg = new Bitmap(val.Length * ((int)Magnify + 1), (int)Height);
154 Graphics graph = Graphics.FromImage(codeImg);
155
156 graph.FillRectangle(Brushes.White, new Rectangle(0, 0, codeImg.Width, codeImg.Height));
157
158 int len = 0;
159 for (int i = 0; i != val.Length; i++)
160 {
161 int width = Magnify + 1;
162 if (val[i] == '1')
163 {
164 graph.FillRectangle(Brushes.Black, new Rectangle(len, 0, width, Height));
165
166 }
167 else
168 {
169 graph.FillRectangle(Brushes.White, new Rectangle(len, 0, width, Height));
170 }
171 len += width;
172 }
173
174 graph.Dispose();
175 return codeImg;
176 }
177
178 /// <summary>
179 /// 绘制文字
180 /// </summary>
181 /// <param name="codeImage">图形</param>
182 /// <param name="text">文字</param>
183 private void GetViewImage(Bitmap codeImage, string text)
184 {
185 if (ViewFont == null) return;
186 Graphics graphic = Graphics.FromImage(codeImage);
187 SizeF fontSize = graphic.MeasureString(text, ViewFont);
188
189 if (fontSize.Width > codeImage.Width || fontSize.Height > codeImage.Height - 20)
190 {
191 graphic.Dispose();
192 return;
193 }
194 int starHeight = codeImage.Height - (int)fontSize.Height;
195 graphic.FillRectangle(Brushes.White, new Rectangle(0, starHeight, codeImage.Width, (int)fontSize.Height));
196
197 int _StarWidth = (codeImage.Width - (int)fontSize.Width) / 2;
198 graphic.DrawString(text, ViewFont, Brushes.Black, _StarWidth, starHeight);
199 graphic.Dispose();
200
201 }
202 }
203
204 public class BarCode128
205 {
206 // ASCII从32到127对应的条码区,由3个条、3个空、共11个单元构成,符号内含校验码
207 private string[] Code128Encoding = new string[] {
208 "11011001100", "11001101100", "11001100110", "10010011000", "10010001100", "10001001100", "10011001000", "10011000100", "10001100100", "11001001000",
209 "11001000100", "11000100100", "10110011100", "10011011100", "10011001110", "10111001100", "10011101100", "10011100110", "11001110010", "11001011100",
210 "11001001110", "11011100100", "11001110100", "11101101110", "11101001100", "11100101100", "11100100110", "11101100100", "11100110100", "11100110010",
211 "11011011000", "11011000110", "11000110110", "10100011000", "10001011000", "10001000110", "10110001000", "10001101000", "10001100010", "11010001000",
212 "11000101000", "11000100010", "10110111000", "10110001110", "10001101110", "10111011000", "10111000110", "10001110110", "11101110110", "11010001110",
213 "11000101110", "11011101000", "11011100010", "11011101110", "11101011000", "11101000110", "11100010110", "11101101000", "11101100010", "11100011010",
214 "11101111010", "11001000010", "11110001010", "10100110000", "10100001100", "10010110000", "10010000110", "10000101100", "10000100110", "10110010000",
215 "10110000100", "10011010000", "10011000010", "10000110100", "10000110010", "11000010010", "11001010000", "11110111010", "11000010100", "10001111010",
216 "10100111100", "10010111100", "10010011110", "10111100100", "10011110100", "10011110010", "11110100100", "11110010100", "11110010010", "11011011110",
217 "11011110110", "11110110110", "10101111000", "10100011110", "10001011110", "10111101000", "10111100010", "11110101000", "11110100010", "10111011110",
218 "10111101110", "11101011110", "11110101110", "11010000100", "11010010000", "11010011100"
219 };
220 private const string Code128Stop = "11000111010", Code128End = "11"; //固定码尾
221 private enum Code128ChangeModes { CodeA = 101, CodeB = 100, CodeC = 99 }; //变更
222 private enum Code128StartModes { CodeUnset = 0, CodeA = 103, CodeB = 104, CodeC = 105 };//各类编码的码头
223
224 /// <summary>
225 /// 绘制Code128码(以像素为单位)
226 /// </summary>
227 public int EncodeBarcode(string code, System.Drawing.Graphics g, int x, int y, int width, int height, bool showText)
228 {
229 if (string.IsNullOrEmpty(code)) new Exception("条码不能为空");
230 List<int> encoded = CodetoEncoded(code); //1.拆分转义
231 encoded.Add(CheckDigitCode128(encoded)); //2.加入校验码
232 string encodestring = EncodeString(encoded); //3.编码
233
234 if (showText) //计算文本的大小,字体占图像的1/4高
235 {
236 Font font = new System.Drawing.Font("宋体", height / 4F, System.Drawing.FontStyle.Regular, GraphicsUnit.Pixel, ((byte)(0)));
237 SizeF size = g.MeasureString(code, font);
238 height = height - (int)size.Height;
239
240 int _StarWidth = (width - (int)size.Width) / 2;
241 g.DrawString(code, font, System.Drawing.Brushes.Black, _StarWidth, height);
242 int w = DrawBarCode(g, encodestring, x, y, width, height); //4.绘制
243 return ((int)size.Width > w ? (int)size.Width : w);
244 }
245 else
246 return DrawBarCode(g, encodestring, x, y, width, height); //4.绘制
247 }
248
249 //1.检测并将字符串拆分并加入码头
250 private List<int> CodetoEncoded(string code)
251 {
252 List<int> encoded = new List<int>();
253 int type = 0;//2:B类,3:C类
254 for (int i = 0; code.Length > 0; i++)
255 {
256 int k = isNumber(code);
257 if (k >= 4) //连续偶个数字可优先使用C类(其实并不定要转C类,但能用C类时条码会更短)
258 {
259 if (type == 0) encoded.Add((int)Code128StartModes.CodeC); //加入码头
260 else if (type != 3) encoded.Add((int)(Code128ChangeModes.CodeC)); //转义
261 type = 3;
262 for (int j = 0; j < k; j = j + 2) //两位数字合为一个码身
263 {
264 encoded.Add(Int32.Parse(code.Substring(0, 2)));
265 code = code.Substring(2);
266 }
267 }
268 else
269 {
270 if ((int)code[0] < 32 || (int)code[0] > 126) throw new Exception("字符串必须是数字或字母");
271 if (type == 0) encoded.Add((int)Code128StartModes.CodeB); //加入码头
272 else if (type != 2) encoded.Add((int)(Code128ChangeModes.CodeB)); //转义
273 type = 2;
274 encoded.Add((int)code[0] - 32);//字符串转为ASCII-32
275 code = code.Substring(1);
276 }
277 }
278 return encoded;
279 }
280 //2.校验码
281 private int CheckDigitCode128(List<int> encoded)
282 {
283 int check = encoded[0];
284 for (int i = 1; i < encoded.Count; i++)
285 check = check + (encoded[i] * i);
286 return (check % 103);
287 }
288
289 //2.编码(对应Code128Encoding数组)
290 private string EncodeString(List<int> encoded)
291 {
292 string encodedString = "";
293 for (int i = 0; i < encoded.Count; i++)
294 {
295 encodedString += Code128Encoding[encoded[i]];
296 }
297 encodedString += Code128Stop + Code128End; // 加入结束码
298 return encodedString;
299 }
300
301 //4.绘制条码(返回实际图像宽度)
302 private int DrawBarCode(System.Drawing.Graphics g, string encodeString, int x, int y, int width, int height)
303 {
304 int w = width / encodeString.Length;
305 for (int i = 0; i < encodeString.Length; i++)
306 {
307 g.FillRectangle(encodeString[i] == '0' ? System.Drawing.Brushes.White : System.Drawing.Brushes.Black, x, y, w, height);
308 x += w;
309 }
310 return w * (encodeString.Length + 2);
311 }
312 //检测是否连续偶个数字,返回连续数字的长度
313 private int isNumber(string code)
314 {
315 int k = 0;
316 for (int i = 0; i < code.Length; i++)
317 {
318 if (char.IsNumber(code[i]))
319 k++;
320 else
321 break;
322 }
323 if (k % 2 != 0) k--;
324 return k;
325 }
326
327 /// <summary>
328 /// 绘制Code128码到图片
329 /// </summary>
330 public Image EncodeBarcode(string code, int width, int height, bool showText)
331 {
332 Bitmap image = new Bitmap(width, height);
333 using (Graphics g = Graphics.FromImage(image))
334 {
335 g.Clear(Color.White);
336 int w = EncodeBarcode(code, g, 0, 0, width, height, showText);
337
338 Bitmap image2 = new Bitmap(w, height); //剪切多余的空白;
339 using (Graphics g2 = Graphics.FromImage(image2))
340 {
341 g2.DrawImage(image, 0, 0);
342 return image2;
343 }
344
345 }
346
347 }
348
349 /// <summary>
350 /// 绘制Code128码到流
351 /// </summary>
352 public byte[] EncodeBarcodeByte(string code, int width, int height, bool showText)
353 {
354 Image image = EncodeBarcode(code, width, height, showText);
355 System.IO.MemoryStream ms = new System.IO.MemoryStream();
356 image.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
357 byte[] byteImage = ms.ToArray();
358 ms.Close();
359 image.Dispose();
360 return byteImage;
361
362 }
363 }
364 }