BarcodeMaxiCode.cs 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446
  1. using FastReport.Utils;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Drawing;
  6. using System.Text;
  7. namespace FastReport.Barcode
  8. {
  9. /// <summary>
  10. /// Generates the 2D MaxiCode barcode.
  11. /// </summary>
  12. public class BarcodeMaxiCode : Barcode2DBase
  13. {
  14. /// <summary>
  15. /// Sets the MaxiCode mode to use. Only modes 2 to 6 are supported.
  16. /// </summary>
  17. [DefaultValue(4)]
  18. public int Mode
  19. {
  20. get
  21. {
  22. return mode;
  23. }
  24. set
  25. {
  26. mode = value;
  27. }
  28. }
  29. //public int ECI { get; set; }
  30. const float FieldSizeFactor = 2.47f;
  31. const float PenSizeFactor = 4.5f;
  32. MaxiCodeImpl maxiCodeImpl;
  33. int mode;
  34. /// <summary>
  35. /// Initializes a new instance of the <see cref="BarcodeMaxiCode"/> class with default settings.
  36. /// </summary>
  37. public BarcodeMaxiCode()
  38. {
  39. Mode = 4;
  40. }
  41. internal override void Initialize(string text, bool showText, int angle, float zoom, bool showMarker)
  42. {
  43. base.Initialize(text, showText, angle, zoom, showMarker);
  44. maxiCodeImpl = new MaxiCodeImpl(base.text);
  45. maxiCodeImpl.setMode(Mode);
  46. maxiCodeImpl.encode();
  47. }
  48. internal override SizeF CalcBounds()
  49. {
  50. int textAdd = showText ? (int)(FontHeight) : 0;
  51. SizeF s = new SizeF();
  52. foreach (MaxiCodeImpl.Hexagon hex in maxiCodeImpl.hexagons)
  53. {
  54. for (int i = 0; i < hex.pointX.Length; i++)
  55. {
  56. float pointX = FieldSizeFactor * (float)hex.pointX[i];
  57. float pointY = FieldSizeFactor * (float)hex.pointY[i];
  58. if (pointX > s.Width)
  59. s.Width = pointX;
  60. if (pointY > s.Height)
  61. s.Height = pointY;
  62. }
  63. }
  64. if (s.Width <= 0)
  65. s.Width = 100;
  66. if (s.Height <= 0)
  67. s.Height = 100;
  68. s.Height += textAdd;
  69. return s;
  70. }
  71. internal override void Draw2DBarcode(IGraphics g, float kx, float ky)
  72. {
  73. Brush b = new SolidBrush(Color);
  74. Pen p = new Pen(Color, PenSizeFactor * ((kx + ky) / 2));
  75. foreach (MaxiCodeImpl.Hexagon hex in maxiCodeImpl.hexagons)
  76. {
  77. PointF[] points = new PointF[hex.pointX.Length];
  78. for (int i = 0; i < hex.pointX.Length; i++)
  79. points[i] = new PointF(FieldSizeFactor * kx * (float)hex.pointX[i], FieldSizeFactor * ky * (float)hex.pointY[i]);
  80. g.FillPolygon(b, points);
  81. }
  82. foreach (MaxiCodeImpl.Ellipse circle in maxiCodeImpl.target)
  83. {
  84. g.DrawEllipse(p,
  85. FieldSizeFactor * kx * (float)circle.x,
  86. FieldSizeFactor * ky * (float)circle.y,
  87. FieldSizeFactor * kx * ((float)circle.w - (float)circle.x),
  88. FieldSizeFactor * ky * ((float)circle.h - (float)circle.y));
  89. }
  90. b.Dispose();
  91. p.Dispose();
  92. }
  93. /// <inheritdoc/>
  94. public override void Assign(BarcodeBase source)
  95. {
  96. base.Assign(source);
  97. BarcodeMaxiCode src = source as BarcodeMaxiCode;
  98. Mode = src.Mode;
  99. }
  100. internal override void Serialize(FastReport.Utils.FRWriter writer, string prefix, BarcodeBase diff)
  101. {
  102. base.Serialize(writer, prefix, diff);
  103. BarcodeMaxiCode c = diff as BarcodeMaxiCode;
  104. if (c == null || Mode != c.Mode)
  105. writer.WriteInt(prefix + "Mode", Mode);
  106. }
  107. }
  108. /*
  109. * Copyright 2014-2015 Robin Stuart, Daniel Gredler
  110. *
  111. * Licensed under the Apache License, Version 2.0 (the "License");
  112. * you may not use this file except in compliance with the License.
  113. * You may obtain a copy of the License at
  114. *
  115. * http://www.apache.org/licenses/LICENSE-2.0
  116. *
  117. * Unless required by applicable law or agreed to in writing, software
  118. * distributed under the License is distributed on an "AS IS" BASIS,
  119. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  120. * See the License for the specific language governing permissions and
  121. * limitations under the License.
  122. */
  123. /**
  124. * Implements MaxiCode according to ISO 16023:2000.
  125. *
  126. * MaxiCode employs a pattern of hexagons around a central 'bulls-eye'
  127. * finder pattern. Encoding in several modes is supported, but encoding in
  128. * Mode 2 and 3 require primary messages to be set. Input characters can be
  129. * any from the ISO 8859-1 (Latin-1) character set.
  130. *
  131. * TODO: Add ECI functionality.
  132. *
  133. * @author <a href="mailto:rstuart114@gmail.com">Robin Stuart</a>
  134. * @author Daniel Gredler
  135. */
  136. class MaxiCodeImpl
  137. {
  138. public class ReedSolomon
  139. {
  140. private int logmod;
  141. private int rlen;
  142. private int[] logt;
  143. private int[] alog;
  144. private int[] rspoly;
  145. public int[] res;
  146. public int getResult(int count)
  147. {
  148. return res[count];
  149. }
  150. public void init_gf(int poly)
  151. {
  152. int m, b, p, v;
  153. // Find the top bit, and hence the symbol size
  154. for (b = 1, m = 0; b <= poly; b <<= 1)
  155. {
  156. m++;
  157. }
  158. b >>= 1;
  159. m--;
  160. // Calculate the log/alog tables
  161. logmod = (1 << m) - 1;
  162. logt = new int[logmod + 1];
  163. alog = new int[logmod];
  164. for (p = 1, v = 0; v < logmod; v++)
  165. {
  166. alog[v] = p;
  167. logt[p] = v;
  168. p <<= 1;
  169. if ((p & b) != 0)
  170. {
  171. p ^= poly;
  172. }
  173. }
  174. }
  175. public void init_code(int nsym, int index)
  176. {
  177. int i, k;
  178. rspoly = new int[nsym + 1];
  179. rlen = nsym;
  180. rspoly[0] = 1;
  181. for (i = 1; i <= nsym; i++)
  182. {
  183. rspoly[i] = 1;
  184. for (k = i - 1; k > 0; k--)
  185. {
  186. if (rspoly[k] != 0)
  187. {
  188. rspoly[k] = alog[(logt[rspoly[k]] + index) % logmod];
  189. }
  190. rspoly[k] ^= rspoly[k - 1];
  191. }
  192. rspoly[0] = alog[(logt[rspoly[0]] + index) % logmod];
  193. index++;
  194. }
  195. }
  196. public void encode(int len, int[] data)
  197. {
  198. int i, k, m;
  199. res = new int[rlen];
  200. for (i = 0; i < rlen; i++)
  201. {
  202. res[i] = 0;
  203. }
  204. for (i = 0; i < len; i++)
  205. {
  206. m = res[rlen - 1] ^ data[i];
  207. for (k = rlen - 1; k > 0; k--)
  208. {
  209. if ((m != 0) && (rspoly[k] != 0))
  210. {
  211. res[k] = res[k - 1] ^ alog[(logt[m] + logt[rspoly[k]]) % logmod];
  212. }
  213. else
  214. {
  215. res[k] = res[k - 1];
  216. }
  217. }
  218. if ((m != 0) && (rspoly[0] != 0))
  219. {
  220. res[0] = alog[(logt[m] + logt[rspoly[0]]) % logmod];
  221. }
  222. else
  223. {
  224. res[0] = 0;
  225. }
  226. }
  227. }
  228. }
  229. #if READONLY_STRUCTS
  230. public readonly struct Hexagon
  231. #else
  232. public struct Hexagon
  233. #endif
  234. {
  235. const double INK_SPREAD = 1.25;
  236. static readonly double[] OFFSET_X = new double[] { 0.0, 0.86, 0.86, 0.0, -0.86, -0.86 };
  237. static readonly double[] OFFSET_Y = new double[] { 1.0, 0.5, -0.5, -1.0, -0.5, 0.5 };
  238. public readonly double[] pointX;
  239. public readonly double[] pointY;
  240. public Hexagon(double centreX, double centreY)
  241. {
  242. pointX = new double[6];
  243. pointY = new double[6];
  244. for (int i = 0; i < 6; i++)
  245. {
  246. pointX[i] = centreX + (OFFSET_X[i] * INK_SPREAD);
  247. pointY[i] = centreY + (OFFSET_Y[i] * INK_SPREAD);
  248. }
  249. }
  250. }
  251. #if READONLY_STRUCTS
  252. public readonly struct Ellipse
  253. #else
  254. public struct Ellipse
  255. #endif
  256. {
  257. #pragma warning disable FR0006 // Field name of struct must be longer than 2 characters.
  258. public readonly double x;
  259. public readonly double y;
  260. public readonly double w;
  261. public readonly double h;
  262. #pragma warning restore FR0006 // Field name of struct must be longer than 2 characters.
  263. public Ellipse(double x, double y, double w, double h)
  264. {
  265. this.x = x;
  266. this.y = y;
  267. this.w = w;
  268. this.h = h;
  269. }
  270. }
  271. private int eciMode = 3;
  272. private byte[] inputBytes;
  273. //string error_msg;
  274. public List<Hexagon> hexagons = new List<Hexagon>();
  275. public List<Ellipse> target = new List<Ellipse>();
  276. private string text;
  277. public MaxiCodeImpl(string text)
  278. {
  279. this.text = text;
  280. }
  281. //========================================================================
  282. /** MaxiCode module sequence, from ISO/IEC 16023 Figure 5 (30 x 33 data grid). */
  283. static int[] MAXICODE_GRID = {
  284. 122, 121, 128, 127, 134, 133, 140, 139, 146, 145, 152, 151, 158, 157, 164, 163, 170, 169, 176, 175, 182, 181, 188, 187, 194, 193, 200, 199, 0, 0,
  285. 124, 123, 130, 129, 136, 135, 142, 141, 148, 147, 154, 153, 160, 159, 166, 165, 172, 171, 178, 177, 184, 183, 190, 189, 196, 195, 202, 201, 817, 0,
  286. 126, 125, 132, 131, 138, 137, 144, 143, 150, 149, 156, 155, 162, 161, 168, 167, 174, 173, 180, 179, 186, 185, 192, 191, 198, 197, 204, 203, 819, 818,
  287. 284, 283, 278, 277, 272, 271, 266, 265, 260, 259, 254, 253, 248, 247, 242, 241, 236, 235, 230, 229, 224, 223, 218, 217, 212, 211, 206, 205, 820, 0,
  288. 286, 285, 280, 279, 274, 273, 268, 267, 262, 261, 256, 255, 250, 249, 244, 243, 238, 237, 232, 231, 226, 225, 220, 219, 214, 213, 208, 207, 822, 821,
  289. 288, 287, 282, 281, 276, 275, 270, 269, 264, 263, 258, 257, 252, 251, 246, 245, 240, 239, 234, 233, 228, 227, 222, 221, 216, 215, 210, 209, 823, 0,
  290. 290, 289, 296, 295, 302, 301, 308, 307, 314, 313, 320, 319, 326, 325, 332, 331, 338, 337, 344, 343, 350, 349, 356, 355, 362, 361, 368, 367, 825, 824,
  291. 292, 291, 298, 297, 304, 303, 310, 309, 316, 315, 322, 321, 328, 327, 334, 333, 340, 339, 346, 345, 352, 351, 358, 357, 364, 363, 370, 369, 826, 0,
  292. 294, 293, 300, 299, 306, 305, 312, 311, 318, 317, 324, 323, 330, 329, 336, 335, 342, 341, 348, 347, 354, 353, 360, 359, 366, 365, 372, 371, 828, 827,
  293. 410, 409, 404, 403, 398, 397, 392, 391, 80, 79, 0, 0, 14, 13, 38, 37, 3, 0, 45, 44, 110, 109, 386, 385, 380, 379, 374, 373, 829, 0,
  294. 412, 411, 406, 405, 400, 399, 394, 393, 82, 81, 41, 0, 16, 15, 40, 39, 4, 0, 0, 46, 112, 111, 388, 387, 382, 381, 376, 375, 831, 830,
  295. 414, 413, 408, 407, 402, 401, 396, 395, 84, 83, 42, 0, 0, 0, 0, 0, 6, 5, 48, 47, 114, 113, 390, 389, 384, 383, 378, 377, 832, 0,
  296. 416, 415, 422, 421, 428, 427, 104, 103, 56, 55, 17, 0, 0, 0, 0, 0, 0, 0, 21, 20, 86, 85, 434, 433, 440, 439, 446, 445, 834, 833,
  297. 418, 417, 424, 423, 430, 429, 106, 105, 58, 57, 0, 0, 0, 0, 0, 0, 0, 0, 23, 22, 88, 87, 436, 435, 442, 441, 448, 447, 835, 0,
  298. 420, 419, 426, 425, 432, 431, 108, 107, 60, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 90, 89, 438, 437, 444, 443, 450, 449, 837, 836,
  299. 482, 481, 476, 475, 470, 469, 49, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 54, 53, 464, 463, 458, 457, 452, 451, 838, 0,
  300. 484, 483, 478, 477, 472, 471, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 466, 465, 460, 459, 454, 453, 840, 839,
  301. 486, 485, 480, 479, 474, 473, 52, 51, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 43, 468, 467, 462, 461, 456, 455, 841, 0,
  302. 488, 487, 494, 493, 500, 499, 98, 97, 62, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 92, 91, 506, 505, 512, 511, 518, 517, 843, 842,
  303. 490, 489, 496, 495, 502, 501, 100, 99, 64, 63, 0, 0, 0, 0, 0, 0, 0, 0, 29, 28, 94, 93, 508, 507, 514, 513, 520, 519, 844, 0,
  304. 492, 491, 498, 497, 504, 503, 102, 101, 66, 65, 18, 0, 0, 0, 0, 0, 0, 0, 19, 30, 96, 95, 510, 509, 516, 515, 522, 521, 846, 845,
  305. 560, 559, 554, 553, 548, 547, 542, 541, 74, 73, 33, 0, 0, 0, 0, 0, 0, 11, 68, 67, 116, 115, 536, 535, 530, 529, 524, 523, 847, 0,
  306. 562, 561, 556, 555, 550, 549, 544, 543, 76, 75, 0, 0, 8, 7, 36, 35, 12, 0, 70, 69, 118, 117, 538, 537, 532, 531, 526, 525, 849, 848,
  307. 564, 563, 558, 557, 552, 551, 546, 545, 78, 77, 0, 34, 10, 9, 26, 25, 0, 0, 72, 71, 120, 119, 540, 539, 534, 533, 528, 527, 850, 0,
  308. 566, 565, 572, 571, 578, 577, 584, 583, 590, 589, 596, 595, 602, 601, 608, 607, 614, 613, 620, 619, 626, 625, 632, 631, 638, 637, 644, 643, 852, 851,
  309. 568, 567, 574, 573, 580, 579, 586, 585, 592, 591, 598, 597, 604, 603, 610, 609, 616, 615, 622, 621, 628, 627, 634, 633, 640, 639, 646, 645, 853, 0,
  310. 570, 569, 576, 575, 582, 581, 588, 587, 594, 593, 600, 599, 606, 605, 612, 611, 618, 617, 624, 623, 630, 629, 636, 635, 642, 641, 648, 647, 855, 854,
  311. 728, 727, 722, 721, 716, 715, 710, 709, 704, 703, 698, 697, 692, 691, 686, 685, 680, 679, 674, 673, 668, 667, 662, 661, 656, 655, 650, 649, 856, 0,
  312. 730, 729, 724, 723, 718, 717, 712, 711, 706, 705, 700, 699, 694, 693, 688, 687, 682, 681, 676, 675, 670, 669, 664, 663, 658, 657, 652, 651, 858, 857,
  313. 732, 731, 726, 725, 720, 719, 714, 713, 708, 707, 702, 701, 696, 695, 690, 689, 684, 683, 678, 677, 672, 671, 666, 665, 660, 659, 654, 653, 859, 0,
  314. 734, 733, 740, 739, 746, 745, 752, 751, 758, 757, 764, 763, 770, 769, 776, 775, 782, 781, 788, 787, 794, 793, 800, 799, 806, 805, 812, 811, 861, 860,
  315. 736, 735, 742, 741, 748, 747, 754, 753, 760, 759, 766, 765, 772, 771, 778, 777, 784, 783, 790, 789, 796, 795, 802, 801, 808, 807, 814, 813, 862, 0,
  316. 738, 737, 744, 743, 750, 749, 756, 755, 762, 761, 768, 767, 774, 773, 780, 779, 786, 785, 792, 791, 798, 797, 804, 803, 810, 809, 816, 815, 864, 863
  317. };
  318. /**
  319. * ASCII character to Code Set mapping, from ISO/IEC 16023 Appendix A.
  320. * 1 = Set A, 2 = Set B, 3 = Set C, 4 = Set D, 5 = Set E.
  321. * 0 refers to special characters that fit into more than one set (e.g. GS).
  322. */
  323. static int[] MAXICODE_SET = {
  324. 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5,
  325. 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 0, 2, 1, 1, 1, 1, 1, 1,
  326. 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2,
  327. 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  328. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  329. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  330. 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4,
  331. 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  332. 5, 4, 5, 5, 5, 5, 5, 5, 4, 5, 3, 4, 3, 5, 5, 4, 4, 3, 3, 3,
  333. 4, 3, 5, 4, 4, 3, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3,
  334. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  335. 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
  336. 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
  337. };
  338. /** ASCII character to symbol value, from ISO/IEC 16023 Appendix A. */
  339. static int[] MAXICODE_SYMBOL_CHAR = {
  340. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
  341. 20, 21, 22, 23, 24, 25, 26, 30, 28, 29, 30, 35, 32, 53, 34, 35, 36, 37, 38, 39,
  342. 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 37,
  343. 38, 39, 40, 41, 52, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
  344. 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 42, 43, 44, 45, 46, 0, 1, 2, 3,
  345. 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
  346. 24, 25, 26, 32, 54, 34, 35, 36, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 47, 48,
  347. 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 36,
  348. 37, 37, 38, 39, 40, 41, 42, 43, 38, 44, 37, 39, 38, 45, 46, 40, 41, 39, 40, 41,
  349. 42, 42, 47, 43, 44, 43, 44, 45, 45, 46, 47, 46, 0, 1, 2, 3, 4, 5, 6, 7,
  350. 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 32,
  351. 33, 34, 35, 36, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
  352. 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 32, 33, 34, 35, 36
  353. };
  354. int mode;
  355. int structuredAppendPosition = 1;
  356. int structuredAppendTotal = 1;
  357. string primaryData = "";
  358. int[] codewords;
  359. int[] source;
  360. int[] set = new int[144];
  361. int[] character = new int[144];
  362. bool[,] grid = new bool[33, 30];
  363. /**
  364. * Sets the MaxiCode mode to use. Only modes 2 to 6 are supported.
  365. *
  366. * @param mode the MaxiCode mode to use
  367. */
  368. public void setMode(int mode)
  369. {
  370. if (mode < 2 || mode > 6)
  371. {
  372. throw new ArgumentOutOfRangeException("Invalid MaxiCode mode: " + mode);
  373. }
  374. this.mode = mode;
  375. }
  376. /**
  377. * Returns the MaxiCode mode being used. Only modes 2 to 6 are supported.
  378. *
  379. * @return the MaxiCode mode being used
  380. */
  381. public int getMode()
  382. {
  383. return mode;
  384. }
  385. /**
  386. * If this MaxiCode symbol is part of a series of MaxiCode symbols appended in a structured format, this method sets the
  387. * position of this symbol in the series. Valid values are 1 through 8 inclusive.
  388. *
  389. * @param position the position of this MaxiCode symbol in the structured append series
  390. */
  391. public void setStructuredAppendPosition(int position)
  392. {
  393. if (position < 1 || position > 8)
  394. {
  395. throw new ArgumentOutOfRangeException("Invalid MaxiCode structured append position: " + position);
  396. }
  397. this.structuredAppendPosition = position;
  398. }
  399. /**
  400. * Returns the position of this MaxiCode symbol in a series of symbols using structured append. If this symbol is not part of
  401. * such a series, this method will return <code>1</code>.
  402. *
  403. * @return the position of this MaxiCode symbol in a series of symbols using structured append
  404. */
  405. public int getStructuredAppendPosition()
  406. {
  407. return structuredAppendPosition;
  408. }
  409. /**
  410. * If this MaxiCode symbol is part of a series of MaxiCode symbols appended in a structured format, this method sets the total
  411. * number of symbols in the series. Valid values are 1 through 8 inclusive. A value of 1 indicates that this symbol is not
  412. * part of a structured append series.
  413. *
  414. * @param total the total number of MaxiCode symbols in the structured append series
  415. */
  416. public void setStructuredAppendTotal(int total)
  417. {
  418. if (total < 1 || total > 8)
  419. {
  420. throw new ArgumentOutOfRangeException("Invalid MaxiCode structured append total: " + total);
  421. }
  422. this.structuredAppendTotal = total;
  423. }
  424. /**
  425. * Returns the size of the series of MaxiCode symbols using structured append that this symbol is part of. If this symbol is
  426. * not part of a structured append series, this method will return <code>1</code>.
  427. *
  428. * @return size of the series that this symbol is part of
  429. */
  430. public int getStructuredAppendTotal()
  431. {
  432. return structuredAppendTotal;
  433. }
  434. /**
  435. * Sets the primary data. Should only be used for modes 2 and 3. Must conform to the following structure:
  436. *
  437. * <table summary="Expected primary data structure.">
  438. * <tr><th>Characters</th><th>Meaning</th></tr>
  439. * <tr><td>1-9</td><td>Postal code data which can consist of up to 9 digits (for mode 2) or up to 6
  440. * alphanumeric characters (for mode 3). Remaining unused characters should be
  441. * filled with the SPACE character (ASCII 32).</td></tr>
  442. * <tr><td>10-12</td><td>Three-digit country code according to ISO-3166.</td></tr>
  443. * <tr><td>13-15</td><td>Three digit service code. This depends on your parcel courier.</td></tr>
  444. * </table>
  445. *
  446. * @param primary the primary data
  447. */
  448. public void setPrimary(String primary)
  449. {
  450. primaryData = primary;
  451. }
  452. /**
  453. * Returns the primary data for this MaxiCode symbol. Should only be used for modes 2 and 3.
  454. *
  455. * @return the primary data for this MaxiCode symbol
  456. */
  457. public String getPrimary()
  458. {
  459. return primaryData;
  460. }
  461. /** {@inheritDoc} */
  462. //@Override
  463. public bool encode()
  464. {
  465. inputBytes = Encoding.UTF8.GetBytes(text);
  466. // copy input data over into source
  467. int sourcelen = text.Length;
  468. source = new int[sourcelen];
  469. //eciProcess();
  470. for (int i = 0; i < sourcelen; i++)
  471. {
  472. source[i] = inputBytes[i] & 0xFF;
  473. }
  474. // mode 2 -> mode 3 if postal code isn't strictly numeric
  475. if (mode == 2)
  476. {
  477. for (int i = 0; i < 10 && i < primaryData.Length; i++)
  478. {
  479. if ((primaryData[i] < '0') || (primaryData[i] > '9'))
  480. {
  481. mode = 3;
  482. break;
  483. }
  484. }
  485. }
  486. // initialize the set and character arrays
  487. if (!processText())
  488. {
  489. //error_msg = "Input data too long";
  490. //return false;
  491. throw new Exception("Input data too long");
  492. }
  493. // start building the codeword array, starting with a copy of the character data
  494. // insert primary message if this is a structured carrier message; insert mode otherwise
  495. codewords = new int[character.Length];
  496. character.CopyTo(codewords, 0);
  497. if (mode == 2 || mode == 3)
  498. {
  499. int[] _primary = getPrimaryCodewords();
  500. if (_primary == null)
  501. {
  502. return false;
  503. }
  504. codewords = insert(codewords, 0, _primary);
  505. }
  506. else
  507. {
  508. codewords = insert(codewords, 0, new int[] { mode });
  509. }
  510. // insert structured append flag if necessary
  511. if (structuredAppendTotal > 1)
  512. {
  513. int[] flag = new int[2];
  514. flag[0] = 33; // padding
  515. flag[1] = ((structuredAppendPosition - 1) << 3) | (structuredAppendTotal - 1); // position + total
  516. int index;
  517. if (mode == 2 || mode == 3)
  518. {
  519. index = 10; // first two data symbols in the secondary message
  520. }
  521. else
  522. {
  523. index = 1; // first two data symbols in the primary message (first symbol at index 0 isn't a data symbol)
  524. }
  525. codewords = insert(codewords, index, flag);
  526. }
  527. int secondaryMax, secondaryECMax;
  528. if (mode == 5)
  529. {
  530. // 68 data codewords, 56 error corrections in secondary message
  531. secondaryMax = 68;
  532. secondaryECMax = 56;
  533. }
  534. else
  535. {
  536. // 84 data codewords, 40 error corrections in secondary message
  537. secondaryMax = 84;
  538. secondaryECMax = 40;
  539. }
  540. // truncate data codewords to maximum data space available
  541. int totalMax = secondaryMax + 10;
  542. if (codewords.Length > totalMax)
  543. {
  544. //codewords = codewords.Take(totalMax).ToArray();
  545. int[] __codewords = new int[totalMax];
  546. Array.Copy(codewords, __codewords, totalMax);
  547. codewords = __codewords;
  548. }
  549. // insert primary error correction between primary message and secondary message (always EEC)
  550. //int[] primary = codewords.Take(10).ToArray();
  551. int[] primary = new int[10];
  552. Array.Copy(codewords, 0, primary, 0, 10);
  553. int[] primaryCheck = getErrorCorrection(primary, 10);
  554. codewords = insert(codewords, 10, primaryCheck);
  555. // calculate secondary error correction
  556. //int[] secondary = codewords.Skip(20).ToArray();
  557. int[] secondary = new int[codewords.Length - 20];
  558. Array.Copy(codewords, 20, secondary, 0, secondary.Length);
  559. int[] secondaryOdd = new int[secondary.Length / 2];
  560. int[] secondaryEven = new int[secondary.Length / 2];
  561. for (int i = 0; i < secondary.Length; i++)
  562. {
  563. if ((i & 1) != 0)
  564. { // odd
  565. secondaryOdd[(i - 1) / 2] = secondary[i];
  566. }
  567. else
  568. { // even
  569. secondaryEven[i / 2] = secondary[i];
  570. }
  571. }
  572. int[] secondaryECOdd = getErrorCorrection(secondaryOdd, secondaryECMax / 2);
  573. int[] secondaryECEven = getErrorCorrection(secondaryEven, secondaryECMax / 2);
  574. // add secondary error correction after secondary message
  575. int[] _codewords = codewords;
  576. codewords = new int[codewords.Length + secondaryECOdd.Length + secondaryECEven.Length];
  577. Array.Copy(_codewords, codewords, _codewords.Length);
  578. //codewords = Arrays.copyOf(codewords, codewords.Length + secondaryECOdd.Length + secondaryECEven.Length);
  579. for (int i = 0; i < secondaryECOdd.Length; i++)
  580. {
  581. codewords[20 + secondaryMax + (2 * i) + 1] = secondaryECOdd[i];
  582. }
  583. for (int i = 0; i < secondaryECEven.Length; i++)
  584. {
  585. codewords[20 + secondaryMax + (2 * i)] = secondaryECEven[i];
  586. }
  587. //encodeInfo += "Mode: " + mode + "\n";
  588. //encodeInfo += "ECC Codewords: " + secondaryECMax + "\n";
  589. //encodeInfo += "Codewords: ";
  590. //for (int i = 0; i < codewords.Length; i++)
  591. //{
  592. // encodeInfo += Integer.toString(codewords[i]) + " ";
  593. //}
  594. //encodeInfo += "\n";
  595. // copy data into symbol grid
  596. int[] bit_pattern = new int[7];
  597. for (int i = 0; i < 33; i++)
  598. {
  599. for (int j = 0; j < 30; j++)
  600. {
  601. int block = (MAXICODE_GRID[(i * 30) + j] + 5) / 6;
  602. int bit = (MAXICODE_GRID[(i * 30) + j] + 5) % 6;
  603. if (block != 0)
  604. {
  605. bit_pattern[0] = (codewords[block - 1] & 0x20) >> 5;
  606. bit_pattern[1] = (codewords[block - 1] & 0x10) >> 4;
  607. bit_pattern[2] = (codewords[block - 1] & 0x8) >> 3;
  608. bit_pattern[3] = (codewords[block - 1] & 0x4) >> 2;
  609. bit_pattern[4] = (codewords[block - 1] & 0x2) >> 1;
  610. bit_pattern[5] = (codewords[block - 1] & 0x1);
  611. if (bit_pattern[bit] != 0)
  612. {
  613. grid[i, j] = true;
  614. }
  615. else
  616. {
  617. grid[i, j] = false;
  618. }
  619. }
  620. }
  621. }
  622. // add orientation markings
  623. grid[0, 28] = true; // top right filler
  624. grid[0, 29] = true;
  625. grid[9, 10] = true; // top left marker
  626. grid[9, 11] = true;
  627. grid[10, 11] = true;
  628. grid[15, 7] = true; // left hand marker
  629. grid[16, 8] = true;
  630. grid[16, 20] = true; // right hand marker
  631. grid[17, 20] = true;
  632. grid[22, 10] = true; // bottom left marker
  633. grid[23, 10] = true;
  634. grid[22, 17] = true; // bottom right marker
  635. grid[23, 17] = true;
  636. // the following is provided for compatibility, but the results are not useful
  637. //row_count = 33;
  638. //readable = "";
  639. //pattern = new String[33];
  640. //row_height = new int[33];
  641. //for (int i = 0; i < 33; i++)
  642. //{
  643. // StringBuilder bin = new StringBuilder(30);
  644. // for (int j = 0; j < 30; j++)
  645. // {
  646. // if (grid[i][j])
  647. // {
  648. // bin.append("1");
  649. // }
  650. // else
  651. // {
  652. // bin.append("0");
  653. // }
  654. // }
  655. // pattern[i] = bin2pat(bin.toString());
  656. // row_height[i] = 1;
  657. //}
  658. //symbol_height = 72;
  659. //symbol_width = 74;
  660. plotSymbol();
  661. return true;
  662. }
  663. /**
  664. * Extracts the postal code, country code and service code from the primary data and returns the corresponding primary message
  665. * codewords.
  666. *
  667. * @return the primary message codewords
  668. */
  669. int[] getPrimaryCodewords()
  670. {
  671. //assert mode == 2 || mode == 3;
  672. if (primaryData.Length != 15)
  673. {
  674. //error_msg = "Invalid Primary String";
  675. //return null;
  676. throw new Exception("Invalid Primary String");
  677. }
  678. for (int i = 9; i < 15; i++)
  679. { /* check that country code and service are numeric */
  680. if ((primaryData[i] < '0') || (primaryData[i] > '9'))
  681. {
  682. //error_msg = "Invalid Primary String";
  683. //return null;
  684. throw new Exception("Invalid Primary String");
  685. }
  686. }
  687. String postcode;
  688. if (mode == 2)
  689. {
  690. postcode = primaryData.Substring(0, 9);
  691. int index = postcode.IndexOf(' ');
  692. if (index != -1)
  693. {
  694. postcode = postcode.Substring(0, index);
  695. }
  696. }
  697. else
  698. {
  699. // if (mode == 3)
  700. postcode = primaryData.Substring(0, 6);
  701. }
  702. int country = int.Parse(primaryData.Substring(9, 3));
  703. int service = int.Parse(primaryData.Substring(12, 3));
  704. //if (debug)
  705. //{
  706. // System.out.println("Using mode " + mode);
  707. // System.out.println(" Postcode: " + postcode);
  708. // System.out.println(" Country Code: " + country);
  709. // System.out.println(" Service: " + service);
  710. //}
  711. if (mode == 2)
  712. {
  713. return getMode2PrimaryCodewords(postcode, country, service);
  714. }
  715. else
  716. { // mode == 3
  717. return getMode3PrimaryCodewords(postcode, country, service);
  718. }
  719. }
  720. /**
  721. * Returns the primary message codewords for mode 2.
  722. *
  723. * @param postcode the postal code
  724. * @param country the country code
  725. * @param service the service code
  726. * @return the primary message, as codewords
  727. */
  728. static int[] getMode2PrimaryCodewords(String postcode, int country, int service)
  729. {
  730. for (int i = 0; i < postcode.Length; i++)
  731. {
  732. if (postcode[i] < '0' || postcode[i] > '9')
  733. {
  734. postcode = postcode.Substring(0, i);
  735. break;
  736. }
  737. }
  738. int postcodeNum = int.Parse(postcode);
  739. int[] primary = new int[10];
  740. primary[0] = ((postcodeNum & 0x03) << 4) | 2;
  741. primary[1] = ((postcodeNum & 0xfc) >> 2);
  742. primary[2] = ((postcodeNum & 0x3f00) >> 8);
  743. primary[3] = ((postcodeNum & 0xfc000) >> 14);
  744. primary[4] = ((postcodeNum & 0x3f00000) >> 20);
  745. primary[5] = ((postcodeNum & 0x3c000000) >> 26) | ((postcode.Length & 0x3) << 4);
  746. primary[6] = ((postcode.Length & 0x3c) >> 2) | ((country & 0x3) << 4);
  747. primary[7] = (country & 0xfc) >> 2;
  748. primary[8] = ((country & 0x300) >> 8) | ((service & 0xf) << 2);
  749. primary[9] = ((service & 0x3f0) >> 4);
  750. return primary;
  751. }
  752. /**
  753. * Returns the primary message codewords for mode 3.
  754. *
  755. * @param postcode the postal code
  756. * @param country the country code
  757. * @param service the service code
  758. * @return the primary message, as codewords
  759. */
  760. static int[] getMode3PrimaryCodewords(String postcode, int country, int service)
  761. {
  762. int[] postcodeNums = new int[postcode.Length];
  763. postcode = postcode.ToUpper();
  764. for (int i = 0; i < postcodeNums.Length; i++)
  765. {
  766. postcodeNums[i] = postcode[i];
  767. if (postcode[i] >= 'A' && postcode[i] <= 'Z')
  768. {
  769. // (Capital) letters shifted to Code Set A values
  770. postcodeNums[i] -= 64;
  771. }
  772. if (postcodeNums[i] == 27 || postcodeNums[i] == 31 || postcodeNums[i] == 33 || postcodeNums[i] >= 59)
  773. {
  774. // Not a valid postal code character, use space instead
  775. postcodeNums[i] = 32;
  776. }
  777. // Input characters lower than 27 (NUL - SUB) in postal code are interpreted as capital
  778. // letters in Code Set A (e.g. LF becomes 'J')
  779. }
  780. int[] primary = new int[10];
  781. primary[0] = ((postcodeNums[5] & 0x03) << 4) | 3;
  782. primary[1] = ((postcodeNums[4] & 0x03) << 4) | ((postcodeNums[5] & 0x3c) >> 2);
  783. primary[2] = ((postcodeNums[3] & 0x03) << 4) | ((postcodeNums[4] & 0x3c) >> 2);
  784. primary[3] = ((postcodeNums[2] & 0x03) << 4) | ((postcodeNums[3] & 0x3c) >> 2);
  785. primary[4] = ((postcodeNums[1] & 0x03) << 4) | ((postcodeNums[2] & 0x3c) >> 2);
  786. primary[5] = ((postcodeNums[0] & 0x03) << 4) | ((postcodeNums[1] & 0x3c) >> 2);
  787. primary[6] = ((postcodeNums[0] & 0x3c) >> 2) | ((country & 0x3) << 4);
  788. primary[7] = (country & 0xfc) >> 2;
  789. primary[8] = ((country & 0x300) >> 8) | ((service & 0xf) << 2);
  790. primary[9] = ((service & 0x3f0) >> 4);
  791. return primary;
  792. }
  793. /**
  794. * Formats text according to Appendix A, populating the {@link #set} and {@link #character} arrays.
  795. *
  796. * @return true if the content fits in this symbol and was formatted; false otherwise
  797. */
  798. bool processText()
  799. {
  800. int Length = text.Length;
  801. int i, j, count, current_set;
  802. if (Length > 138)
  803. {
  804. return false;
  805. }
  806. for (i = 0; i < 144; i++)
  807. {
  808. set[i] = -1;
  809. character[i] = 0;
  810. }
  811. for (i = 0; i < Length; i++)
  812. {
  813. /* Look up characters in table from Appendix A - this gives
  814. value and code set for most characters */
  815. set[i] = MAXICODE_SET[source[i]];
  816. character[i] = MAXICODE_SYMBOL_CHAR[source[i]];
  817. }
  818. // If a character can be represented in more than one code set, pick which version to use.
  819. if (set[0] == 0)
  820. {
  821. if (character[0] == 13)
  822. {
  823. character[0] = 0;
  824. }
  825. set[0] = 1;
  826. }
  827. for (i = 1; i < Length; i++)
  828. {
  829. if (set[i] == 0)
  830. {
  831. /* Special character that can be represented in more than one code set. */
  832. if (character[i] == 13)
  833. {
  834. /* Carriage Return */
  835. set[i] = bestSurroundingSet(i, Length, 1, 5);
  836. if (set[i] == 5)
  837. {
  838. character[i] = 13;
  839. }
  840. else
  841. {
  842. character[i] = 0;
  843. }
  844. }
  845. else if (character[i] == 28)
  846. {
  847. /* FS */
  848. set[i] = bestSurroundingSet(i, Length, 1, 2, 3, 4, 5);
  849. if (set[i] == 5)
  850. {
  851. character[i] = 32;
  852. }
  853. }
  854. else if (character[i] == 29)
  855. {
  856. /* GS */
  857. set[i] = bestSurroundingSet(i, Length, 1, 2, 3, 4, 5);
  858. if (set[i] == 5)
  859. {
  860. character[i] = 33;
  861. }
  862. }
  863. else if (character[i] == 30)
  864. {
  865. /* RS */
  866. set[i] = bestSurroundingSet(i, Length, 1, 2, 3, 4, 5);
  867. if (set[i] == 5)
  868. {
  869. character[i] = 34;
  870. }
  871. }
  872. else if (character[i] == 32)
  873. {
  874. /* Space */
  875. set[i] = bestSurroundingSet(i, Length, 1, 2, 3, 4, 5);
  876. if (set[i] == 1)
  877. {
  878. character[i] = 32;
  879. }
  880. else if (set[i] == 2)
  881. {
  882. character[i] = 47;
  883. }
  884. else
  885. {
  886. character[i] = 59;
  887. }
  888. }
  889. else if (character[i] == 44)
  890. {
  891. /* Comma */
  892. set[i] = bestSurroundingSet(i, Length, 1, 2);
  893. if (set[i] == 2)
  894. {
  895. character[i] = 48;
  896. }
  897. }
  898. else if (character[i] == 46)
  899. {
  900. /* Full Stop */
  901. set[i] = bestSurroundingSet(i, Length, 1, 2);
  902. if (set[i] == 2)
  903. {
  904. character[i] = 49;
  905. }
  906. }
  907. else if (character[i] == 47)
  908. {
  909. /* Slash */
  910. set[i] = bestSurroundingSet(i, Length, 1, 2);
  911. if (set[i] == 2)
  912. {
  913. character[i] = 50;
  914. }
  915. }
  916. else if (character[i] == 58)
  917. {
  918. /* Colon */
  919. set[i] = bestSurroundingSet(i, Length, 1, 2);
  920. if (set[i] == 2)
  921. {
  922. character[i] = 51;
  923. }
  924. }
  925. }
  926. }
  927. for (i = Length; i < set.Length; i++)
  928. {
  929. /* Add the padding */
  930. if (set[Length - 1] == 2)
  931. {
  932. set[i] = 2;
  933. }
  934. else
  935. {
  936. set[i] = 1;
  937. }
  938. character[i] = 33;
  939. }
  940. /* Find candidates for number compression (not allowed in primary message in modes 2 and 3). */
  941. if (mode == 2 || mode == 3)
  942. {
  943. j = 9;
  944. }
  945. else
  946. {
  947. j = 0;
  948. }
  949. count = 0;
  950. for (i = j; i < 143; i++)
  951. {
  952. if (set[i] == 1 && character[i] >= 48 && character[i] <= 57)
  953. {
  954. /* Character is a number */
  955. count++;
  956. }
  957. else
  958. {
  959. count = 0;
  960. }
  961. if (count == 9)
  962. {
  963. /* Nine digits in a row can be compressed */
  964. set[i] = 6;
  965. set[i - 1] = 6;
  966. set[i - 2] = 6;
  967. set[i - 3] = 6;
  968. set[i - 4] = 6;
  969. set[i - 5] = 6;
  970. set[i - 6] = 6;
  971. set[i - 7] = 6;
  972. set[i - 8] = 6;
  973. count = 0;
  974. }
  975. }
  976. /* Add shift and latch characters */
  977. current_set = 1;
  978. i = 0;
  979. do
  980. {
  981. if ((set[i] != current_set) && (set[i] != 6))
  982. {
  983. switch (set[i])
  984. {
  985. case 1:
  986. if (i + 1 < set.Length && set[i + 1] == 1)
  987. {
  988. if (i + 2 < set.Length && set[i + 2] == 1)
  989. {
  990. if (i + 3 < set.Length && set[i + 3] == 1)
  991. {
  992. /* Latch A */
  993. insert(i, 63);
  994. current_set = 1;
  995. Length++;
  996. i += 3;
  997. }
  998. else
  999. {
  1000. /* 3 Shift A */
  1001. insert(i, 57);
  1002. Length++;
  1003. i += 2;
  1004. }
  1005. }
  1006. else
  1007. {
  1008. /* 2 Shift A */
  1009. insert(i, 56);
  1010. Length++;
  1011. i++;
  1012. }
  1013. }
  1014. else
  1015. {
  1016. /* Shift A */
  1017. insert(i, 59);
  1018. Length++;
  1019. }
  1020. break;
  1021. case 2:
  1022. if (i + 1 < set.Length && set[i + 1] == 2)
  1023. {
  1024. /* Latch B */
  1025. insert(i, 63);
  1026. current_set = 2;
  1027. Length++;
  1028. i++;
  1029. }
  1030. else
  1031. {
  1032. /* Shift B */
  1033. insert(i, 59);
  1034. Length++;
  1035. }
  1036. break;
  1037. case 3:
  1038. if (i + 3 < set.Length && set[i + 1] == 3 && set[i + 2] == 3 && set[i + 3] == 3)
  1039. {
  1040. /* Lock In C */
  1041. insert(i, 60);
  1042. insert(i, 60);
  1043. current_set = 3;
  1044. Length++;
  1045. i += 3;
  1046. }
  1047. else
  1048. {
  1049. /* Shift C */
  1050. insert(i, 60);
  1051. Length++;
  1052. }
  1053. break;
  1054. case 4:
  1055. if (i + 3 < set.Length && set[i + 1] == 4 && set[i + 2] == 4 && set[i + 3] == 4)
  1056. {
  1057. /* Lock In D */
  1058. insert(i, 61);
  1059. insert(i, 61);
  1060. current_set = 4;
  1061. Length++;
  1062. i += 3;
  1063. }
  1064. else
  1065. {
  1066. /* Shift D */
  1067. insert(i, 61);
  1068. Length++;
  1069. }
  1070. break;
  1071. case 5:
  1072. if (i + 3 < set.Length && set[i + 1] == 5 && set[i + 2] == 5 && set[i + 3] == 5)
  1073. {
  1074. /* Lock In E */
  1075. insert(i, 62);
  1076. insert(i, 62);
  1077. current_set = 5;
  1078. Length++;
  1079. i += 3;
  1080. }
  1081. else
  1082. {
  1083. /* Shift E */
  1084. insert(i, 62);
  1085. Length++;
  1086. }
  1087. break;
  1088. default:
  1089. throw new Exception("Unexpected set " + set[i] + " at index " + i + ".");
  1090. }
  1091. i++;
  1092. }
  1093. i++;
  1094. } while (i < set.Length);
  1095. /* Number compression has not been forgotten! It's handled below. */
  1096. i = 0;
  1097. do
  1098. {
  1099. if (set[i] == 6)
  1100. {
  1101. /* Number compression */
  1102. int value = 0;
  1103. for (j = 0; j < 9; j++)
  1104. {
  1105. value *= 10;
  1106. value += (character[i + j] - '0');
  1107. }
  1108. character[i] = 31; /* NS */
  1109. character[i + 1] = (value & 0x3f000000) >> 24;
  1110. character[i + 2] = (value & 0xfc0000) >> 18;
  1111. character[i + 3] = (value & 0x3f000) >> 12;
  1112. character[i + 4] = (value & 0xfc0) >> 6;
  1113. character[i + 5] = (value & 0x3f);
  1114. i += 6;
  1115. for (j = i; j < 140; j++)
  1116. {
  1117. set[j] = set[j + 3];
  1118. character[j] = character[j + 3];
  1119. }
  1120. Length -= 3;
  1121. }
  1122. else
  1123. {
  1124. i++;
  1125. }
  1126. } while (i < set.Length);
  1127. /* Inject ECI codes to beginning of data, according to Table 3 */
  1128. if (eciMode != 3)
  1129. {
  1130. insert(0, 27); // ECI
  1131. if ((eciMode >= 0) && (eciMode <= 31))
  1132. {
  1133. insert(1, eciMode & 0x1F);
  1134. Length += 2;
  1135. }
  1136. if ((eciMode >= 32) && (eciMode <= 1023))
  1137. {
  1138. insert(1, 0x20 + (eciMode >> 6));
  1139. insert(2, eciMode & 0x3F);
  1140. Length += 3;
  1141. }
  1142. if ((eciMode >= 1024) && (eciMode <= 32767))
  1143. {
  1144. insert(1, 0x30 + (eciMode >> 12));
  1145. insert(2, (eciMode >> 6) & 0x3F);
  1146. insert(3, eciMode & 0x3F);
  1147. Length += 4;
  1148. }
  1149. if ((eciMode >= 32768) && (eciMode <= 999999))
  1150. {
  1151. insert(1, 0x38 + (eciMode >> 18));
  1152. insert(2, (eciMode >> 12) & 0x3F);
  1153. insert(3, (eciMode >> 6) & 0x3F);
  1154. insert(4, eciMode & 0x3F);
  1155. Length += 5;
  1156. }
  1157. }
  1158. /* Make sure we haven't exceeded the maximum data Length. */
  1159. if ((mode == 2 || mode == 3) && Length > 84)
  1160. {
  1161. return false;
  1162. }
  1163. if ((mode == 4 || mode == 6) && Length > 93)
  1164. {
  1165. return false;
  1166. }
  1167. if (mode == 5 && Length > 77)
  1168. {
  1169. return false;
  1170. }
  1171. return true;
  1172. }
  1173. /**
  1174. * Guesses the best set to use at the specified index by looking at the surrounding sets. In general, characters in
  1175. * lower-numbered sets are more common, so we choose them if we can. If no good surrounding sets can be found, the default
  1176. * value returned is the first value from the valid set.
  1177. *
  1178. * @param index the current index
  1179. * @param Length the maximum Length to look at
  1180. * @param valid the valid sets for this index
  1181. * @return the best set to use at the specified index
  1182. */
  1183. int bestSurroundingSet(int index, int Length, params int[] valid)
  1184. {
  1185. int option1 = set[index - 1];
  1186. if (index + 1 < Length)
  1187. {
  1188. // we have two options to check
  1189. int option2 = set[index + 1];
  1190. if (contains(valid, option1) && contains(valid, option2))
  1191. {
  1192. return Math.Min(option1, option2);
  1193. }
  1194. else if (contains(valid, option1))
  1195. {
  1196. return option1;
  1197. }
  1198. else if (contains(valid, option2))
  1199. {
  1200. return option2;
  1201. }
  1202. else
  1203. {
  1204. return valid[0];
  1205. }
  1206. }
  1207. else
  1208. {
  1209. // we only have one option to check
  1210. if (contains(valid, option1))
  1211. {
  1212. return option1;
  1213. }
  1214. else
  1215. {
  1216. return valid[0];
  1217. }
  1218. }
  1219. }
  1220. /**
  1221. * Moves everything up so that the specified shift or latch character can be inserted.
  1222. *
  1223. * @param position the position beyond which everything needs to be shifted
  1224. * @param c the latch or shift character to insert at the specified position, after everything has been shifted
  1225. */
  1226. void insert(int position, int c)
  1227. {
  1228. for (int i = 143; i > position; i--)
  1229. {
  1230. set[i] = set[i - 1];
  1231. character[i] = character[i - 1];
  1232. }
  1233. character[position] = c;
  1234. }
  1235. /**
  1236. * Returns the error correction codewords for the specified data codewords.
  1237. *
  1238. * @param codewords the codewords that we need error correction codewords for
  1239. * @param ecclen the number of error correction codewords needed
  1240. * @return the error correction codewords for the specified data codewords
  1241. */
  1242. static int[] getErrorCorrection(int[] codewords, int ecclen)
  1243. {
  1244. ReedSolomon rs = new ReedSolomon();
  1245. rs.init_gf(0x43);
  1246. rs.init_code(ecclen, 1);
  1247. rs.encode(codewords.Length, codewords);
  1248. int[] results = new int[ecclen];
  1249. for (int i = 0; i < ecclen; i++)
  1250. {
  1251. results[i] = rs.getResult(results.Length - 1 - i);
  1252. }
  1253. return results;
  1254. }
  1255. /** {@inheritDoc} */
  1256. //@Override
  1257. protected void plotSymbol()
  1258. {
  1259. // hexagons
  1260. for (int row = 0; row < 33; row++)
  1261. {
  1262. for (int col = 0; col < 30; col++)
  1263. {
  1264. if (grid[row, col])
  1265. {
  1266. double x = (2.46 * col) + 1.23;
  1267. if ((row & 1) != 0)
  1268. {
  1269. x += 1.23;
  1270. }
  1271. double y = (2.135 * row) + 1.43;
  1272. hexagons.Add(new Hexagon(x, y));
  1273. }
  1274. }
  1275. }
  1276. // circles
  1277. //double[] radii = { 10.85, 8.97, 7.10, 5.22, 3.31, 1.43 };
  1278. double[] radii = { 9.91, 6.16, 2.37 };
  1279. for (int i = 0; i < radii.Length; i++)
  1280. {
  1281. target.Add(new Ellipse(
  1282. 35.76 - radii[i],
  1283. 35.60 - radii[i],
  1284. 35.76 + radii[i],
  1285. 35.60 + radii[i]));
  1286. }
  1287. }
  1288. /** {@inheritDoc} */
  1289. //@Override
  1290. protected int[] getCodewords()
  1291. {
  1292. return codewords;
  1293. }
  1294. //========================================================================
  1295. int[] insert(int[] original, int index, int[] inserted)
  1296. {
  1297. int[] modified = new int[original.Length + inserted.Length];
  1298. Array.Copy(original, 0, modified, 0, index);
  1299. Array.Copy(inserted, 0, modified, index, inserted.Length);
  1300. Array.Copy(original, index, modified, index + inserted.Length, modified.Length - index - inserted.Length);
  1301. return modified;
  1302. }
  1303. bool contains(int[] values, int value)
  1304. {
  1305. for (int i = 0; i < values.Length; i++)
  1306. {
  1307. if (values[i] == value)
  1308. {
  1309. return true;
  1310. }
  1311. }
  1312. return false;
  1313. }
  1314. }
  1315. }