BarcodePlessey.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. namespace FastReport.Barcode
  5. {
  6. /// <summary>
  7. /// Generates the Plessey barcode.
  8. /// </summary>
  9. public class BarcodePlessey : LinearBarcodeBase
  10. {
  11. private const String ALPHABET_STRING = "0123456789ABCDEF";
  12. private static readonly int[] startWidths = new int[] { 14, 11, 14, 11, 5, 20, 14, 11 };
  13. private static readonly int[] terminationWidths = new int[] { 25 };
  14. private static readonly int[] endWidths = new int[] { 20, 5, 20, 5, 14, 11, 14, 11 };
  15. private static readonly int[][] numberWidths = new int[][]
  16. {
  17. new int[] { 5, 20, 5, 20, 5, 20, 5, 20 }, // 0
  18. new int[] { 14, 11, 5, 20, 5, 20, 5, 20 }, // 1
  19. new int[] { 5, 20, 14, 11, 5, 20, 5, 20 }, // 2
  20. new int[] { 14, 11, 14, 11, 5, 20, 5, 20 }, // 3
  21. new int[] { 5, 20, 5, 20, 14, 11, 5, 20 }, // 4
  22. new int[] { 14, 11, 5, 20, 14, 11, 5, 20 }, // 5
  23. new int[] { 5, 20, 14, 11, 14, 11, 5, 20 }, // 6
  24. new int[] { 14, 11, 14, 11, 14, 11, 5, 20 }, // 7
  25. new int[] { 5, 20, 5, 20, 5, 20, 14, 11 }, // 8
  26. new int[] { 14, 11, 5, 20, 5, 20, 14, 11 }, // 9
  27. new int[] { 5, 20, 14, 11, 5, 20, 14, 11 }, // A / 10
  28. new int[] { 14, 11, 14, 11, 5, 20, 14, 11 }, // B / 11
  29. new int[] { 5, 20, 5, 20, 14, 11, 14, 11 }, // C / 12
  30. new int[] { 14, 11, 5, 20, 14, 11, 14, 11 }, // D / 13
  31. new int[] { 5, 20, 14, 11, 14, 11, 14, 11 }, // E / 14
  32. new int[] { 14, 11, 14, 11, 14, 11, 14, 11 } // F / 15
  33. };
  34. private static readonly byte[] crcGrid = new byte[] { 1, 1, 1, 1, 0, 1, 0, 0, 1 };
  35. private static readonly int[] crc0Widths = new int[] { 5, 20 };
  36. private static readonly int[] crc1Widths = new int[] { 14, 11 };
  37. private static readonly string start = "606050060";
  38. private static readonly string end = "70050050606";
  39. private static readonly string[] tabelle = new string[] {
  40. "500500500500", //0
  41. "60500500500", //1
  42. "50060500500", //2
  43. "6060500500", //3
  44. "50050060500", //4
  45. "6050060500", //5
  46. "5006060500", //6
  47. "606060500", //7
  48. "50050050060", //8
  49. "6050050060", //9
  50. "5006050060", //A
  51. "606050060", //B
  52. "5005006060", //C
  53. "605006060", //D
  54. "500606060", //E
  55. "60606060" //F
  56. };
  57. internal override string GetPattern()
  58. {
  59. #region ZXing implementation, used for CRC
  60. string contents = text;
  61. int length = contents.Length;
  62. for (int i = 0; i < length; i++)
  63. {
  64. int indexInString = ALPHABET_STRING.IndexOf(contents[i]);
  65. if (indexInString < 0)
  66. throw new ArgumentException("Requested contents contains a not encodable character: '" + contents[i] + "'");
  67. }
  68. // quiet zone + start pattern + data + crc + termination bar + end pattern + quiet zone
  69. int codeWidth = 100 + 100 + length * 100 + 25 * 8 + 25 + 100 + 100;
  70. bool[] result = new bool[codeWidth];
  71. byte[] crcBuffer = new byte[4 * length + 8];
  72. int crcBufferPos = 0;
  73. int pos = 100;
  74. // start pattern
  75. pos += appendPattern(result, pos, startWidths, true);
  76. // data
  77. for (int i = 0; i < length; i++)
  78. {
  79. int indexInString = ALPHABET_STRING.IndexOf(contents[i]);
  80. int[] widths = numberWidths[indexInString];
  81. pos += appendPattern(result, pos, widths, true);
  82. // remember the position number for crc calculation
  83. crcBuffer[crcBufferPos++] = (byte)(indexInString & 1);
  84. crcBuffer[crcBufferPos++] = (byte)((indexInString >> 1) & 1);
  85. crcBuffer[crcBufferPos++] = (byte)((indexInString >> 2) & 1);
  86. crcBuffer[crcBufferPos++] = (byte)((indexInString >> 3) & 1);
  87. }
  88. // CRC calculation
  89. for (int i = 0; i < (4 * length); i++)
  90. {
  91. if (crcBuffer[i] != 0)
  92. {
  93. for (int j = 0; j < 9; j++)
  94. {
  95. crcBuffer[i + j] ^= crcGrid[j];
  96. }
  97. }
  98. }
  99. // append CRC pattern
  100. for (int i = 0; i < 8; i++)
  101. {
  102. switch (crcBuffer[length * 4 + i])
  103. {
  104. case 0:
  105. pos += appendPattern(result, pos, crc0Widths, true);
  106. break;
  107. case 1:
  108. pos += appendPattern(result, pos, crc1Widths, true);
  109. break;
  110. }
  111. }
  112. // termination bar
  113. pos += appendPattern(result, pos, terminationWidths, true);
  114. // end pattern
  115. appendPattern(result, pos, endWidths, false);
  116. //return result;
  117. #endregion
  118. string pattern = "" + start;
  119. //data
  120. foreach(char c in text)
  121. {
  122. int i;
  123. if (int.TryParse("" + c, out i))
  124. pattern += tabelle[i];
  125. else
  126. {
  127. switch (c)
  128. {
  129. case 'A':
  130. pattern += tabelle[10];
  131. break;
  132. case 'B':
  133. pattern += tabelle[11];
  134. break;
  135. case 'C':
  136. pattern += tabelle[12];
  137. break;
  138. case 'D':
  139. pattern += tabelle[13];
  140. break;
  141. case 'E':
  142. pattern += tabelle[14];
  143. break;
  144. case 'F':
  145. pattern += tabelle[15];
  146. break;
  147. default:
  148. throw new Exception("internal Error");
  149. }
  150. }
  151. }
  152. //CRC from ZXing
  153. for (int i = 0; i < 8; i++)
  154. {
  155. switch (crcBuffer[text.Length * 4 + i])
  156. {
  157. case 0:
  158. pattern += "500";
  159. break;
  160. case 1:
  161. pattern += "60";
  162. break;
  163. }
  164. }
  165. pattern += end;
  166. return pattern;
  167. }
  168. /// <summary>
  169. /// Appends the given pattern to the target array starting at pos.
  170. /// </summary>
  171. /// <param name="target">encode black/white pattern into this array</param>
  172. /// <param name="pos">position to start encoding at in <c>target</c></param>
  173. /// <param name="pattern">lengths of black/white runs to encode</param>
  174. /// <param name="startColor">starting color - false for white, true for black</param>
  175. /// <returns>the number of elements added to target.</returns>
  176. private int appendPattern(bool[] target, int pos, int[] pattern, bool startColor)
  177. {
  178. bool color = startColor;
  179. int numAdded = 0;
  180. foreach (int len in pattern)
  181. {
  182. for (int j = 0; j < len; j++)
  183. {
  184. target[pos++] = color;
  185. }
  186. numAdded += len;
  187. color = !color; // flip color after each segment
  188. }
  189. return numAdded;
  190. }
  191. }
  192. }