BarcodeGS1.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. using FastReport.Utils;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. namespace FastReport.Barcode
  8. {
  9. /// <summary>
  10. /// Base methods for GS1 DataBar barcodes.
  11. /// </summary>
  12. public class BarcodeGS1Base : LinearBarcodeBase
  13. {
  14. protected List<string> EncodedData { get; set; }
  15. /// <summary>
  16. /// Routine to generate widths for GS1 elements for a given value.
  17. /// </summary>
  18. /// <param name="val">Required value.</param>
  19. /// <param name="n">Number of modules.</param>
  20. /// <param name="elements">Elements in a set (GS1 omni based and Expanded = 4; GS1 Limited = 7).</param>
  21. /// <param name="maxWidth">Maximum module width of an element.</param>
  22. /// <param name="noNarrow">False will skip patterns without a one module wide element.</param>
  23. /// <returns>Element widths</returns>
  24. protected List<int> GetGS1Widths(int val, int n, int elements, int maxWidth, int noNarrow)
  25. {
  26. int elmWidth;
  27. int subVal, lessVal;
  28. int narrowMask = 0;
  29. List<int> widths = new List<int>();
  30. for (int bar = 0; bar < elements - 1; bar++)
  31. {
  32. for (elmWidth = 1, narrowMask |= (1 << bar); ; elmWidth++, narrowMask &= ~(1 << bar))
  33. {
  34. // Get all combinations
  35. subVal = Combins(n - elmWidth - 1, elements - bar - 2);
  36. //Less combinations with no single-module element
  37. if ((noNarrow == 0) && (narrowMask == 0) &&
  38. (n - elmWidth - (elements - bar - 1) >= elements - bar - 1))
  39. {
  40. subVal -= Combins(n - elmWidth - (elements - bar), elements - bar - 2);
  41. }
  42. // Less combinations with elements > maxVal
  43. if (elements - bar - 1 > 1)
  44. {
  45. lessVal = 0;
  46. for (int mxwElement = n - elmWidth - (elements - bar - 2); mxwElement > maxWidth; mxwElement--)
  47. {
  48. lessVal += Combins(n - elmWidth - mxwElement - 1, elements - bar - 3);
  49. }
  50. subVal -= lessVal * (elements - 1 - bar);
  51. }
  52. else if (n - elmWidth > maxWidth)
  53. {
  54. subVal--;
  55. }
  56. val -= subVal;
  57. if (val < 0)
  58. break;
  59. }
  60. val += subVal;
  61. n -= elmWidth;
  62. widths.Add(elmWidth);
  63. }
  64. widths.Add(n);
  65. return widths;
  66. }
  67. /// <summary>
  68. ///
  69. /// </summary>
  70. /// <param name="n"></param>
  71. /// <param name="r"></param>
  72. /// <returns>Returns the number of Combinations of r selected from n.</returns>
  73. private int Combins(int n, int r)
  74. {
  75. int i, j;
  76. int maxDenom, minDenom;
  77. int val;
  78. if (n - r > r)
  79. {
  80. minDenom =
  81. r; maxDenom
  82. = n - r;
  83. }
  84. else
  85. {
  86. minDenom = n - r;
  87. maxDenom = r;
  88. }
  89. val = 1;
  90. j = 1;
  91. for (i = n; i > maxDenom; i--)
  92. {
  93. val *= i;
  94. if (j <= minDenom)
  95. {
  96. val /= j;
  97. j++;
  98. }
  99. }
  100. for (; j <= minDenom; j++)
  101. {
  102. val /= j;
  103. }
  104. return (val);
  105. }
  106. /// <summary>
  107. /// Drawing lines of strokes
  108. /// </summary>
  109. /// <param name="data">Encoded data in width strokes; For separate line, these are colored strokes, any value that is not equal to zero is black.</param>
  110. /// <param name="g"></param>
  111. /// <param name="zoom">Scale size.</param>
  112. /// <param name="rect">Use left of rectangle for to set start position x, top for top pos y, bottom for bottom pos y of strokes.</param>
  113. /// <param name="reversColor">Flag for reversing color by default first strokes white, disabled for separate line. </param>
  114. /// <param name="separatorLine">Flag separete line </param>
  115. protected void DrawLineBars(string data, IGraphics g, float zoom, RectangleF rect, bool reversColor, bool separatorLine = false)
  116. {
  117. using (Pen pen = new Pen(Color))
  118. {
  119. float currentWidth = rect.Left;
  120. for (int x = 0; x < data.Length; x++)
  121. {
  122. float heightStart = rect.Top;
  123. float heightEnd = rect.Bottom;
  124. float width = WideBarRatio;
  125. if (!separatorLine)
  126. width = (data[x] - '0') * WideBarRatio;
  127. width *= zoom;
  128. heightStart *= zoom;
  129. heightEnd *= zoom;
  130. pen.Width = width;
  131. if (reversColor)
  132. pen.Color = Color.Black;
  133. else
  134. pen.Color = Color.Transparent;
  135. if (separatorLine)
  136. {
  137. if (data[x] != '0')
  138. pen.Color = Color.Black;
  139. }
  140. else
  141. {
  142. if ((x % 2 != 0 && !reversColor))
  143. pen.Color = Color.Black;
  144. if ((x % 2 != 0 && reversColor))
  145. pen.Color = Color.Transparent;
  146. }
  147. g.DrawLine(pen,
  148. currentWidth + width / 2,
  149. barArea.Top * zoom + heightStart,
  150. currentWidth + width / 2,
  151. barArea.Top * zoom + heightEnd);
  152. currentWidth += width;
  153. }
  154. }
  155. }
  156. /// <inheritdoc />
  157. public override string GetDefaultValue()
  158. {
  159. return "(01)0000123456789";
  160. }
  161. }
  162. /// <summary>
  163. /// Generates the GS1 DataBar Omnidirectional barcode.
  164. /// </summary>
  165. public class BarcodeGS1Omnidirectional : BarcodeGS1Base
  166. {
  167. /// <summary>
  168. /// Get value for encoding.
  169. /// </summary>
  170. /// <param name="data">Data</param>
  171. /// <returns></returns>
  172. protected long GetValue(string data)
  173. {
  174. long result;
  175. string prefix = "";
  176. int startPrefix = data.IndexOf('(');
  177. int endPrefix = data.IndexOf(')');
  178. if (startPrefix >= 0 && endPrefix > 0)
  179. {
  180. prefix = data.Substring(startPrefix, endPrefix + 1);
  181. data = data.Replace(prefix, "");
  182. }
  183. if(data.Length > 13)
  184. data = data.Remove(13, 1);
  185. if (!long.TryParse(data, out result) || data.Length != 13 || result < 0)
  186. throw new FormatException(Res.Get("Messages,InvalidBarcode2"));
  187. if (prefix == "")
  188. prefix = "(01)";
  189. this.text = prefix + CheckSumModulo10(data);
  190. return result + 10000000000000;
  191. }
  192. private int[] ChecksumWeight =
  193. {
  194. 1, 3, 9, 27, 2, 6, 18, 54,
  195. 4, 12, 36, 29, 8, 24, 72, 58,
  196. 16, 48, 65, 37, 32, 17, 51, 74,
  197. 64, 34, 23, 69, 49, 68, 46, 59
  198. };
  199. private int[] FinderPattern =
  200. {
  201. 3, 8, 2, 1, 1,
  202. 3, 5, 5, 1, 1,
  203. 3, 3, 7, 1, 1,
  204. 3, 1, 9, 1, 1,
  205. 2, 7, 4, 1, 1,
  206. 2, 5, 6, 1, 1,
  207. 2, 3, 8, 1, 1,
  208. 1, 5, 7, 1, 1,
  209. 1, 3, 9, 1, 1
  210. };
  211. private int[] ModulesOdd = { 12, 10, 8, 6, 4, 5, 7, 9, 11 };
  212. private int[] ModulesEven = { 4, 6, 8, 10, 12, 10, 8, 6, 4 };
  213. private int[] WidthsOdd = { 8, 6, 4, 3, 1, 2, 4, 6, 8 };
  214. private int[] WidthsEven = { 1, 3, 5, 6, 8, 7, 5, 3, 1 };
  215. private int[] GSums = { 0, 161, 961, 2015, 2715, 0, 336, 1036, 1516 };
  216. private int[] TList = { 1, 10, 34, 70, 126, 4, 20, 48, 81 };
  217. internal override string GetPattern()
  218. {
  219. EncodedData = new List<string>();
  220. int[] dataGroup = new int[4];
  221. int[] v_odd = new int[4];
  222. int[] v_even = new int[4];
  223. long value = GetValue(text);
  224. long left = value / 4537077;
  225. long right = value % 4537077;
  226. int data1 = (int)(left / 1597);
  227. int data2 = (int)(left % 1597);
  228. int data3 = (int)(right / 1597);
  229. int data4 = (int)(right % 1597);
  230. if ((data1 >= 0) && (data1 <= 160)) { dataGroup[0] = 0; }
  231. if ((data1 >= 161) && (data1 <= 960)) { dataGroup[0] = 1; }
  232. if ((data1 >= 961) && (data1 <= 2014)) { dataGroup[0] = 2; }
  233. if ((data1 >= 2015) && (data1 <= 2714)) { dataGroup[0] = 3; }
  234. if ((data1 >= 2715) && (data1 <= 2840)) { dataGroup[0] = 4; }
  235. if ((data2 >= 0) && (data2 <= 335)) { dataGroup[1] = 5; }
  236. if ((data2 >= 336) && (data2 <= 1035)) { dataGroup[1] = 6; }
  237. if ((data2 >= 1036) && (data2 <= 1515)) { dataGroup[1] = 7; }
  238. if ((data2 >= 1516) && (data2 <= 1596)) { dataGroup[1] = 8; }
  239. if ((data4 >= 0) && (data4 <= 335)) { dataGroup[3] = 5; }
  240. if ((data4 >= 336) && (data4 <= 1035)) { dataGroup[3] = 6; }
  241. if ((data4 >= 1036) && (data4 <= 1515)) { dataGroup[3] = 7; }
  242. if ((data4 >= 1516) && (data4 <= 1596)) { dataGroup[3] = 8; }
  243. if ((data3 >= 0) && (data3 <= 160)) { dataGroup[2] = 0; }
  244. if ((data3 >= 161) && (data3 <= 960)) { dataGroup[2] = 1; }
  245. if ((data3 >= 961) && (data3 <= 2014)) { dataGroup[2] = 2; }
  246. if ((data3 >= 2015) && (data3 <= 2714)) { dataGroup[2] = 3; }
  247. if ((data3 >= 2715) && (data3 <= 2840)) { dataGroup[2] = 4; }
  248. v_odd[0] = (data1 - GSums[dataGroup[0]]) / TList[dataGroup[0]];
  249. v_even[0] = (data1 - GSums[dataGroup[0]]) % TList[dataGroup[0]];
  250. v_odd[1] = (data2 - GSums[dataGroup[1]]) % TList[dataGroup[1]];
  251. v_even[1] = (data2 - GSums[dataGroup[1]]) / TList[dataGroup[1]];
  252. v_odd[3] = (data4 - GSums[dataGroup[3]]) % TList[dataGroup[3]];
  253. v_even[3] = (data4 - GSums[dataGroup[3]]) / TList[dataGroup[3]];
  254. v_odd[2] = (data3 - GSums[dataGroup[2]]) / TList[dataGroup[2]];
  255. v_even[2] = (data3 - GSums[dataGroup[2]]) % TList[dataGroup[2]];
  256. int[,] data_widths = new int[8, 4];
  257. /* Use GS1 subset width algorithm */
  258. for (int i = 0; i < 4; i++)
  259. {
  260. if ((i == 0) || (i == 2))
  261. {
  262. List<int> widths;
  263. widths = GetGS1Widths(v_odd[i], ModulesOdd[dataGroup[i]], 4, WidthsOdd[dataGroup[i]], 1);
  264. data_widths[0, i] = widths[0];
  265. data_widths[2, i] = widths[1];
  266. data_widths[4, i] = widths[2];
  267. data_widths[6, i] = widths[3];
  268. widths = GetGS1Widths(v_even[i], ModulesEven[dataGroup[i]], 4, WidthsEven[dataGroup[i]], 0);
  269. data_widths[1, i] = widths[0];
  270. data_widths[3, i] = widths[1];
  271. data_widths[5, i] = widths[2];
  272. data_widths[7, i] = widths[3];
  273. }
  274. else
  275. {
  276. List<int> widths;
  277. widths = GetGS1Widths(v_odd[i], ModulesOdd[dataGroup[i]], 4, WidthsOdd[dataGroup[i]], 0);
  278. data_widths[0, i] = widths[0];
  279. data_widths[2, i] = widths[1];
  280. data_widths[4, i] = widths[2];
  281. data_widths[6, i] = widths[3];
  282. widths = GetGS1Widths(v_even[i], ModulesEven[dataGroup[i]], 4, WidthsEven[dataGroup[i]], 1);
  283. data_widths[1, i] = widths[0];
  284. data_widths[3, i] = widths[1];
  285. data_widths[5, i] = widths[2];
  286. data_widths[7, i] = widths[3];
  287. }
  288. }
  289. // Calculate the checksum
  290. int checksum = 0;
  291. for (int i = 0; i < 8; i++)
  292. {
  293. checksum += ChecksumWeight[i] * data_widths[i, 0];
  294. checksum += ChecksumWeight[i + 8] * data_widths[i, 1];
  295. checksum += ChecksumWeight[i + 16] * data_widths[i, 2];
  296. checksum += ChecksumWeight[i + 24] * data_widths[i, 3];
  297. }
  298. checksum %= 79;
  299. // Calculate the two check characters
  300. if (checksum >= 8) { checksum++; }
  301. if (checksum >= 72) { checksum++; }
  302. int c_left = checksum / 9;
  303. int c_right = checksum % 9;
  304. int[] barWeights = new int[46];
  305. // Put element widths together
  306. barWeights[0] = 1;
  307. barWeights[1] = 1;
  308. barWeights[44] = 1;
  309. barWeights[45] = 1;
  310. for (int i = 0; i < 8; i++)
  311. {
  312. barWeights[i + 2] = data_widths[i, 0];
  313. barWeights[i + 15] = data_widths[7 - i, 1];
  314. barWeights[i + 23] = data_widths[i, 3];
  315. barWeights[i + 36] = data_widths[7 - i, 2];
  316. }
  317. for (int i = 0; i < 5; i++)
  318. {
  319. barWeights[i + 10] = FinderPattern[i + (5 * c_left)];
  320. barWeights[i + 31] = FinderPattern[(4 - i) + (5 * c_right)];
  321. }
  322. EncodedData.Add("");
  323. foreach (int val in barWeights)
  324. EncodedData[0] += val;
  325. return EncodedData[0];
  326. }
  327. internal override float GetWidth(string code)
  328. {
  329. float width = 0;
  330. for (int x = 0; x < EncodedData[0].Length; x++)
  331. width += EncodedData[0][x] - '0';
  332. return width * WideBarRatio;
  333. }
  334. /// <inheritdoc />
  335. internal override void DoLines(string data, IGraphics g, float zoom)
  336. {
  337. DrawLineBars(EncodedData[0], g, zoom, new RectangleF(0, 0, 0, barArea.Height), false);
  338. }
  339. }
  340. /// <summary>
  341. /// Generates the GS1 DataBar Stacked barcode.
  342. /// </summary>
  343. public class BarcodeGS1Stacked : BarcodeGS1Omnidirectional
  344. {
  345. internal override string GetPattern()
  346. {
  347. string data = base.GetPattern();
  348. EncodedData = new List<string>();
  349. EncodedData.Add(data.Substring(0, 23) + "11");
  350. EncodedData.Add("0000"); // left padding of separate line
  351. EncodedData.Add("11" + data.Substring(23, 23));
  352. // convert line of strokes to black and white modules
  353. string[] bars = new string[2];
  354. for(int i = 0; i < EncodedData[0].Length; i++)
  355. {
  356. if(i % 2 == 0)
  357. {
  358. for (int x = 0; x < EncodedData[0][i] - '0'; x++)
  359. bars[0] += "0";
  360. for (int x = 0; x < EncodedData[2][i] - '0'; x++)
  361. bars[1] += "1";
  362. }
  363. else
  364. {
  365. for (int x = 0; x < EncodedData[0][i] - '0'; x++)
  366. bars[0] += "1";
  367. for (int x = 0; x < EncodedData[2][i] - '0'; x++)
  368. bars[1] += "0";
  369. }
  370. }
  371. // Encode separate line (applying encoding rules from sections 5.3.2.1)
  372. for (int i = 4; i < bars[0].Length - 4; i++)
  373. {
  374. if (bars[0][i] == '1' && bars[1][i] == '1')
  375. EncodedData[1] += "0";
  376. else if(bars[0][i] == '0' && bars[1][i] == '0')
  377. EncodedData[1] += "1";
  378. else if(bars[0][i] != bars[1][i])
  379. {
  380. EncodedData[1] += EncodedData[1][EncodedData[1].Length - 1] == '0' ? "1" : "0";
  381. }
  382. }
  383. return "";
  384. }
  385. /// <inheritdoc />
  386. internal override void DoLines(string data, IGraphics g, float zoom)
  387. {
  388. DrawLineBars(EncodedData[0], g, zoom, new RectangleF(0, 0, 0, barArea.Height * 5 / 13), false);
  389. DrawLineBars(EncodedData[1], g, zoom, new RectangleF(0, barArea.Height * 5 / 13, 0, barArea.Height * 1 / 13), false, true);
  390. DrawLineBars(EncodedData[2], g, zoom, new RectangleF(0, barArea.Height * 6 / 13, 0, barArea.Height * 7 / 13), true);
  391. }
  392. internal override float GetWidth(string code)
  393. {
  394. float width = 0;
  395. for (int x = 0; x < EncodedData[0].Length; x++)
  396. width += EncodedData[0][x] - '0';
  397. return width * WideBarRatio;
  398. }
  399. }
  400. /// <summary>
  401. /// Generates the GS1 DataBar Stacked Omnidirectional barcode.
  402. /// </summary>
  403. public class BarcodeGS1StackedOmnidirectional : BarcodeGS1Omnidirectional
  404. {
  405. internal override string GetPattern()
  406. {
  407. string[] bars = new string[2];
  408. bool nextBarBlack = true;
  409. bool nextBarWhite = true;
  410. string data = base.GetPattern();
  411. EncodedData = new List<string>();
  412. EncodedData.Add(data.Substring(0, 23) + "11");
  413. EncodedData.Add("0000"); // left padding of top separate line
  414. EncodedData.Add("0000010101010101010101010101010101010101010101"); // left padding of middle separate line
  415. EncodedData.Add("0000"); // left padding of bottom separate line
  416. EncodedData.Add("11" + data.Substring(23, 23));
  417. // Encode separate lines (applying encoding rules from sections 5.3.2.2)
  418. for (int i = 0; i < EncodedData[0].Length; i++)
  419. {
  420. if (i % 2 == 0)
  421. {
  422. for (int x = 0; x < EncodedData[0][i] - '0'; x++)
  423. {
  424. if (i > 5 && i < 9)
  425. {
  426. if (nextBarBlack)
  427. {
  428. bars[0] += "1";
  429. nextBarBlack = false;
  430. }
  431. else
  432. {
  433. bars[0] += "0";
  434. nextBarBlack = true;
  435. }
  436. }
  437. else
  438. bars[0] += "1";
  439. }
  440. for (int x = 0; x < EncodedData[4][i] - '0'; x++)
  441. {
  442. if (i > 15 && i < 19)
  443. {
  444. if (nextBarWhite)
  445. {
  446. bars[1] += "0";
  447. nextBarWhite = false;
  448. }
  449. else
  450. {
  451. bars[1] += "1";
  452. nextBarWhite = true;
  453. }
  454. }
  455. else
  456. bars[1] += "0";
  457. }
  458. }
  459. else
  460. {
  461. for (int x = 0; x < EncodedData[0][i] - '0'; x++)
  462. {
  463. bars[0] += "0";
  464. }
  465. for (int x = 0; x < EncodedData[4][i] - '0'; x++)
  466. {
  467. bars[1] += "1";
  468. }
  469. }
  470. }
  471. EncodedData[1] += bars[0].Remove(0, 4).Remove(42, 4);
  472. EncodedData[3] += bars[1].Remove(0, 4).Remove(42, 4);
  473. return "";
  474. }
  475. internal override float GetWidth(string code)
  476. {
  477. float width = 0;
  478. for (int x = 0; x < EncodedData[0].Length; x++)
  479. width += EncodedData[0][x] - '0';
  480. return width * WideBarRatio;
  481. }
  482. /// <inheritdoc />
  483. internal override void DoLines(string data, IGraphics g, float zoom)
  484. {
  485. DrawLineBars(EncodedData[0], g, zoom, new RectangleF(0, 0, 0, barArea.Height * 33 / 69), false);
  486. DrawLineBars(EncodedData[1], g, zoom, new RectangleF(0, barArea.Height * 33 / 69 , 0, barArea.Height * 1 / 69), false, true);
  487. DrawLineBars(EncodedData[2], g, zoom, new RectangleF(0, barArea.Height * 34 / 69 , 0, barArea.Height * 1 / 69), false, true);
  488. DrawLineBars(EncodedData[3], g, zoom, new RectangleF(0, barArea.Height * 35 / 69 , 0, barArea.Height * 1 / 69), false, true);
  489. DrawLineBars(EncodedData[4], g, zoom, new RectangleF(0, barArea.Height * 36 / 69 , 0, barArea.Height * 33 / 69), true);
  490. }
  491. }
  492. /// <summary>
  493. /// Generates the GS1 DataBar Limited barcode.
  494. /// </summary>
  495. public class BarcodeGS1Limited : BarcodeGS1Base
  496. {
  497. /// <summary>
  498. /// Get value for encoding.
  499. /// </summary>
  500. /// <param name="data">Data</param>
  501. /// <returns></returns>
  502. protected long GetValue(string data)
  503. {
  504. long result;
  505. string prefix = "";
  506. int startPrefix = data.IndexOf('(');
  507. int endPrefix = data.IndexOf(')');
  508. if (startPrefix >= 0 && endPrefix > 0)
  509. {
  510. prefix = data.Substring(startPrefix, endPrefix + 1);
  511. data = data.Replace(prefix, "");
  512. }
  513. if (data.Length > 13)
  514. data = data.Remove(13, 1);
  515. if (!long.TryParse(data, out result) || data.Length != 13 || result > 1999999999999 || result < 0)
  516. throw new FormatException(Res.Get("Messages,InvalidBarcode2"));
  517. if (prefix == "")
  518. prefix = "(01)";
  519. this.text = prefix + CheckSumModulo10(data);
  520. return result;
  521. }
  522. int[] ChecksumWeight =
  523. {
  524. 1, 3, 9, 27, 81, 65, 17, 51, 64, 14, 42, 37, 22, 66,
  525. 20, 60, 2, 6, 18, 54, 73, 41, 34, 13, 39, 28, 84, 74
  526. };
  527. int[] FinderPattern =
  528. {
  529. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 1,
  530. 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 1, 1,
  531. 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1,
  532. 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 3, 2, 1, 1,
  533. 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 3, 1, 1, 1,
  534. 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1, 1,
  535. 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 2, 1, 1,
  536. 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 3, 1, 1, 1,
  537. 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 3, 1, 1, 1,
  538. 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 1,
  539. 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1,
  540. 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1,
  541. 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 3, 1, 1, 1,
  542. 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 3, 1, 1, 1,
  543. 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1,
  544. 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1,
  545. 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1,
  546. 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, 1,
  547. 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 1,
  548. 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1,
  549. 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1,
  550. 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 3, 1, 1,
  551. 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1,
  552. 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 1, 1, 1,
  553. 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1,
  554. 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1,
  555. 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 2, 1, 1, 1,
  556. 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 1,
  557. 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1,
  558. 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 1,
  559. 1, 1, 1, 1, 1, 3, 1, 1, 2, 1, 2, 1, 1, 1,
  560. 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1,
  561. 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1,
  562. 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1,
  563. 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1,
  564. 1, 1, 1, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1,
  565. 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1,
  566. 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1,
  567. 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1,
  568. 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1,
  569. 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1,
  570. 1, 3, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1,
  571. 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1,
  572. 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 2, 1, 1,
  573. 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 1, 1,
  574. 1, 1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1,
  575. 1, 2, 1, 1, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1,
  576. 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 3, 1, 1,
  577. 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1,
  578. 1, 1, 1, 1, 1, 1, 2, 1, 1, 3, 2, 1, 1, 1,
  579. 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1,
  580. 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1,
  581. 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1,
  582. 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1,
  583. 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1,
  584. 1, 1, 1, 3, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1,
  585. 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1,
  586. 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1,
  587. 1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1,
  588. 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 3, 1, 1,
  589. 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1,
  590. 1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 2, 1, 1, 1,
  591. 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 1,
  592. 1, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 1, 1,
  593. 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
  594. 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1,
  595. 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1,
  596. 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1,
  597. 1, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1,
  598. 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1,
  599. 1, 3, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1,
  600. 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1,
  601. 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1,
  602. 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1,
  603. 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1,
  604. 1, 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1,
  605. 1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1, 1,
  606. 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1,
  607. 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1,
  608. 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1,
  609. 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1,
  610. 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1,
  611. 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1,
  612. 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1,
  613. 2, 1, 1, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1, 1,
  614. 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1,
  615. 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1,
  616. 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1
  617. };
  618. int[] ModulesOdd = { 17, 13, 9, 15, 11, 19, 7 };
  619. int[] ModulesEven = { 9, 13, 17, 11, 15, 7, 19 };
  620. int[] WidthsOdd = { 6, 5, 3, 5, 4, 8, 1 };
  621. int[] WidthsEven = { 3, 4, 6, 4, 5, 1, 8 };
  622. int[] TEven = { 28, 728, 6454, 203, 2408, 1, 16632 };
  623. internal override string GetPattern()
  624. {
  625. EncodedData = new List<string>();
  626. long value = GetValue(text);
  627. long left = value / 2013571;
  628. long right = value % 2013571;
  629. int leftGroup = 0;
  630. if (left > 183063) { leftGroup = 1; }
  631. if (left > 820063) { leftGroup = 2; }
  632. if (left > 1000775) { leftGroup = 3; }
  633. if (left > 1491020) { leftGroup = 4; }
  634. if (left > 1979844) { leftGroup = 5; }
  635. if (left > 1996938) { leftGroup = 6; }
  636. int rightGroup = 0;
  637. if (right > 183063) { rightGroup = 1; }
  638. if (right > 820063) { rightGroup = 2; }
  639. if (right > 1000775) { rightGroup = 3; }
  640. if (right > 1491020) { rightGroup = 4; }
  641. if (right > 1979844) { rightGroup = 5; }
  642. if (right > 1996938) { rightGroup = 6; }
  643. switch (leftGroup)
  644. {
  645. case 1:
  646. left -= 183064;
  647. break;
  648. case 2:
  649. left -= 820064;
  650. break;
  651. case 3:
  652. left -= 1000776;
  653. break;
  654. case 4:
  655. left -= 1491021;
  656. break;
  657. case 5:
  658. left -= 1979845;
  659. break;
  660. case 6:
  661. left -= 1996939;
  662. break;
  663. }
  664. switch (rightGroup)
  665. {
  666. case 1:
  667. right -= 183064;
  668. break;
  669. case 2:
  670. right -= 820064;
  671. break;
  672. case 3:
  673. right -= 1000776;
  674. break;
  675. case 4:
  676. right -= 1491021;
  677. break;
  678. case 5:
  679. right -= 1979845;
  680. break;
  681. case 6:
  682. right -= 1996939;
  683. break;
  684. }
  685. int leftOdd = (int)(left / TEven[leftGroup]);
  686. int leftEven = (int)(left % TEven[leftGroup]);
  687. int rightOdd = (int)(right / TEven[rightGroup]);
  688. int rightEven = (int)(right % TEven[rightGroup]);
  689. List<int> widths;
  690. int[] leftWidths = new int[14];
  691. int[] rightWidths = new int[14];
  692. widths = GetGS1Widths(leftOdd, ModulesOdd[leftGroup], 7, WidthsOdd[leftGroup], 1);
  693. leftWidths[0] = widths[0];
  694. leftWidths[2] = widths[1];
  695. leftWidths[4] = widths[2];
  696. leftWidths[6] = widths[3];
  697. leftWidths[8] = widths[4];
  698. leftWidths[10] = widths[5];
  699. leftWidths[12] = widths[6];
  700. widths = GetGS1Widths(leftEven, ModulesEven[leftGroup], 7, WidthsEven[leftGroup], 0);
  701. leftWidths[1] = widths[0];
  702. leftWidths[3] = widths[1];
  703. leftWidths[5] = widths[2];
  704. leftWidths[7] = widths[3];
  705. leftWidths[9] = widths[4];
  706. leftWidths[11] = widths[5];
  707. leftWidths[13] = widths[6];
  708. widths = GetGS1Widths(rightOdd, ModulesOdd[rightGroup], 7, WidthsOdd[rightGroup], 1);
  709. rightWidths[0] = widths[0];
  710. rightWidths[2] = widths[1];
  711. rightWidths[4] = widths[2];
  712. rightWidths[6] = widths[3];
  713. rightWidths[8] = widths[4];
  714. rightWidths[10] = widths[5];
  715. rightWidths[12] = widths[6];
  716. widths = GetGS1Widths(rightEven, ModulesEven[rightGroup], 7, WidthsEven[rightGroup], 0);
  717. rightWidths[1] = widths[0];
  718. rightWidths[3] = widths[1];
  719. rightWidths[5] = widths[2];
  720. rightWidths[7] = widths[3];
  721. rightWidths[9] = widths[4];
  722. rightWidths[11] = widths[5];
  723. rightWidths[13] = widths[6];
  724. int checksum = 0;
  725. /* Calculate the checksum */
  726. for (int i = 0; i < 14; i++)
  727. {
  728. checksum += ChecksumWeight[i] * leftWidths[i];
  729. checksum += ChecksumWeight[i + 14] * rightWidths[i];
  730. }
  731. checksum %= 89;
  732. int[] checkElements = new int[14];
  733. for (int i = 0; i < 14; i++)
  734. {
  735. checkElements[i] = FinderPattern[i + (checksum * 14)];
  736. }
  737. int[] totalWidths = new int[46];
  738. totalWidths[0] = 1;
  739. totalWidths[1] = 1;
  740. totalWidths[44] = 1;
  741. totalWidths[45] = 1;
  742. for (int i = 0; i < 14; i++)
  743. {
  744. totalWidths[i + 2] = leftWidths[i];
  745. totalWidths[i + 16] = checkElements[i];
  746. totalWidths[i + 30] = rightWidths[i];
  747. }
  748. EncodedData.Add("");
  749. foreach (int val in totalWidths)
  750. EncodedData[0] += val;
  751. return EncodedData[0];
  752. }
  753. /// <inheritdoc />
  754. internal override void DoLines(string data, IGraphics g, float zoom)
  755. {
  756. DrawLineBars(EncodedData[0], g, zoom, new RectangleF(0, 0, 0, barArea.Height), false);
  757. }
  758. internal override float GetWidth(string code)
  759. {
  760. float width = 0;
  761. for (int x = 0; x < EncodedData[0].Length; x++)
  762. width += EncodedData[0][x] - '0';
  763. return width * WideBarRatio;
  764. }
  765. }
  766. }