BarcodeIntelligentMail.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. using FastReport.Utils;
  2. using System;
  3. using System.ComponentModel;
  4. using System.Globalization;
  5. using System.Text.RegularExpressions;
  6. namespace FastReport.Barcode
  7. {
  8. /// <summary>
  9. /// Generates the Intelligent Mail (USPS) barcode.
  10. /// </summary>
  11. public class BarcodeIntelligentMail : LinearBarcodeBase
  12. {
  13. #region LinearBarcodeBase
  14. private bool quietZone;
  15. const string space = "2";
  16. /// <summary>
  17. /// Gets or sets the value indicating that quiet zone must be shown.
  18. /// </summary>
  19. [DefaultValue(false)]
  20. public bool QuietZone
  21. {
  22. get { return quietZone; }
  23. set { quietZone = value; }
  24. }
  25. /// <inheritdoc/>
  26. public override bool IsNumeric
  27. {
  28. get { return true; }
  29. }
  30. internal override string GetPattern()
  31. {
  32. string bars = Bars(text);
  33. if (QuietZone)
  34. bars = space + bars + space;
  35. return bars;
  36. }
  37. /// <inheritdoc/>
  38. public override void Assign(BarcodeBase source)
  39. {
  40. base.Assign(source);
  41. BarcodeIntelligentMail src = source as BarcodeIntelligentMail;
  42. QuietZone = src.QuietZone;
  43. }
  44. /// <inheritdoc />
  45. public override string GetDefaultValue()
  46. {
  47. return "12345678901234567890";
  48. }
  49. internal override void Serialize(FastReport.Utils.FRWriter writer, string prefix, BarcodeBase diff)
  50. {
  51. base.Serialize(writer, prefix, diff);
  52. BarcodeIntelligentMail c = diff as BarcodeIntelligentMail;
  53. if (c == null || QuietZone != c.QuietZone)
  54. writer.WriteBool(prefix + "QuietZone", QuietZone);
  55. }
  56. #endregion
  57. // for more information and specs check
  58. // http://ribbs.usps.gov/onecodesolution/USPS-B-3200D001.pdf
  59. int table2Of13Size = 78;
  60. int table5Of13Size = 1287;
  61. long entries2Of13;
  62. long entries5Of13;
  63. int[] table2Of13 = null;
  64. int[] table5Of13 = null;
  65. decimal[][] codewordArray = null;
  66. int[] barTopCharIndexArray = new int[] { 4, 0, 2, 6, 3, 5, 1, 9, 8, 7, 1, 2, 0, 6, 4, 8, 2, 9, 5, 3, 0, 1, 3, 7, 4, 6, 8, 9, 2, 0, 5, 1, 9, 4, 3, 8, 6, 7, 1, 2, 4, 3, 9, 5, 7, 8, 3, 0, 2, 1, 4, 0, 9, 1, 7, 0, 2, 4, 6, 3, 7, 1, 9, 5, 8 };
  67. int[] barBottomCharIndexArray = new int[] { 7, 1, 9, 5, 8, 0, 2, 4, 6, 3, 5, 8, 9, 7, 3, 0, 6, 1, 7, 4, 6, 8, 9, 2, 5, 1, 7, 5, 4, 3, 8, 7, 6, 0, 2, 5, 4, 9, 3, 0, 1, 6, 8, 2, 0, 4, 5, 9, 6, 7, 5, 2, 6, 3, 8, 5, 1, 9, 8, 7, 4, 0, 2, 6, 3 };
  68. int[] barTopCharShiftArray = new int[] { 3, 0, 8, 11, 1, 12, 8, 11, 10, 6, 4, 12, 2, 7, 9, 6, 7, 9, 2, 8, 4, 0, 12, 7, 10, 9, 0, 7, 10, 5, 7, 9, 6, 8, 2, 12, 1, 4, 2, 0, 1, 5, 4, 6, 12, 1, 0, 9, 4, 7, 5, 10, 2, 6, 9, 11, 2, 12, 6, 7, 5, 11, 0, 3, 2 };
  69. int[] barBottomCharShiftArray = new int[] { 2, 10, 12, 5, 9, 1, 5, 4, 3, 9, 11, 5, 10, 1, 6, 3, 4, 1, 10, 0, 2, 11, 8, 6, 1, 12, 3, 8, 6, 4, 4, 11, 0, 6, 1, 9, 11, 5, 3, 7, 3, 10, 7, 11, 8, 2, 10, 3, 5, 8, 0, 3, 12, 11, 8, 4, 5, 1, 3, 0, 7, 12, 9, 8, 10 };
  70. /// <summary>
  71. /// Initializes a new instance of the <see cref="BarcodeIntelligentMail"/> class with default settings.
  72. /// </summary>
  73. public BarcodeIntelligentMail()
  74. {
  75. table2Of13 = OneCodeInfo(1);
  76. table5Of13 = OneCodeInfo(2);
  77. codewordArray = OneCodeInfo();
  78. QuietZone = false;
  79. }
  80. string Bars(string source)
  81. {
  82. if (string.IsNullOrEmpty(source))
  83. return null;
  84. source = TrimOff(source, " -.");
  85. if (!Regex.IsMatch(source, "^[0-9][0-4]([0-9]{18})|([0-9]{23})|([0-9]{27})|([0-9]{29})$"))
  86. //return string.Empty;
  87. {
  88. MyRes res = new MyRes("Messages");
  89. throw new FormatException(res.Get("BarcodeFewError"));
  90. }
  91. int fcs = 0;
  92. long l = 0;
  93. decimal v = 0;
  94. string encoded = string.Empty, ds = string.Empty, zip = source.Substring(20);
  95. int[] byteArray = new int[14], ai = new int[66], ai1 = new int[66];
  96. decimal[][] ad = new decimal[11][];
  97. if (!string.IsNullOrEmpty(zip) && zip.Length > 0)
  98. l = long.Parse(zip, CultureInfo.InvariantCulture) + ((zip.Length == 5) ? 1 : ((zip.Length == 9) ? 100001 : (zip.Length == 11 ? 1000100001 : 0)));
  99. v = l * 10 + int.Parse(source.Substring(0, 1), CultureInfo.InvariantCulture);
  100. v = v * 5 + int.Parse(source.Substring(1, 1), CultureInfo.InvariantCulture);
  101. ds = v.ToString(CultureInfo.InvariantCulture) + source.Substring(2, 18);
  102. byteArray[12] = (int)(l & 255);
  103. byteArray[11] = (int)(l >> 8 & 255);
  104. byteArray[10] = (int)(l >> 16 & 255);
  105. byteArray[9] = (int)(l >> 24 & 255);
  106. byteArray[8] = (int)(l >> 32 & 255);
  107. OneCodeMathMultiply(ref byteArray, 13, 10);
  108. OneCodeMathAdd(ref byteArray, 13, int.Parse(source.Substring(0, 1), CultureInfo.InvariantCulture));
  109. OneCodeMathMultiply(ref byteArray, 13, 5);
  110. OneCodeMathAdd(ref byteArray, 13, int.Parse(source.Substring(1, 1), CultureInfo.InvariantCulture));
  111. for (short i = 2; i <= 19; i++)
  112. {
  113. OneCodeMathMultiply(ref byteArray, 13, 10);
  114. OneCodeMathAdd(ref byteArray, 13, int.Parse(source.Substring(i, 1), CultureInfo.InvariantCulture));
  115. }
  116. fcs = OneCodeMathFcs(byteArray);
  117. for (short i = 0; i <= 9; i++)
  118. {
  119. codewordArray[i][0] = entries2Of13 + entries5Of13;
  120. codewordArray[i][1] = 0;
  121. }
  122. codewordArray[0][0] = 659;
  123. codewordArray[9][0] = 636;
  124. OneCodeMathDivide(ds);
  125. codewordArray[9][1] *= 2;
  126. if (fcs >> 10 != 0) codewordArray[0][1] += 659;
  127. for (short i = 0; i <= 9; i++) ad[i] = new decimal[3];
  128. for (short i = 0; i <= 9; i++)
  129. {
  130. if (codewordArray[i][1] >= (decimal)(entries2Of13 + entries5Of13)) return null;
  131. ad[i][0] = 8192;
  132. ad[i][1] = (codewordArray[i][1] >= (decimal)entries2Of13) ? ad[i][1] = table2Of13[(int)(codewordArray[i][1] - entries2Of13)] : ad[i][1] = table5Of13[(int)codewordArray[i][1]];
  133. }
  134. for (short i = 0; i <= 9; i++) if ((fcs & 1 << i) != 0) ad[i][1] = ~(int)ad[i][1] & 8191;
  135. for (short i = 0; i <= 64; i++)
  136. {
  137. ai[i] = (int)ad[barTopCharIndexArray[i]][1] >> barTopCharShiftArray[i] & 1;
  138. ai1[i] = (int)ad[barBottomCharIndexArray[i]][1] >> barBottomCharShiftArray[i] & 1;
  139. }
  140. encoded = "";
  141. for (int i = 0; i <= 64; i++)
  142. {
  143. //if (ai[i] == 0) encoded += (ai1[i] == 0) ? "T" : "D";
  144. //else encoded += (ai1[i] == 0) ? "A" : "F";
  145. if (ai[i] == 0)
  146. encoded += (ai1[i] == 0) ? "E" : "G";
  147. else
  148. encoded += (ai1[i] == 0) ? "F" : "6";
  149. encoded += space;
  150. }
  151. return encoded.Substring(0, encoded.Length - 1);
  152. }
  153. int[] OneCodeInfo(byte topic)
  154. {
  155. int[] a;
  156. switch (topic)
  157. {
  158. case 1:
  159. a = new int[table2Of13Size + 1];
  160. OneCodeInitializeNof13Table(ref a, 2, table2Of13Size);
  161. entries5Of13 = table2Of13Size;
  162. break;
  163. default:
  164. a = new int[table5Of13Size + 1];
  165. OneCodeInitializeNof13Table(ref a, 5, table5Of13Size);
  166. entries2Of13 = table5Of13Size;
  167. break;
  168. }
  169. return a;
  170. }
  171. decimal[][] OneCodeInfo()
  172. {
  173. decimal[][] da = new decimal[11][];
  174. try
  175. {
  176. for (short i = 0; i <= 9; i++) da[i] = new decimal[3];
  177. return da;
  178. }
  179. finally
  180. {
  181. da = null;
  182. }
  183. }
  184. bool OneCodeInitializeNof13Table(ref int[] ai, int i, int j)
  185. {
  186. int i1 = 0;
  187. int j1 = j - 1;
  188. for (short k = 0; k <= 8191; k++)
  189. {
  190. int k1 = 0;
  191. for (int l1 = 0; l1 <= 12; l1++) if ((k & 1 << l1) != 0) k1 += 1;
  192. if (k1 == i)
  193. {
  194. int l = OneCodeMathReverse(k) >> 3;
  195. bool flag = k == l;
  196. if (l >= k)
  197. {
  198. if (flag)
  199. {
  200. ai[j1] = k;
  201. j1 -= 1;
  202. }
  203. else
  204. {
  205. ai[i1] = k;
  206. i1 += 1;
  207. ai[i1] = l;
  208. i1 += 1;
  209. }
  210. }
  211. }
  212. }
  213. return i1 == j1 + 1;
  214. }
  215. bool OneCodeMathAdd(ref int[] bytearray, int i, int j)
  216. {
  217. if (bytearray == null) return false;
  218. if (i < 1) return false;
  219. int x = (bytearray[i - 1] | (bytearray[i - 2] << 8)) + j;
  220. int l = x | 65535;
  221. int k = i - 3;
  222. bytearray[i - 1] = x & 255;
  223. bytearray[i - 2] = x >> 8 & 255;
  224. while (l == 1 && k > 0)
  225. {
  226. x = l + bytearray[k];
  227. bytearray[k] = x & 255;
  228. l = x | 255;
  229. k -= 1;
  230. }
  231. return true;
  232. }
  233. bool OneCodeMathDivide(string v)
  234. {
  235. int j = 10;
  236. string n = v;
  237. for (int k = j - 1; k >= 1; k += -1)
  238. {
  239. string r = string.Empty;
  240. int divider = (int)codewordArray[k][0];
  241. string copy = n;
  242. string left = "0";
  243. int l = copy.Length;
  244. for (short i = 1; i <= l; i++)
  245. {
  246. int divident = int.Parse(copy.Substring(0, i), CultureInfo.InvariantCulture);
  247. while (divident < divider & i < l - 1)
  248. {
  249. r = r + "0";
  250. i += 1;
  251. divident = int.Parse(copy.Substring(0, i), CultureInfo.InvariantCulture);
  252. }
  253. r = r + (divident / divider).ToString(CultureInfo.InvariantCulture);
  254. left = (divident % divider).ToString(CultureInfo.InvariantCulture).PadLeft(i, '0');
  255. copy = left + copy.Substring(i);
  256. }
  257. n = r.TrimStart('0');
  258. if (string.IsNullOrEmpty(n)) n = "0";
  259. codewordArray[k][1] = int.Parse(left, CultureInfo.InvariantCulture);
  260. if (k == 1) codewordArray[0][1] = int.Parse(r, CultureInfo.InvariantCulture);
  261. }
  262. return true;
  263. }
  264. int OneCodeMathFcs(int[] bytearray)
  265. {
  266. int c = 3893;
  267. int i = 2047;
  268. int j = bytearray[0] << 5;
  269. for (short b = 2; b <= 7; b++)
  270. {
  271. if (((i ^ j) & 1024) != 0) i = i << 1 ^ c;
  272. else i <<= 1;
  273. i = i & 2047;
  274. j <<= 1;
  275. }
  276. for (int l = 1; l <= 12; l++)
  277. {
  278. int k = bytearray[l] << 3;
  279. for (short b = 0; b <= 7; b++)
  280. {
  281. if (((i ^ k) & 1024) != 0) i = i << 1 ^ c;
  282. else i <<= 1;
  283. i = i & 2047;
  284. k <<= 1;
  285. }
  286. }
  287. return i;
  288. }
  289. bool OneCodeMathMultiply(ref int[] bytearray, int i, int j)
  290. {
  291. if (bytearray == null) return false;
  292. if (i < 1) return false;
  293. int l = 0;
  294. int k = 0;
  295. for (k = i - 1; k >= 1; k += -2)
  296. {
  297. int x = (bytearray[k] | (bytearray[k - 1] << 8)) * j + l;
  298. bytearray[k] = x & 255;
  299. bytearray[k - 1] = x >> 8 & 255;
  300. l = x >> 16;
  301. }
  302. if (k == 0) bytearray[0] = (bytearray[0] * j + l) & 255;
  303. return true;
  304. }
  305. int OneCodeMathReverse(int i)
  306. {
  307. int j = 0;
  308. for (short k = 0; k <= 15; k++)
  309. {
  310. j <<= 1;
  311. j = j | i & 1;
  312. i >>= 1;
  313. }
  314. return j;
  315. }
  316. string TrimOff(string source, string bad)
  317. {
  318. for (int i = 0, l = bad.Length - 1; i <= l; i++) source = source.Replace(bad.Substring(i, 1), string.Empty);
  319. return source;
  320. }
  321. }
  322. }