C#
  1  using System;
  2  using System.Text;
  3  
  4  namespace GenCode128
  5  {
  6     public enum CodeSet
  7     {
  8        CodeA
  9        ,CodeB
 10        // ,CodeC   // not supported
 11     }
 12  
 13  	/// <summary>
 14  	/// Represent the set of code values to be output into barcode form
 15  	/// </summary>
 16  	public class Code128Content
 17  	{
 18        private int[] mCodeList;
 19  
 20        /// <summary>
 21        /// Create content based on a string of ASCII data
 22        /// </summary>
 23        /// <param name="AsciiData">the string that should be represented</param>
 24  		public Code128Content( string AsciiData )
 25  		{
 26           mCodeList = StringToCode128(AsciiData);
 27  		}
 28  
 29        /// <summary>
 30        /// Provides the Code128 code values representing the object's string
 31        /// </summary>
 32        public int[] Codes
 33        {
 34           get
 35           {
 36              return mCodeList;
 37           }
 38        }
 39  
 40        /// <summary>
 41        /// Transform the string into integers representing the Code128 codes
 42        /// necessary to represent it
 43        /// </summary>
 44        /// <param name="AsciiData">String to be encoded</param>
 45        /// <returns>Code128 representation</returns>
 46        private int[] StringToCode128( string AsciiData )
 47        {
 48           // turn the string into ascii byte data
 49           byte[] asciiBytes = Encoding.ASCII.GetBytes( AsciiData );
 50  
 51           // decide which codeset to start with
 52           Code128Code.CodeSetAllowed csa1 = asciiBytes.Length>0 ? Code128Code.CodesetAllowedForChar( asciiBytes[0] ) : Code128Code.CodeSetAllowed.CodeAorB;
 53           Code128Code.CodeSetAllowed csa2 = asciiBytes.Length>0 ? Code128Code.CodesetAllowedForChar( asciiBytes[1] ) : Code128Code.CodeSetAllowed.CodeAorB;
 54           CodeSet currcs = GetBestStartSet(csa1,csa2);
 55  
 56           // set up the beginning of the barcode
 57           System.Collections.ArrayList codes = new System.Collections.ArrayList(asciiBytes.Length + 3); // assume no codeset changes, account for start, checksum, and stop
 58           codes.Add(Code128Code.StartCodeForCodeSet(currcs));
 59  
 60           // add the codes for each character in the string
 61           for (int i = 0; i < asciiBytes.Length; i++)
 62           {
 63              int thischar = asciiBytes[i];
 64              int nextchar = asciiBytes.Length>(i+1) ? asciiBytes[i+1] : -1;
 65  
 66              codes.AddRange( Code128Code.CodesForChar(thischar, nextchar, ref currcs) );
 67           }
 68  
 69           // calculate the check digit
 70           int checksum = (int)(codes[0]);
 71           for (int i = 1; i < codes.Count; i++)
 72           {
 73              checksum += i * (int)(codes[i]);
 74           }
 75           codes.Add( checksum % 103 );
 76  
 77           codes.Add( Code128Code.StopCode() );
 78  
 79           int[] result = codes.ToArray(typeof(int)) as int[];
 80           return result;
 81        }
 82  
 83        /// <summary>
 84        /// Determines the best starting code set based on the the first two 
 85        /// characters of the string to be encoded
 86        /// </summary>
 87        /// <param name="csa1">First character of input string</param>
 88        /// <param name="csa2">Second character of input string</param>
 89        /// <returns>The codeset determined to be best to start with</returns>
 90        private CodeSet GetBestStartSet( Code128Code.CodeSetAllowed csa1, Code128Code.CodeSetAllowed csa2 )
 91        {
 92           int vote = 0;
 93  
 94           vote += (csa1==Code128Code.CodeSetAllowed.CodeA) ?  1 : 0;
 95           vote += (csa1==Code128Code.CodeSetAllowed.CodeB) ? -1 : 0;
 96           vote += (csa2==Code128Code.CodeSetAllowed.CodeA) ?  1 : 0;
 97           vote += (csa2==Code128Code.CodeSetAllowed.CodeB) ? -1 : 0;
 98  
 99           return (vote>0) ? CodeSet.CodeA : CodeSet.CodeB;   // ties go to codeB due to my own prejudices
100        }
101  	}
102  
103     /// <summary>
104     /// Static tools for determining codes for individual characters in the content
105     /// </summary>
106     public static class Code128Code
107     {
108        #region Constants
109  
110        private const int cSHIFT = 98;
111        private const int cCODEA = 101;
112        private const int cCODEB = 100;
113  
114        private const int cSTARTA = 103;
115        private const int cSTARTB = 104;
116        private const int cSTOP   = 106;
117  
118        #endregion
119  
120        /// <summary>
121        /// Get the Code128 code value(s) to represent an ASCII character, with 
122        /// optional look-ahead for length optimization
123        /// </summary>
124        /// <param name="CharAscii">The ASCII value of the character to translate</param>
125        /// <param name="LookAheadAscii">The next character in sequence (or -1 if none)</param>
126        /// <param name="CurrCodeSet">The current codeset, that the returned codes need to follow;
127        /// if the returned codes change that, then this value will be changed to reflect it</param>
128        /// <returns>An array of integers representing the codes that need to be output to produce the 
129        /// given character</returns>
130        public static int[] CodesForChar(int CharAscii, int LookAheadAscii, ref CodeSet CurrCodeSet)
131        {
132           int[] result;
133           int shifter = -1;
134  
135           if (!CharCompatibleWithCodeset(CharAscii,CurrCodeSet))
136           {
137              // if we have a lookahead character AND if the next character is ALSO not compatible
138              if ( (LookAheadAscii != -1)  && !CharCompatibleWithCodeset(LookAheadAscii,CurrCodeSet)  ) 
139              {
140                 // we need to switch code sets
141                 switch (CurrCodeSet)
142                 {
143                    case CodeSet.CodeA:
144                       shifter = cCODEB;
145                       CurrCodeSet = CodeSet.CodeB;
146                       break;
147                    case CodeSet.CodeB:
148                       shifter = cCODEA;
149                       CurrCodeSet = CodeSet.CodeA;
150                       break;
151                 }
152              }
153              else
154              {
155                 // no need to switch code sets, a temporary SHIFT will suffice
156                 shifter = cSHIFT;
157              }
158           }
159  
160           if (shifter!=-1)
161           {
162              result = new int[2];
163              result[0] = shifter;
164              result[1] = CodeValueForChar(CharAscii);
165           }
166           else
167           {
168              result = new int[1];
169              result[0] = CodeValueForChar(CharAscii);
170           }
171  
172           return result;
173        }
174  
175        /// <summary>
176        /// Tells us which codesets a given character value is allowed in
177        /// </summary>
178        /// <param name="CharAscii">ASCII value of character to look at</param>
179        /// <returns>Which codeset(s) can be used to represent this character</returns>
180        public static CodeSetAllowed CodesetAllowedForChar(int CharAscii)
181        {
182           if (CharAscii>=32 && CharAscii<=95)
183           {
184              return CodeSetAllowed.CodeAorB;
185           }
186           else 
187           {
188              return (CharAscii<32) ? CodeSetAllowed.CodeA : CodeSetAllowed.CodeB;
189           }
190        }
191  
192        /// <summary>
193        /// Determine if a character can be represented in a given codeset
194        /// </summary>
195        /// <param name="CharAscii">character to check for</param>
196        /// <param name="currcs">codeset context to test</param>
197        /// <returns>true if the codeset contains a representation for the ASCII character</returns>
198        public static bool CharCompatibleWithCodeset(int CharAscii, CodeSet currcs)
199        {
200           CodeSetAllowed csa = CodesetAllowedForChar(CharAscii);
201           return csa==CodeSetAllowed.CodeAorB 
202                    || (csa==CodeSetAllowed.CodeA && currcs==CodeSet.CodeA)
203                    || (csa==CodeSetAllowed.CodeB && currcs==CodeSet.CodeB);
204        }
205  
206        /// <summary>
207        /// Gets the integer code128 code value for a character (assuming the appropriate code set)
208        /// </summary>
209        /// <param name="CharAscii">character to convert</param>
210        /// <returns>code128 symbol value for the character</returns>
211        public static int CodeValueForChar(int CharAscii)
212        {
213           return (CharAscii>=32) ? CharAscii-32 :  CharAscii+64;
214        }
215  
216        /// <summary>
217        /// Return the appropriate START code depending on the codeset we want to be in
218        /// </summary>
219        /// <param name="cs">The codeset you want to start in</param>
220        /// <returns>The code128 code to start a barcode in that codeset</returns>
221        public static int StartCodeForCodeSet(CodeSet cs)
222        {
223           return cs==CodeSet.CodeA ? cSTARTA : cSTARTB;
224        }
225  
226        /// <summary>
227        /// Return the Code128 stop code
228        /// </summary>
229        /// <returns>the stop code</returns>
230        public static int StopCode()
231        {
232           return cSTOP;
233        }
234  
235        /// <summary>
236        /// Indicates which code sets can represent a character -- CodeA, CodeB, or either
237        /// </summary>
238        public enum CodeSetAllowed
239        {
240           CodeA,
241           CodeB,
242           CodeAorB
243        }
244  
245     }
246  }