基于C#的BarCode 39实现

一、39条码简介

      39码是1974年发展出来的条码系统,是一种可供使用者双向扫瞄的分散式条码,也就是说相临两资料码之间,必须包含一个不具任何意义的空白(或细白,其逻辑值为0),且其具有支援文字的能力,故较一般一维条码应用广泛,由于CODE 39支持0~9、A~Z等,目前较主要用于,通常运用于资产管理、会员卡、店内码管理、产品卷标等。

  标准的39码是由起始安全空间、起始码、资料码、可忽略不计的检查码、终止安全空间及终止码所构成。

二、39码编码

  39码的每一个字元编码方式,都是由九条不同排列的线条编码而得。可区分成如表之四种类型:

                                             

                                     表1 39码的字元编码方式

  (1)英文字母部分

       26个英文字母所对应的39码逻辑值如表所示。

       

字元

逻辑型态

字元

逻辑型态

A

110101001011

N

101011010011

B

101101001011

O

110101101001

C

110110100101

P

101101101001

D

101011001011

Q

101010110011

E

110101100101

R

110101011001

F

101101100101

S

101101011001

G

101010011011

T

101011011001

H

110101001101

U

110010101011

I

101101001101

V

100110101011

J

101011001101

W

110011010101

K

110101010011

X

100101101011

L

101101010011

Y

110010110101

M

110110101001

Z

100110110101

    (2)数字与特殊符号部分

         39码也可表示数字0~9以及特殊符号,其对应的逻辑值如表所示。

                                                         

字元

逻辑型态

字元

逻辑型态

0

101001101101

100101001001

1

110100101011

100101011011

2

101100101011

100101101101

3

110110010101

100100101001

4

101001101011

101001001001

5

110100110101

100100100101

6

101100110101

110010101101

7

101001011011

空白

100110101101

8

110100101101

 

 

9

101100101101

 

     (3)39码的检查码查询表

                                   

三、39码编码算法

  (1)移除输入待编码内容Value to Code中的*,得到Value;

      (2)将Value逐位按“二”中的的检查码查询表计算检查码的和sum,计算检查码 checkcode=sum%43,再以checkcode在检查码中查询对应的编码字元checkChar

  (3)将Value与checkChar拼接后,前后加上'*'再逐位按“二”中的对应的编码+‘0’进行编码,将最后一个0去掉后得到Code;

      (4)按表1对Code进行绘图。

四、基于C#的算法实现

(1)UI设计

  

(2)算法代码

  1 using System;
  2 using System.Collections;
  3 using System.Collections.Generic;
  4 using System.Linq;
  5 using System.Text;
  6 using System.Threading.Tasks;
  7 using System.Drawing;
  8 using System.Drawing.Drawing2D;
  9 
 10 namespace BarCode
 11 {
 12     /// <summary>
 13     /// 39 barcode
 14     /// </summary>
 15     public class BarCode
 16     {
 17         private string _rawData;
 18         private bool _enableChecksum;
 19         private int _height;
 20         private int _width;
 21         private bool _includeLabel;
 22         private string _code;
 23         private enum LabelPositions : int { TOPLEFT, TOPCENTER, TOPRIGHT, BOTTOMLEFT, BOTTOMCENTER, BOTTOMRIGHT };
 24 
 25         private LabelPositions _labelPosition;
 26         private Color _ForeColor = Color.Black;
 27         private Color _BackColor = Color.White;
 28         private string Code
 29         {
 30             get
 31             {
 32                 if (string.IsNullOrEmpty(this._code))
 33                 {
 34                     this._code = Encode(); 
 35                 }
 36                 return this._code;
 37             }
 38         }
 39         private Image _encodedImage;
 40         public Image EncodedImage
 41         {
 42             get{return _encodedImage;}
 43             set{this._encodedImage=value;}
 44         }
 45         private Hashtable C39_Code = new Hashtable(); //is initialized by init_Code39()
 46         private Hashtable ExtC39_Translation = new Hashtable();
 47         /// <summary>
 48         /// Encodes with Code39.
 49         /// </summary>
 50         /// <param name="input">Data to encode.</param>
 51         /// <param name="AllowExtended">Allow Extended Code 39 (Full Ascii mode).</param>
 52         /// <param name="EnableChecksum">Whether to calculate the Mod 43 checksum and encode it into the barcode</param>
 53         public BarCode(string input, bool enableChecksum, int height, int width,bool includeLabel)
 54         {
 55             _rawData = input;
 56             _enableChecksum = enableChecksum;
 57             _height = height;
 58             _width = width;
 59             _includeLabel=includeLabel;
 60             _labelPosition=LabelPositions.BOTTOMCENTER;
 61         }
 62 
 63         /// <summary>
 64         /// Encode the raw data using the Code 39 algorithm.
 65         /// </summary>
 66         private string Encode()
 67         {
 68             this.init_Code39();
 69             this.init_ExtendedCode39();
 70 
 71             string strNoAstr = this._rawData.Replace("*", "");
 72             string strFormattedData = "*" + strNoAstr + (this._enableChecksum ? getChecksumChar(strNoAstr).ToString() : String.Empty) + "*";
 73 
 74             string result = "";
 75             //foreach (char c in this.FormattedData)
 76             foreach (char c in strFormattedData)
 77             {
 78                 try
 79                 {
 80                     result += C39_Code[c].ToString();
 81                     result += "0";//whitespace
 82                 }//try
 83                 catch
 84                 {
 85                     throw new Exception("EC39-1: Invalid data. (Try using Extended Code39)");
 86                 }//catch
 87             }//foreach
 88 
 89             result = result.Substring(0, result.Length-1);
 90             
 91             //clear the hashtable so it no longer takes up memory
 92             this.C39_Code.Clear();
 93 
 94             return result;
 95         }//Encode_Code39
 96         private void init_Code39()
 97         {
 98             C39_Code.Clear();
 99             C39_Code.Add('0', "101001101101");
100             C39_Code.Add('1', "110100101011");
101             C39_Code.Add('2', "101100101011");
102             C39_Code.Add('3', "110110010101");
103             C39_Code.Add('4', "101001101011");
104             C39_Code.Add('5', "110100110101");
105             C39_Code.Add('6', "101100110101");
106             C39_Code.Add('7', "101001011011");
107             C39_Code.Add('8', "110100101101");
108             C39_Code.Add('9', "101100101101");
109             C39_Code.Add('A', "110101001011");
110             C39_Code.Add('B', "101101001011");
111             C39_Code.Add('C', "110110100101");
112             C39_Code.Add('D', "101011001011");
113             C39_Code.Add('E', "110101100101");
114             C39_Code.Add('F', "101101100101");
115             C39_Code.Add('G', "101010011011");
116             C39_Code.Add('H', "110101001101");
117             C39_Code.Add('I', "101101001101");
118             C39_Code.Add('J', "101011001101");
119             C39_Code.Add('K', "110101010011");
120             C39_Code.Add('L', "101101010011");
121             C39_Code.Add('M', "110110101001");
122             C39_Code.Add('N', "101011010011");
123             C39_Code.Add('O', "110101101001");
124             C39_Code.Add('P', "101101101001");
125             C39_Code.Add('Q', "101010110011");
126             C39_Code.Add('R', "110101011001");
127             C39_Code.Add('S', "101101011001");
128             C39_Code.Add('T', "101011011001");
129             C39_Code.Add('U', "110010101011");
130             C39_Code.Add('V', "100110101011");
131             C39_Code.Add('W', "110011010101");
132             C39_Code.Add('X', "100101101011");
133             C39_Code.Add('Y', "110010110101");
134             C39_Code.Add('Z', "100110110101");
135             C39_Code.Add('-', "100101011011");
136             C39_Code.Add('.', "110010101101");
137             C39_Code.Add(' ', "100110101101");
138             C39_Code.Add('$', "100100100101");
139             C39_Code.Add('/', "100100101001");
140             C39_Code.Add('+', "100101001001");
141             C39_Code.Add('%', "101001001001");
142             C39_Code.Add('*', "100101101101");
143         }//init_Code39
144         private void init_ExtendedCode39()
145         {
146             ExtC39_Translation.Clear();
147             ExtC39_Translation.Add(Convert.ToChar(0).ToString(), "%U");
148             ExtC39_Translation.Add(Convert.ToChar(1).ToString(), "$A");
149             ExtC39_Translation.Add(Convert.ToChar(2).ToString(), "$B");
150             ExtC39_Translation.Add(Convert.ToChar(3).ToString(), "$C");
151             ExtC39_Translation.Add(Convert.ToChar(4).ToString(), "$D");
152             ExtC39_Translation.Add(Convert.ToChar(5).ToString(), "$E");
153             ExtC39_Translation.Add(Convert.ToChar(6).ToString(), "$F");
154             ExtC39_Translation.Add(Convert.ToChar(7).ToString(), "$G");
155             ExtC39_Translation.Add(Convert.ToChar(8).ToString(), "$H");
156             ExtC39_Translation.Add(Convert.ToChar(9).ToString(), "$I");
157             ExtC39_Translation.Add(Convert.ToChar(10).ToString(), "$J");
158             ExtC39_Translation.Add(Convert.ToChar(11).ToString(), "$K");
159             ExtC39_Translation.Add(Convert.ToChar(12).ToString(), "$L");
160             ExtC39_Translation.Add(Convert.ToChar(13).ToString(), "$M");
161             ExtC39_Translation.Add(Convert.ToChar(14).ToString(), "$N");
162             ExtC39_Translation.Add(Convert.ToChar(15).ToString(), "$O");
163             ExtC39_Translation.Add(Convert.ToChar(16).ToString(), "$P");
164             ExtC39_Translation.Add(Convert.ToChar(17).ToString(), "$Q");
165             ExtC39_Translation.Add(Convert.ToChar(18).ToString(), "$R");
166             ExtC39_Translation.Add(Convert.ToChar(19).ToString(), "$S");
167             ExtC39_Translation.Add(Convert.ToChar(20).ToString(), "$T");
168             ExtC39_Translation.Add(Convert.ToChar(21).ToString(), "$U");
169             ExtC39_Translation.Add(Convert.ToChar(22).ToString(), "$V");
170             ExtC39_Translation.Add(Convert.ToChar(23).ToString(), "$W");
171             ExtC39_Translation.Add(Convert.ToChar(24).ToString(), "$X");
172             ExtC39_Translation.Add(Convert.ToChar(25).ToString(), "$Y");
173             ExtC39_Translation.Add(Convert.ToChar(26).ToString(), "$Z");
174             ExtC39_Translation.Add(Convert.ToChar(27).ToString(), "%A");
175             ExtC39_Translation.Add(Convert.ToChar(28).ToString(), "%B");
176             ExtC39_Translation.Add(Convert.ToChar(29).ToString(), "%C");
177             ExtC39_Translation.Add(Convert.ToChar(30).ToString(), "%D");
178             ExtC39_Translation.Add(Convert.ToChar(31).ToString(), "%E");
179             ExtC39_Translation.Add("!", "/A");
180             ExtC39_Translation.Add(""", "/B");
181             ExtC39_Translation.Add("#", "/C");
182             ExtC39_Translation.Add("$", "/D");
183             ExtC39_Translation.Add("%", "/E");
184             ExtC39_Translation.Add("&", "/F");
185             ExtC39_Translation.Add("'", "/G");
186             ExtC39_Translation.Add("(", "/H");
187             ExtC39_Translation.Add(")", "/I");
188             ExtC39_Translation.Add("*", "/J");
189             ExtC39_Translation.Add("+", "/K");
190             ExtC39_Translation.Add(",", "/L");
191             ExtC39_Translation.Add("/", "/O");
192             ExtC39_Translation.Add(":", "/Z");
193             ExtC39_Translation.Add(";", "%F");
194             ExtC39_Translation.Add("<", "%G");
195             ExtC39_Translation.Add("=", "%H");
196             ExtC39_Translation.Add(">", "%I");
197             ExtC39_Translation.Add("?", "%J");
198             ExtC39_Translation.Add("[", "%K");
199             ExtC39_Translation.Add("\", "%L");
200             ExtC39_Translation.Add("]", "%M");
201             ExtC39_Translation.Add("^", "%N");
202             ExtC39_Translation.Add("_", "%O");
203             ExtC39_Translation.Add("{", "%P");
204             ExtC39_Translation.Add("|", "%Q");
205             ExtC39_Translation.Add("}", "%R");
206             ExtC39_Translation.Add("~", "%S");
207             ExtC39_Translation.Add("`", "%W");
208             ExtC39_Translation.Add("@", "%V");
209             ExtC39_Translation.Add("a", "+A");
210             ExtC39_Translation.Add("b", "+B");
211             ExtC39_Translation.Add("c", "+C");
212             ExtC39_Translation.Add("d", "+D");
213             ExtC39_Translation.Add("e", "+E");
214             ExtC39_Translation.Add("f", "+F");
215             ExtC39_Translation.Add("g", "+G");
216             ExtC39_Translation.Add("h", "+H");
217             ExtC39_Translation.Add("i", "+I");
218             ExtC39_Translation.Add("j", "+J");
219             ExtC39_Translation.Add("k", "+K");
220             ExtC39_Translation.Add("l", "+L");
221             ExtC39_Translation.Add("m", "+M");
222             ExtC39_Translation.Add("n", "+N");
223             ExtC39_Translation.Add("o", "+O");
224             ExtC39_Translation.Add("p", "+P");
225             ExtC39_Translation.Add("q", "+Q");
226             ExtC39_Translation.Add("r", "+R");
227             ExtC39_Translation.Add("s", "+S");
228             ExtC39_Translation.Add("t", "+T");
229             ExtC39_Translation.Add("u", "+U");
230             ExtC39_Translation.Add("v", "+V");
231             ExtC39_Translation.Add("w", "+W");
232             ExtC39_Translation.Add("x", "+X");
233             ExtC39_Translation.Add("y", "+Y");
234             ExtC39_Translation.Add("z", "+Z");
235             ExtC39_Translation.Add(Convert.ToChar(127).ToString(), "%T"); //also %X, %Y, %Z 
236         }
237         private void InsertExtendedCharsIfNeeded(ref string FormattedData)
238         {
239             string output = "";
240             foreach (char c in FormattedData)
241             {
242                 try
243                 {
244                     string s = C39_Code[c].ToString();
245                     output += c;
246                 }//try
247                 catch 
248                 { 
249                     //insert extended substitution
250                     object oTrans = ExtC39_Translation[c.ToString()];
251                     output += oTrans.ToString();
252                 }//catch
253             }//foreach
254 
255             FormattedData = output;
256         }
257         private char getChecksumChar(string strNoAstr) 
258         {
259             //checksum
260             string Code39_Charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%";
261             InsertExtendedCharsIfNeeded(ref strNoAstr);
262             int sum = 0;
263 
264             //Calculate the checksum
265             for (int i = 0; i < strNoAstr.Length; ++i)
266             {
267                 sum = sum + Code39_Charset.IndexOf(strNoAstr[i].ToString());
268             }
269 
270             //return the checksum char
271             return Code39_Charset[sum % 43];
272         }
273 
274         /// <summary>
275         /// Gets a bitmap representation of the encoded data.
276         /// </summary>
277         /// <returns>Bitmap of encoded value.</returns>
278         public Bitmap GenerateCodeImage(ref string codeValue)
279         {
280             if (Code == "") throw new Exception("EGENERATE_IMAGE-1: Encode Error.");
281             Bitmap b = null;
282 
283             DateTime dtStartTime = DateTime.Now;
284 
285 
286             b = new Bitmap(this._width, this._height);
287             int iBarWidth = this._width / Code.Length;
288             int shiftAdjustment = (this._width % Code.Length) / 2;
289             int iBarWidthModifier = 1;
290 
291             if (iBarWidth <= 0)
292             {
293                 throw new Exception("EGENERATE_IMAGE-2: Image size specified not large enough to draw image. (Bar size determined to be less than 1 pixel)");
294             }
295 
296             //draw image
297             int pos = 0;
298             int halfBarWidth = (int)(iBarWidth * 0.5);
299 
300             using (Graphics g = Graphics.FromImage(b))
301             {
302                 //clears the image and colors the entire background
303                 g.Clear(this._BackColor);
304 
305                 //lines are fBarWidth wide so draw the appropriate color line vertically
306                 using (Pen backpen = new Pen(_BackColor, iBarWidth / iBarWidthModifier))
307                 {
308                     using (Pen pen = new Pen(_ForeColor, iBarWidth / iBarWidthModifier))
309                     {
310                         while (pos < Code.Length)
311                         {
312                             if (Code[pos] == '1')
313                             {
314                                 g.DrawLine(pen, new Point(pos * iBarWidth + shiftAdjustment + halfBarWidth, 0), new Point(pos * iBarWidth + shiftAdjustment + halfBarWidth, this._height));
315                             }
316                             pos++;
317                         }//while
318                     }//using
319                 }//using
320 
321                 if (this._includeLabel)
322                 {
323                     GenerateCodeLabel((Image)b);
324                 }//if
325 
326                 EncodedImage = (Image)b;
327                 codeValue=Code;
328                 return b;
329             }
330         }
331      
332         /// <summary>
333         /// Saves an encoded image to a specified file and type.
334         /// </summary>
335         /// <param name="Filename">Filename to save to.</param>
336         /// <param name="FileType">Format to use.</param>
337         public void SaveImage(string Filename)
338         {
339             try
340             {
341                 if (this.Code != null)
342                 {
343                     string FileType = Filename.Substring(Filename.LastIndexOf('.') + 1).ToUpper();
344                     System.Drawing.Imaging.ImageFormat imageformat;
345                     switch (FileType)
346                     {
347                         case "BMP": imageformat = System.Drawing.Imaging.ImageFormat.Bmp; break;
348                         case "GIF": imageformat = System.Drawing.Imaging.ImageFormat.Gif; break;
349                         case "JPG": imageformat = System.Drawing.Imaging.ImageFormat.Jpeg; break;
350                         case "PNG": imageformat = System.Drawing.Imaging.ImageFormat.Png; break;
351                         case "TIFF": imageformat = System.Drawing.Imaging.ImageFormat.Tiff; break;
352                         default: imageformat = System.Drawing.Imaging.ImageFormat.Png; break;
353                     }//switch
354                     ((Bitmap)this.EncodedImage).Save(Filename, imageformat);
355                 }//if
356             }//try
357             catch (Exception ex)
358             {
359                 throw new Exception("ESAVEIMAGE-1: Could not save image.

=======================

" + ex.Message);
360             }//catch
361         }//SaveImage(string, SaveTypes)
362       
363         private Image GenerateCodeLabel(Image img)
364         {
365             try
366             {
367                 System.Drawing.Font font =new Font("Microsoft Sans Serif", 10, FontStyle.Bold); 
368 
369                 using (Graphics g = Graphics.FromImage(img))
370                 {
371                     g.DrawImage(img, (float)0, (float)0);
372 
373                     g.SmoothingMode = SmoothingMode.HighQuality;
374                     g.InterpolationMode = InterpolationMode.HighQualityBicubic;
375                     g.PixelOffsetMode = PixelOffsetMode.HighQuality;
376                     g.CompositingQuality = CompositingQuality.HighQuality;
377 
378                     StringFormat f = new StringFormat();
379                     f.Alignment = StringAlignment.Near;
380                     f.LineAlignment = StringAlignment.Near;
381                     int LabelX = 0;
382                     int LabelY = 0;
383 
384                     switch (this._labelPosition)
385                     {
386                         case LabelPositions.BOTTOMCENTER:
387                             LabelX = img.Width / 2;
388                             LabelY = img.Height - (font.Height);
389                             f.Alignment = StringAlignment.Center;
390                             break;
391                         case LabelPositions.BOTTOMLEFT:
392                             LabelX = 0;
393                             LabelY = img.Height - (font.Height);
394                             f.Alignment = StringAlignment.Near;
395                             break;
396                         case LabelPositions.BOTTOMRIGHT:
397                             LabelX = img.Width;
398                             LabelY = img.Height - (font.Height);
399                             f.Alignment = StringAlignment.Far;
400                             break;
401                         case LabelPositions.TOPCENTER:
402                             LabelX = img.Width / 2;
403                             LabelY = 0;
404                             f.Alignment = StringAlignment.Center;
405                             break;
406                         case LabelPositions.TOPLEFT:
407                             LabelX = img.Width;
408                             LabelY = 0;
409                             f.Alignment = StringAlignment.Near;
410                             break;
411                         case LabelPositions.TOPRIGHT:
412                             LabelX = img.Width;
413                             LabelY = 0;
414                             f.Alignment = StringAlignment.Far;
415                             break;
416                     }//switch
417 
418                     //color a background color box at the bottom of the barcode to hold the string of data
419                     g.FillRectangle(new SolidBrush(this._BackColor), new RectangleF((float)0, (float)LabelY, (float)img.Width, (float)font.Height));
420 
421                     //draw datastring under the barcode image
422                     g.DrawString(this._rawData, font, new SolidBrush(this._ForeColor), new RectangleF((float)0, (float)LabelY, (float)img.Width, (float)font.Height), f);
423 
424                     g.Save();
425                 }//using
426                 return img;
427             }//try
428             catch (Exception ex)
429             {
430                 throw new Exception("ELABEL_GENERIC-1: " + ex.Message);
431             }//catch
432         }//Label_Generic
433 
434     }
435 }
View Code
 1  private void btnEncode_Click(object sender, EventArgs e)
 2         {
 3             string input = this.txtInput.Text.Trim();
 4             string txtwidth = this.txtWidth.Text.Trim();
 5             string txtheight = this.txtHeight.Text.Trim();
 6             if (!string.IsNullOrEmpty(input) && !string.IsNullOrEmpty(txtwidth) && !string.IsNullOrEmpty(txtheight))
 7             {
 8                 this._width = Int32.Parse(txtwidth);
 9                 this._height = Int32.Parse(txtheight);
10                 barCode = new BarCode(input, true, this._height, this._width, true);
11                 string codeValue = string.Empty;
12                 pb.Image = barCode.GenerateCodeImage(ref codeValue);
13                 //reposition the barcode image to the middle
14                 pb.Location = new Point((this.pb.Location.X + this.pb.Width / 2) - this.pb.Width / 2, (this.pb.Location.Y + this.pb.Height / 2) - pb.Height / 2);
15 
16                 //txtEncoded.Text = codeValue;        
17             }
18             else
19             {
20                 MessageBox.Show("请输入完整信息");
21             }               
22         }
23         /// <summary>
24         /// 打印生成的条形码
25         /// </summary>
26         /// <param name="sender"></param>
27         /// <param name="e"></param>
28         private void btnPrint_Click(object sender, EventArgs e)
29         {
30             PrintDialog printDialog = new PrintDialog();
31             printDialog.Document = printDocument;
32             if (printDialog.ShowDialog(this) == DialogResult.OK) //到这里会出现选择打印项的窗口  
33             {
34                 printDocument.Print(); //到这里会出现给文件命名的窗口,点击确定后进行打印并完成打印  
35             }  
36         }
37         /// <summary>
38         /// 使用PrintDocument,并且设置相应的事件监听
39         /// </summary>
40         /// <param name="sender"></param>
41         /// <param name="e"></param>
42         private void printDocument_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
43         {
44             try
45             {
46                 if (pb.Image != null)
47                 {
48                     Rectangle rect = new Rectangle(50, 50, this._width, this._height);//设置打印起始位置和大小
49                     e.Graphics.DrawImage(pb.Image,rect);//确定要打印的图片及其打印起始位置和大小
50                     e.HasMorePages = false;
51                 }
52             }
53             catch (Exception ex)
54             {
55                 MessageBox.Show("请先生成条形码!");
56             }
57         }
58 
59         private void btnSaveAsImg_Click(object sender, EventArgs e)
60         {
61             SaveFileDialog saveFdlg = new SaveFileDialog();
62             saveFdlg.Filter = "*.png|*.jpg";
63             if (saveFdlg.ShowDialog() == DialogResult.OK)
64             {
65                 string fileName = saveFdlg.FileName;
66                 barCode.SaveImage(fileName);
67             }
68         }
View Code

 (3)效果图

原文地址:https://www.cnblogs.com/cloudml/p/4501946.html