BarcodeDatamatrix.cs 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501
  1. //
  2. // Copyright 2007 by Paulo Soares.
  3. //
  4. // The contents of this file are subject to the Mozilla Public License Version 1.1
  5. // (the "License"); you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at http://www.mozilla.org/MPL/
  7. //
  8. // Software distributed under the License is distributed on an "AS IS" basis,
  9. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  10. // for the specific language governing rights and limitations under the License.
  11. //
  12. // The Original Code is 'iText, a free JAVA-PDF library'.
  13. //
  14. // The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
  15. // the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
  16. // All Rights Reserved.
  17. // Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
  18. // are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
  19. // Modifications: Alexander Tzyganenko
  20. //
  21. using System;
  22. using System.Collections;
  23. using System.Collections.Generic;
  24. using System.Text;
  25. using System.Drawing;
  26. using System.ComponentModel;
  27. namespace FastReport.Barcode
  28. {
  29. /// <summary>
  30. /// Specifies the Datamatrix encoding.
  31. /// </summary>
  32. public enum DatamatrixEncoding
  33. {
  34. /// <summary>
  35. /// Specifies the auto encoding.
  36. /// </summary>
  37. Auto,
  38. /// <summary>
  39. /// Specifies the ASCII encoding.
  40. /// </summary>
  41. Ascii,
  42. /// <summary>
  43. /// Specifies the C40 encoding.
  44. /// </summary>
  45. C40,
  46. /// <summary>
  47. /// Specifies the text encoding.
  48. /// </summary>
  49. Text,
  50. /// <summary>
  51. /// Specifies the binary encoding.
  52. /// </summary>
  53. Base256,
  54. /// <summary>
  55. /// Specifies the X12 encoding.
  56. /// </summary>
  57. X12,
  58. /// <summary>
  59. /// Specifies the Edifact encoding.
  60. /// </summary>
  61. Edifact
  62. }
  63. /// <summary>
  64. /// Specifies the Datamatrix symbol size.
  65. /// </summary>
  66. public enum DatamatrixSymbolSize
  67. {
  68. /// <summary>
  69. /// Specifies the auto size.
  70. /// </summary>
  71. Auto,
  72. /// <summary>
  73. /// Specifies the 10x10 size.
  74. /// </summary>
  75. Size10x10,
  76. /// <summary>
  77. /// Specifies the 12x12 size.
  78. /// </summary>
  79. Size12x12,
  80. /// <summary>
  81. /// Specifies the 8x8 size.
  82. /// </summary>
  83. Size8x18,
  84. /// <summary>
  85. /// Specifies the 14x14 size.
  86. /// </summary>
  87. Size14x14,
  88. /// <summary>
  89. /// Specifies the 8x32 size.
  90. /// </summary>
  91. Size8x32,
  92. /// <summary>
  93. /// Specifies the 16x16 size.
  94. /// </summary>
  95. Size16x16,
  96. /// <summary>
  97. /// Specifies the 12x26 size.
  98. /// </summary>
  99. Size12x26,
  100. /// <summary>
  101. /// Specifies the 18x18 size.
  102. /// </summary>
  103. Size18x18,
  104. /// <summary>
  105. /// Specifies the 20x20 size.
  106. /// </summary>
  107. Size20x20,
  108. /// <summary>
  109. /// Specifies the 12x36 size.
  110. /// </summary>
  111. Size12x36,
  112. /// <summary>
  113. /// Specifies the 22x22 size.
  114. /// </summary>
  115. Size22x22,
  116. /// <summary>
  117. /// Specifies the 16x36 size.
  118. /// </summary>
  119. Size16x36,
  120. /// <summary>
  121. /// Specifies the 24x24 size.
  122. /// </summary>
  123. Size24x24,
  124. /// <summary>
  125. /// Specifies the 26x26 size.
  126. /// </summary>
  127. Size26x26,
  128. /// <summary>
  129. /// Specifies the 16x48 size.
  130. /// </summary>
  131. Size16x48,
  132. /// <summary>
  133. /// Specifies the 32x32 size.
  134. /// </summary>
  135. Size32x32,
  136. /// <summary>
  137. /// Specifies the 36x36 size.
  138. /// </summary>
  139. Size36x36,
  140. /// <summary>
  141. /// Specifies the 40x40 size.
  142. /// </summary>
  143. Size40x40,
  144. /// <summary>
  145. /// Specifies the 44x44 size.
  146. /// </summary>
  147. Size44x44,
  148. /// <summary>
  149. /// Specifies the 48x48 size.
  150. /// </summary>
  151. Size48x48,
  152. /// <summary>
  153. /// Specifies the 52x52 size.
  154. /// </summary>
  155. Size52x52,
  156. /// <summary>
  157. /// Specifies the 64x64 size.
  158. /// </summary>
  159. Size64x64,
  160. /// <summary>
  161. /// Specifies the 72x72 size.
  162. /// </summary>
  163. Size72x72,
  164. /// <summary>
  165. /// Specifies the 80x80 size.
  166. /// </summary>
  167. Size80x80,
  168. /// <summary>
  169. /// Specifies the 88x88 size.
  170. /// </summary>
  171. Size88x88,
  172. /// <summary>
  173. /// Specifies the 96x96 size.
  174. /// </summary>
  175. Size96x96,
  176. /// <summary>
  177. /// Specifies the 104x104 size.
  178. /// </summary>
  179. Size104x104,
  180. /// <summary>
  181. /// Specifies the 120x120 size.
  182. /// </summary>
  183. Size120x120,
  184. /// <summary>
  185. /// Specifies the 132x132 size.
  186. /// </summary>
  187. Size132x132,
  188. /// <summary>
  189. /// Specifies the 144x144 size.
  190. /// </summary>
  191. Size144x144
  192. }
  193. /// <summary>
  194. /// Generates the 2D Data Matrix barcode.
  195. /// </summary>
  196. public sealed class BarcodeDatamatrix : Barcode2DBase
  197. {
  198. #region Fields
  199. private const byte LATCH_B256 = (byte)231;
  200. private const byte LATCH_EDIFACT = (byte)240;
  201. private const byte LATCH_X12 = (byte)238;
  202. private const byte LATCH_TEXT = (byte)239;
  203. private const byte LATCH_C40 = (byte)230;
  204. private const byte UNLATCH = (byte)254;
  205. private const byte UPPER_CASE_SIGN = (byte)235;
  206. private const string SET_X12 = "\r*> 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  207. const string SHIFTED_SET_C40_AND_TEXT = "!\"#$%&'()*+,-./:;<=>?@[\\]^_";
  208. const string BASE_SET_C40 = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  209. const string SHIFTED_SET_C40 = "`abcdefghijklmnopqrstuvwxyz{|}~\u007f";
  210. const string BASE_SET_TEXT = " 0123456789abcdefghijklmnopqrstuvwxyz";
  211. const string SHIFTED_SET_TEXT = "`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\u007f";
  212. private static readonly DmParams[] dmSizes = {
  213. new DmParams(10, 10, 10, 10, 3, 3, 5),
  214. new DmParams(12, 12, 12, 12, 5, 5, 7),
  215. new DmParams(8, 18, 8, 18, 5, 5, 7),
  216. new DmParams(14, 14, 14, 14, 8, 8, 10),
  217. new DmParams(8, 32, 8, 16, 10, 10, 11),
  218. new DmParams(16, 16, 16, 16, 12, 12, 12),
  219. new DmParams(12, 26, 12, 26, 16, 16, 14),
  220. new DmParams(18, 18, 18, 18, 18, 18, 14),
  221. new DmParams(20, 20, 20, 20, 22, 22, 18),
  222. new DmParams(12, 36, 12, 18, 22, 22, 18),
  223. new DmParams(22, 22, 22, 22, 30, 30, 20),
  224. new DmParams(16, 36, 16, 18, 32, 32, 24),
  225. new DmParams(24, 24, 24, 24, 36, 36, 24),
  226. new DmParams(26, 26, 26, 26, 44, 44, 28),
  227. new DmParams(16, 48, 16, 24, 49, 49, 28),
  228. new DmParams(32, 32, 16, 16, 62, 62, 36),
  229. new DmParams(36, 36, 18, 18, 86, 86, 42),
  230. new DmParams(40, 40, 20, 20, 114, 114, 48),
  231. new DmParams(44, 44, 22, 22, 144, 144, 56),
  232. new DmParams(48, 48, 24, 24, 174, 174, 68),
  233. new DmParams(52, 52, 26, 26, 204, 102, 42),
  234. new DmParams(64, 64, 16, 16, 280, 140, 56),
  235. new DmParams(72, 72, 18, 18, 368, 92, 36),
  236. new DmParams(80, 80, 20, 20, 456, 114, 48),
  237. new DmParams(88, 88, 22, 22, 576, 144, 56),
  238. new DmParams(96, 96, 24, 24, 696, 174, 68),
  239. new DmParams(104, 104, 26, 26, 816, 136, 56),
  240. new DmParams(120, 120, 20, 20, 1050, 175, 68),
  241. new DmParams(132, 132, 22, 22, 1304, 163, 62),
  242. new DmParams(144, 144, 24, 24, 1558, 156, 62)};
  243. private short[] place;
  244. private byte[] image;
  245. private int height;
  246. private int width;
  247. private DatamatrixSymbolSize symbolSize;
  248. private DatamatrixEncoding encoding;
  249. private int codePage;
  250. private int pixelSize;
  251. private bool autoEncode;
  252. #endregion
  253. #region Properties
  254. /// <summary>
  255. /// Gets or sets the symbol size.
  256. /// </summary>
  257. [DefaultValue(DatamatrixSymbolSize.Auto)]
  258. public DatamatrixSymbolSize SymbolSize
  259. {
  260. get { return symbolSize; }
  261. set { symbolSize = value; }
  262. }
  263. /// <summary>
  264. /// Gets or sets the encoding mode.
  265. /// </summary>
  266. [DefaultValue(DatamatrixEncoding.Auto)]
  267. public DatamatrixEncoding Encoding
  268. {
  269. get { return encoding; }
  270. set { encoding = value; }
  271. }
  272. /// <summary>
  273. /// Gets or sets the code page used for text conversion.
  274. /// </summary>
  275. /// <remarks>
  276. /// Use this property to encode non-ASCII characters. For example, set this
  277. /// property to <b>1251</b> to use Window CP1251.
  278. /// </remarks>
  279. [DefaultValue(1252)]
  280. public int CodePage
  281. {
  282. get { return codePage; }
  283. set { codePage = value; }
  284. }
  285. /// <summary>
  286. /// Gets or sets the size of the pixel.
  287. /// </summary>
  288. [DefaultValue(3)]
  289. public int PixelSize
  290. {
  291. get { return pixelSize; }
  292. set { pixelSize = value; }
  293. }
  294. /// <summary>
  295. /// Gets or sets the value AutoEncode.
  296. /// </summary>
  297. [DefaultValue(true)]
  298. public bool AutoEncode
  299. {
  300. get { return autoEncode; }
  301. set { autoEncode = value; }
  302. }
  303. #endregion
  304. #region Private Methods
  305. private void SetBit(int x, int y, int xByte)
  306. {
  307. image[y * xByte + x / 8] |= (byte)(128 >> (x & 7));
  308. }
  309. private void Draw(byte[] data, int dataSize, DmParams dm)
  310. {
  311. int i, j, p, x, y, xs, ys, z;
  312. int xByte = (dm.width + 7) / 8;
  313. for (int k = 0; k < image.Length; ++k)
  314. image[k] = 0;
  315. //alignment patterns
  316. //dotted horizontal line
  317. for (i = 0; i < dm.height; i += dm.heightSection)
  318. {
  319. for (j = 0; j < dm.width; j += 2)
  320. {
  321. SetBit(j, i, xByte);
  322. }
  323. }
  324. //solid horizontal line
  325. for (i = dm.heightSection - 1; i < dm.height; i += dm.heightSection)
  326. {
  327. for (j = 0; j < dm.width; ++j)
  328. {
  329. SetBit(j, i, xByte);
  330. }
  331. }
  332. //solid vertical line
  333. for (i = 0; i < dm.width; i += dm.widthSection)
  334. {
  335. for (j = 0; j < dm.height; ++j)
  336. {
  337. SetBit(i, j, xByte);
  338. }
  339. }
  340. //dotted vertical line
  341. for (i = dm.widthSection - 1; i < dm.width; i += dm.widthSection)
  342. {
  343. for (j = 1; j < dm.height; j += 2)
  344. {
  345. SetBit(i, j, xByte);
  346. }
  347. }
  348. p = 0;
  349. for (ys = 0; ys < dm.height; ys += dm.heightSection)
  350. {
  351. for (y = 1; y < dm.heightSection - 1; ++y)
  352. {
  353. for (xs = 0; xs < dm.width; xs += dm.widthSection)
  354. {
  355. for (x = 1; x < dm.widthSection - 1; ++x)
  356. {
  357. z = place[p++];
  358. if (z == 1 || (z > 1 && ((data[z / 8 - 1] & 0xff) & (128 >> (z % 8))) != 0))
  359. SetBit(x + xs, y + ys, xByte);
  360. }
  361. }
  362. }
  363. }
  364. }
  365. private static void MakePadding(byte[] data, int position, int count)
  366. {
  367. //already in ascii mode
  368. if (count <= 0)
  369. return;
  370. data[position++] = (byte)129;
  371. while (--count > 0)
  372. {
  373. int t = 129 + (((position + 1) * 149) % 253) + 1;
  374. if (t > 254)
  375. t -= 254;
  376. data[position++] = (byte)t;
  377. }
  378. }
  379. private static bool IsDigit(int c)
  380. {
  381. return c >= '0' && c <= '9';
  382. }
  383. private static int AsciiEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength, int symbolIndex)
  384. {
  385. int c;
  386. int textIndex = textOffset;
  387. int dataIndex = dataOffset;
  388. textLength += textOffset;
  389. dataLength += dataOffset;
  390. while (textIndex < textLength)
  391. {
  392. c = text[textIndex++] & 0xff;
  393. if (IsDigit(c) && symbolIndex < 0 && textIndex < textLength && IsDigit(text[textIndex] & 0xff))
  394. {
  395. data[dataIndex++] = (byte)((c - '0') * 10 + (text[textIndex++] & 0xff) - '0' + 130);
  396. }
  397. else if (c == 232)
  398. {
  399. data[dataIndex++] = (byte)232;
  400. }
  401. else if (c > 127)
  402. {
  403. if (dataIndex + 1 >= dataLength)
  404. return -1;
  405. data[dataIndex++] = UPPER_CASE_SIGN;
  406. data[dataIndex++] = (byte)(c - 128 + 1);
  407. }
  408. else
  409. {
  410. data[dataIndex++] = (byte)(c + 1);
  411. }
  412. }
  413. return dataIndex - dataOffset;
  414. }
  415. private static int B256Encodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength, int prevEnc, int origDataOffset)
  416. {
  417. int minRequiredDataIncrement;
  418. int simulatedDataOffset = dataOffset;
  419. if (textLength == 0)
  420. return 0;
  421. if (prevEnc != (int)DatamatrixEncoding.Base256)
  422. {
  423. if (textLength < 250 && textLength + 2 > dataLength)
  424. return -1;
  425. if (textLength >= 250 && textLength + 3 > dataLength)
  426. return -1;
  427. data[dataOffset] = LATCH_B256;
  428. }
  429. if (textLength < 250)
  430. {
  431. data[simulatedDataOffset + 1] = (byte)textLength;
  432. minRequiredDataIncrement = prevEnc != (int)DatamatrixEncoding.Base256 ? 2 : 0;
  433. }
  434. else if (textLength == 250 && prevEnc == (int)DatamatrixEncoding.Base256)
  435. {
  436. data[simulatedDataOffset + 1] = (byte)(textLength / 250 + 249);
  437. for (int i = dataOffset + 1; i > simulatedDataOffset + 2; i--)
  438. data[i] = data[i - 1];
  439. data[simulatedDataOffset + 2] = (byte)(textLength % 250);
  440. minRequiredDataIncrement = 1;
  441. }
  442. else
  443. {
  444. data[simulatedDataOffset + 1] = (byte)(textLength / 250 + 249);
  445. data[simulatedDataOffset + 2] = (byte)(textLength % 250);
  446. minRequiredDataIncrement = prevEnc != (int)DatamatrixEncoding.Base256 ? 3 : 0;
  447. }
  448. if (prevEnc == (int)DatamatrixEncoding.Base256)
  449. textLength = 1;
  450. Array.Copy(text, textOffset, data, minRequiredDataIncrement + dataOffset, textLength);
  451. for (int j = prevEnc != (int)DatamatrixEncoding.Base256 ? dataOffset + 1 : dataOffset; j < minRequiredDataIncrement + textLength + dataOffset; ++j)
  452. {
  453. RandomizationAlgorithm255(data, j);
  454. }
  455. if (prevEnc == (int)DatamatrixEncoding.Base256)
  456. RandomizationAlgorithm255(data, simulatedDataOffset + 1);
  457. return textLength + dataOffset + minRequiredDataIncrement - origDataOffset;
  458. }
  459. private static void RandomizationAlgorithm255(byte[] data, int j)
  460. {
  461. int c = data[j] & 0xff;
  462. int prn = 149 * (j + 1) % 255 + 1;
  463. int tv = c + prn;
  464. if (tv > 255)
  465. tv -= 256;
  466. data[j] = (byte)tv;
  467. }
  468. private static int X12Encodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength, int symbolIndex, int origDataOffset)
  469. {
  470. if (textLength == 0)
  471. return 0;
  472. int n;
  473. bool latch = true;
  474. byte c;
  475. int textIndex = 0;
  476. int dataIndex = 0;
  477. byte[] x = new byte[textLength];
  478. int count = 0;
  479. for (; textIndex < textLength; ++textIndex)
  480. {
  481. int i = SET_X12.IndexOf((char)text[textIndex + textOffset]);
  482. if (i >= 0)
  483. {
  484. x[textIndex] = (byte)i;
  485. ++count;
  486. }
  487. else
  488. {
  489. x[textIndex] = 100;
  490. if (count >= 6)
  491. count -= count / 3 * 3;
  492. for (int k = 0; k < count; ++k)
  493. x[textIndex - k - 1] = 100;
  494. count = 0;
  495. }
  496. }
  497. if (count >= 6)
  498. count -= count / 3 * 3;
  499. for (int k = 0; k < count; ++k)
  500. x[textIndex - k - 1] = 100;
  501. textIndex = 0;
  502. c = 0;
  503. for (; textIndex < textLength; ++textIndex)
  504. {
  505. c = x[textIndex];
  506. if (dataIndex > dataLength)
  507. break;
  508. if (c < 40)
  509. {
  510. if (textIndex == 0 && latch || textIndex > 0 && x[textIndex - 1] > 40)
  511. data[dataOffset + dataIndex++] = LATCH_X12;
  512. if (dataIndex + 2 > dataLength)
  513. break;
  514. n = 1600 * x[textIndex] + 40 * x[textIndex + 1] + x[textIndex + 2] + 1;
  515. data[dataOffset + dataIndex++] = (byte)(n / 256);
  516. data[dataOffset + dataIndex++] = (byte)n;
  517. textIndex += 2;
  518. }
  519. else
  520. {
  521. if (symbolIndex <= 0)
  522. {
  523. if (textIndex > 0 && x[textIndex - 1] < 40)
  524. data[dataOffset + dataIndex++] = UNLATCH;
  525. }
  526. int i = AsciiEncodation(text, textOffset + textIndex, 1, data, dataOffset + dataIndex, dataLength, -1);
  527. if (i < 0)
  528. return -1;
  529. if (data[dataOffset + dataIndex] == UPPER_CASE_SIGN)
  530. dataIndex++;
  531. dataIndex++;
  532. }
  533. }
  534. c = 100;
  535. if (textLength > 0)
  536. c = x[textLength - 1];
  537. if (textIndex != textLength)
  538. return -1;
  539. if (c < 40)
  540. data[dataOffset + dataIndex++] = UNLATCH;
  541. if (dataIndex > dataLength)
  542. return -1;
  543. return dataIndex + dataOffset - origDataOffset;
  544. }
  545. private static int EdifactEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength, int symbolIndex, int prevEnc, int origDataOffset, bool sizeFixed)
  546. {
  547. if (textLength == 0)
  548. return 0;
  549. int c;
  550. int textIndex = 0;
  551. int dataIndex = 0;
  552. int edi = 0;
  553. int pedi = 18;
  554. bool ascii = true;
  555. int dataSize = dataOffset + dataLength;
  556. for (; textIndex < textLength; ++textIndex)
  557. {
  558. c = text[textIndex + textOffset] & 0xff;
  559. if (((c & 0xe0) == 0x40 || (c & 0xe0) == 0x20) && c != '_')
  560. {
  561. if (ascii)
  562. {
  563. if (dataIndex + 1 > dataLength)
  564. break;
  565. data[dataOffset + dataIndex++] = LATCH_EDIFACT;
  566. ascii = false;
  567. }
  568. c &= 0x3f;
  569. edi |= c << pedi;
  570. if (pedi == 0)
  571. {
  572. if (dataIndex + 3 > dataLength)
  573. break;
  574. data[dataOffset + dataIndex++] = (byte)(edi >> 16);
  575. data[dataOffset + dataIndex++] = (byte)(edi >> 8);
  576. data[dataOffset + dataIndex++] = (byte)edi;
  577. edi = 0;
  578. pedi = 18;
  579. }
  580. else
  581. pedi -= 6;
  582. }
  583. else
  584. {
  585. if (!ascii)
  586. {
  587. edi |= ('_' & 0x3f) << pedi;
  588. if (dataIndex + 3 - pedi / 8 > dataLength)
  589. break;
  590. data[dataOffset + dataIndex++] = (byte)(edi >> 16);
  591. if (pedi <= 12)
  592. data[dataOffset + dataIndex++] = (byte)(edi >> 8);
  593. if (pedi <= 6)
  594. data[dataOffset + dataIndex++] = (byte)edi;
  595. ascii = true;
  596. pedi = 18;
  597. edi = 0;
  598. }
  599. if (IsDigit(c) && textOffset + textIndex > 0 && IsDigit(text[textOffset + textIndex - 1] & 0xff) &&
  600. prevEnc == (int)DatamatrixEncoding.Edifact && data[dataOffset - 1] >= 49 && data[dataOffset - 1] <= 58)
  601. {
  602. data[dataOffset + dataIndex - 1] = (byte)(((text[textOffset - 1] & 0xff) - '0') * 10 + c - '0' + 130);
  603. dataIndex--;
  604. }
  605. else
  606. {
  607. int i = AsciiEncodation(text, textOffset + textIndex, 1, data, dataOffset + dataIndex, dataLength, -1);
  608. if (i < 0)
  609. return -1;
  610. if (data[dataOffset + dataIndex] == UPPER_CASE_SIGN)
  611. dataIndex++;
  612. dataIndex++;
  613. }
  614. }
  615. }
  616. if (textIndex != textLength)
  617. return -1;
  618. if (!sizeFixed && (symbolIndex == text.Length - 1 || symbolIndex < 0))
  619. {
  620. dataSize = int.MaxValue;
  621. for (int i = 0; i < dmSizes.Length; ++i)
  622. {
  623. if (dmSizes[i].dataSize >= dataOffset + dataIndex + (3 - pedi / 6))
  624. {
  625. dataSize = dmSizes[i].dataSize;
  626. break;
  627. }
  628. }
  629. }
  630. if (dataSize - dataOffset - dataIndex <= 2 && pedi >= 6)
  631. {
  632. if (pedi != 18 && dataIndex + 2 - pedi / 8 > dataLength)
  633. return -1;
  634. if (pedi <= 12)
  635. {
  636. byte val = (byte)((edi >> 18) & 0x3F);
  637. if ((val & 0x20) == 0)
  638. val |= 0x40;
  639. data[dataOffset + dataIndex++] = (byte)(val + 1);
  640. }
  641. if (pedi <= 6)
  642. {
  643. byte val = (byte)((edi >> 12) & 0x3F);
  644. if ((val & 0x20) == 0)
  645. val |= 0x40;
  646. data[dataOffset + dataIndex++] = (byte)(val + 1);
  647. }
  648. }
  649. else if (!ascii)
  650. {
  651. edi |= ('_' & 0x3f) << pedi;
  652. if (dataIndex + 3 - pedi / 8 > dataLength)
  653. return -1;
  654. data[dataOffset + dataIndex++] = (byte)(edi >> 16);
  655. if (pedi <= 12)
  656. data[dataOffset + dataIndex++] = (byte)(edi >> 8);
  657. if (pedi <= 6)
  658. data[dataOffset + dataIndex++] = (byte)edi;
  659. }
  660. return dataIndex + dataOffset - origDataOffset;
  661. }
  662. private static int C40OrTextEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength, bool c40, int symbolIndex, int prevEnc, int origDataOffset)
  663. {
  664. if (textLength == 0)
  665. return 0;
  666. int i, a, c;
  667. string basic, shift2, shift3;
  668. int textIndex = 0;
  669. int dataIndex = 0;
  670. shift2 = SHIFTED_SET_C40_AND_TEXT;
  671. if (c40)
  672. {
  673. basic = BASE_SET_C40;
  674. shift3 = SHIFTED_SET_C40;
  675. }
  676. else
  677. {
  678. basic = BASE_SET_TEXT;
  679. shift3 = SHIFTED_SET_TEXT;
  680. }
  681. int mode = c40 ? (int)DatamatrixEncoding.C40 : (int)DatamatrixEncoding.Text;
  682. if (symbolIndex != -1)
  683. return AsciiEncodation(text, textOffset, 1, data, dataOffset, dataLength, prevEnc == mode ? 1 : -1);
  684. if (c40)
  685. data[dataOffset + dataIndex++] = LATCH_C40;
  686. else
  687. data[dataOffset + dataIndex++] = LATCH_TEXT;
  688. int[] encodedChars = new int[textLength * 4 + 10];
  689. int encIndex = 0;
  690. int last0 = 0;
  691. int last1 = 0;
  692. while (textIndex < textLength)
  693. {
  694. if (encIndex % 3 == 0)
  695. {
  696. last0 = textIndex;
  697. last1 = encIndex;
  698. }
  699. c = text[textOffset + textIndex++] & 0xff;
  700. if (c > 127)
  701. {
  702. c -= 128;
  703. encodedChars[encIndex++] = 1;
  704. encodedChars[encIndex++] = 30;
  705. }
  706. int idx = basic.IndexOf((char)c);
  707. if (idx >= 0)
  708. {
  709. encodedChars[encIndex++] = idx + 3;
  710. }
  711. else if (c < 32)
  712. {
  713. encodedChars[encIndex++] = 0;
  714. encodedChars[encIndex++] = c;
  715. }
  716. else if ((idx = shift2.IndexOf((char)c)) >= 0)
  717. {
  718. encodedChars[encIndex++] = 1;
  719. encodedChars[encIndex++] = idx;
  720. }
  721. else if ((idx = shift3.IndexOf((char)c)) >= 0)
  722. {
  723. encodedChars[encIndex++] = 2;
  724. encodedChars[encIndex++] = idx;
  725. }
  726. }
  727. if (encIndex % 3 != 0)
  728. {
  729. textIndex = last0;
  730. encIndex = last1;
  731. }
  732. if (encIndex / 3 * 2 > dataLength - 2)
  733. {
  734. return -1;
  735. }
  736. i = 0;
  737. for (; i < encIndex; i += 3)
  738. {
  739. a = 1600 * encodedChars[i] + 40 * encodedChars[i + 1] + encodedChars[i + 2] + 1;
  740. data[dataOffset + dataIndex++] = (byte)(a / 256);
  741. data[dataOffset + dataIndex++] = (byte)a;
  742. }
  743. if (dataLength - dataIndex > 2)
  744. data[dataOffset + dataIndex++] = UNLATCH;
  745. if (symbolIndex < 0 && textLength > textIndex)
  746. {
  747. i = AsciiEncodation(text, textOffset + textIndex, textLength - textIndex, data, dataOffset + dataIndex, dataLength - dataIndex, -1);
  748. return i + dataIndex + dataOffset - origDataOffset;
  749. }
  750. return dataIndex + dataOffset - origDataOffset;
  751. }
  752. private int GetEncodation(byte[] text, int textOffset, int textSize, byte[] data, int dataOffset, int dataSize, bool sizeFixed, bool firstMatch)
  753. {
  754. int e, j, k;
  755. int[] e1 = new int[6];
  756. if (dataSize < 0)
  757. return -1;
  758. e = -1;
  759. if (encoding == DatamatrixEncoding.Auto)
  760. {
  761. e1[0] = AsciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize, -1);
  762. if (firstMatch && e1[0] >= 0)
  763. return e1[0];
  764. e1[1] = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true, -1, -1, dataOffset);
  765. if (firstMatch && e1[1] >= 0)
  766. return e1[1];
  767. e1[2] = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false, -1, -1, dataOffset);
  768. if (firstMatch && e1[2] >= 0)
  769. return e1[2];
  770. e1[3] = B256Encodation(text, textOffset, textSize, data, dataOffset, dataSize, -1, dataOffset);
  771. if (firstMatch && e1[3] >= 0)
  772. return e1[3];
  773. e1[4] = X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize, -1, dataOffset);
  774. if (firstMatch && e1[4] >= 0)
  775. return e1[4];
  776. e1[5] = EdifactEncodation(text, textOffset, textSize, data, dataOffset, dataSize, -1, -1, dataOffset, sizeFixed);
  777. if (firstMatch && e1[5] >= 0)
  778. return e1[5];
  779. if (e1[0] < 0 && e1[1] < 0 && e1[2] < 0 && e1[3] < 0 && e1[4] < 0 && e1[5] < 0)
  780. {
  781. return -1;
  782. }
  783. j = 0;
  784. e = 99999;
  785. for (k = 0; k < 6; ++k)
  786. {
  787. if (e1[k] >= 0 && e1[k] < e)
  788. {
  789. e = e1[k];
  790. j = k;
  791. }
  792. }
  793. if (j == 0)
  794. e = AsciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize, -1);
  795. else if (j == 1)
  796. e = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true, -1, -1, dataOffset);
  797. else if (j == 2)
  798. e = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false, -1, -1, dataOffset);
  799. else if (j == 3)
  800. e = B256Encodation(text, textOffset, textSize, data, dataOffset, dataSize, -1, dataOffset);
  801. else if (j == 4)
  802. e = X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize, -1, dataOffset);
  803. return e;
  804. }
  805. switch (encoding)
  806. {
  807. case DatamatrixEncoding.Ascii:
  808. return AsciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize, -1);
  809. case DatamatrixEncoding.C40:
  810. return C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true, -1, -1, dataOffset);
  811. case DatamatrixEncoding.Text:
  812. return C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false, -1, -1, dataOffset);
  813. case DatamatrixEncoding.Base256:
  814. return B256Encodation(text, textOffset, textSize, data, dataOffset, dataSize, -1, dataOffset);
  815. case DatamatrixEncoding.X12:
  816. return X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize, -1, dataOffset);
  817. case DatamatrixEncoding.Edifact:
  818. return EdifactEncodation(text, textOffset, textSize, data, dataOffset, dataSize, -1, -1, dataOffset, sizeFixed);
  819. }
  820. return -1;
  821. }
  822. private static int GetNumber(byte[] text, int ptrIn, int n)
  823. {
  824. int v, j, c;
  825. v = 0;
  826. for (j = 0; j < n; ++j)
  827. {
  828. c = text[ptrIn++] & 0xff;
  829. if (c < '0' || c > '9')
  830. return -1;
  831. v = v * 10 + c - '0';
  832. }
  833. return v;
  834. }
  835. private string ReplaceControlCodes(string text)
  836. {
  837. if (AutoEncode)
  838. {
  839. if (text.StartsWith("&1;"))
  840. text = ((char)232).ToString() + text.Remove(0, 3);
  841. text = text.Replace("&1;", ((char)0x1d).ToString());
  842. }
  843. return text;
  844. }
  845. private void Generate(string text)
  846. {
  847. if (text.StartsWith("("))
  848. {
  849. string gsText = GS1Helper.ParseGS1(text);
  850. if (!string.IsNullOrEmpty(gsText))
  851. {
  852. text = gsText;
  853. }
  854. }
  855. text = ReplaceControlCodes(text);
  856. byte[] t = System.Text.Encoding.GetEncoding(CodePage).GetBytes(text);
  857. Generate(t, 0, t.Length);
  858. }
  859. private void Generate(byte[] text, int textOffset, int textSize)
  860. {
  861. int e, k, full;
  862. DmParams dm, last;
  863. byte[] data = new byte[2500];
  864. e = -1;
  865. int extCount = 0;
  866. if (text.Length > 0 && text[0] == 232)
  867. {
  868. data[0] = (byte)232;
  869. textOffset++;
  870. textSize--;
  871. extCount = 1;
  872. }
  873. if (height == 0 || width == 0)
  874. {
  875. last = dmSizes[dmSizes.Length - 1];
  876. e = GetEncodation(text, textOffset, textSize, data, extCount, last.dataSize - extCount, false, false);
  877. if (e < 0)
  878. {
  879. throw new Exception("The text is too big.");
  880. }
  881. e += extCount;
  882. for (k = 0; k < dmSizes.Length; ++k)
  883. {
  884. if (dmSizes[k].dataSize >= e)
  885. break;
  886. }
  887. dm = dmSizes[k];
  888. height = dm.height;
  889. width = dm.width;
  890. }
  891. else
  892. {
  893. for (k = 0; k < dmSizes.Length; ++k)
  894. {
  895. if (height == dmSizes[k].height && width == dmSizes[k].width)
  896. break;
  897. }
  898. if (k == dmSizes.Length)
  899. {
  900. throw new Exception("Invalid symbol size.");
  901. }
  902. dm = dmSizes[k];
  903. e = GetEncodation(text, textOffset, textSize, data, extCount, dm.dataSize - extCount, true, true);
  904. if (e < 0)
  905. {
  906. throw new Exception("The text is too big.");
  907. }
  908. e += extCount;
  909. }
  910. image = new byte[((dm.width + 7) / 8) * dm.height];
  911. MakePadding(data, e, dm.dataSize - e);
  912. place = Placement.DoPlacement(dm.height - (dm.height / dm.heightSection * 2), dm.width - (dm.width / dm.widthSection * 2));
  913. full = dm.dataSize + ((dm.dataSize + 2) / dm.dataBlock) * dm.errorBlock;
  914. ReedSolomon.GenerateECC(data, dm.dataSize, dm.dataBlock, dm.errorBlock);
  915. Draw(data, full, dm);
  916. }
  917. #endregion
  918. #region Public Methods
  919. /// <inheritdoc/>
  920. public override void Assign(BarcodeBase source)
  921. {
  922. base.Assign(source);
  923. BarcodeDatamatrix src = source as BarcodeDatamatrix;
  924. SymbolSize = src.SymbolSize;
  925. Encoding = src.Encoding;
  926. CodePage = src.CodePage;
  927. PixelSize = src.PixelSize;
  928. AutoEncode = src.AutoEncode;
  929. }
  930. internal override void Serialize(FastReport.Utils.FRWriter writer, string prefix, BarcodeBase diff)
  931. {
  932. base.Serialize(writer, prefix, diff);
  933. BarcodeDatamatrix c = diff as BarcodeDatamatrix;
  934. if (c == null || SymbolSize != c.SymbolSize)
  935. writer.WriteValue(prefix + "SymbolSize", SymbolSize);
  936. if (c == null || Encoding != c.Encoding)
  937. writer.WriteValue(prefix + "Encoding", Encoding);
  938. if (c == null || CodePage != c.CodePage)
  939. writer.WriteInt(prefix + "CodePage", CodePage);
  940. if (c == null || PixelSize != c.PixelSize)
  941. writer.WriteInt(prefix + "PixelSize", PixelSize);
  942. if (c == null || AutoEncode != c.AutoEncode)
  943. writer.WriteBool(prefix + "AutoEncode", AutoEncode);
  944. }
  945. internal override void Initialize(string text, bool showText, int angle, float zoom, bool showMarker)
  946. {
  947. base.Initialize(text, showText, angle, zoom, showMarker);
  948. if (SymbolSize == DatamatrixSymbolSize.Auto)
  949. {
  950. width = 0;
  951. height = 0;
  952. }
  953. else
  954. {
  955. DmParams dmParams = dmSizes[(int)SymbolSize - 1];
  956. width = dmParams.width;
  957. height = dmParams.height;
  958. }
  959. Generate(base.text);
  960. }
  961. internal override SizeF CalcBounds()
  962. {
  963. int textAdd = showText ? (int)(FontHeight) : 0;
  964. return new SizeF(width * PixelSize, height * PixelSize + textAdd);
  965. }
  966. internal override string StripControlCodes(string data)
  967. {
  968. if (AutoEncode)
  969. {
  970. if (data.StartsWith("&1;"))
  971. data = data.Remove(0, 3);
  972. data = data.Replace("&1;", " ");
  973. }
  974. return data;
  975. }
  976. internal override void Draw2DBarcode(IGraphics g, float kx, float ky)
  977. {
  978. if (image == null)
  979. return;
  980. Brush dark = new SolidBrush(Color);
  981. int stride = (width + 7) / 8;
  982. for (int k = 0; k < height; ++k)
  983. {
  984. int p = k * stride;
  985. for (int j = 0; j < width; ++j)
  986. {
  987. int b = image[p + (j / 8)] & 0xff;
  988. b <<= j % 8;
  989. Brush brush = (b & 0x80) == 0 ? Brushes.White : dark;
  990. g.FillRectangle(brush, j * PixelSize * kx, k * PixelSize * ky,
  991. PixelSize * kx, PixelSize * ky);
  992. }
  993. }
  994. dark.Dispose();
  995. }
  996. #endregion
  997. /// <summary>
  998. /// Initializes a new instance of the <see cref="BarcodeDatamatrix"/> class with default settings.
  999. /// </summary>
  1000. public BarcodeDatamatrix()
  1001. {
  1002. CodePage = 1252;
  1003. PixelSize = 3;
  1004. AutoEncode = true;
  1005. #if CROSSPLATFORM || COREWIN
  1006. System.Text.Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
  1007. #endif
  1008. }
  1009. private class DmParams
  1010. {
  1011. internal DmParams(int height, int width, int heightSection, int widthSection, int dataSize, int dataBlock, int errorBlock)
  1012. {
  1013. this.height = height;
  1014. this.width = width;
  1015. this.heightSection = heightSection;
  1016. this.widthSection = widthSection;
  1017. this.dataSize = dataSize;
  1018. this.dataBlock = dataBlock;
  1019. this.errorBlock = errorBlock;
  1020. }
  1021. internal int height;
  1022. internal int width;
  1023. internal int heightSection;
  1024. internal int widthSection;
  1025. internal int dataSize;
  1026. internal int dataBlock;
  1027. internal int errorBlock;
  1028. };
  1029. private class Placement
  1030. {
  1031. private int nrow;
  1032. private int ncol;
  1033. private short[] array;
  1034. private static Hashtable cache = Hashtable.Synchronized(new Hashtable());
  1035. private Placement()
  1036. {
  1037. }
  1038. internal static short[] DoPlacement(int nrow, int ncol)
  1039. {
  1040. int key = nrow * 1000 + ncol;
  1041. short[] pc = (short[])cache[key];
  1042. if (pc != null)
  1043. return pc;
  1044. Placement p = new Placement();
  1045. p.nrow = nrow;
  1046. p.ncol = ncol;
  1047. p.array = new short[nrow * ncol];
  1048. p.Ecc200();
  1049. cache[key] = p.array;
  1050. return p.array;
  1051. }
  1052. /* "module" places "chr+bit" with appropriate wrapping within array[] */
  1053. private void Module(int row, int col, int chr, int bit)
  1054. {
  1055. if (row < 0) { row += nrow; col += 4 - ((nrow + 4) % 8); }
  1056. if (col < 0) { col += ncol; row += 4 - ((ncol + 4) % 8); }
  1057. array[row * ncol + col] = (short)(8 * chr + bit);
  1058. }
  1059. /* "utah" places the 8 bits of a utah-shaped symbol character in ECC200 */
  1060. private void Utah(int row, int col, int chr)
  1061. {
  1062. Module(row - 2, col - 2, chr, 0);
  1063. Module(row - 2, col - 1, chr, 1);
  1064. Module(row - 1, col - 2, chr, 2);
  1065. Module(row - 1, col - 1, chr, 3);
  1066. Module(row - 1, col, chr, 4);
  1067. Module(row, col - 2, chr, 5);
  1068. Module(row, col - 1, chr, 6);
  1069. Module(row, col, chr, 7);
  1070. }
  1071. /* "cornerN" places 8 bits of the four special corner cases in ECC200 */
  1072. private void Corner1(int chr)
  1073. {
  1074. Module(nrow - 1, 0, chr, 0);
  1075. Module(nrow - 1, 1, chr, 1);
  1076. Module(nrow - 1, 2, chr, 2);
  1077. Module(0, ncol - 2, chr, 3);
  1078. Module(0, ncol - 1, chr, 4);
  1079. Module(1, ncol - 1, chr, 5);
  1080. Module(2, ncol - 1, chr, 6);
  1081. Module(3, ncol - 1, chr, 7);
  1082. }
  1083. private void Corner2(int chr)
  1084. {
  1085. Module(nrow - 3, 0, chr, 0);
  1086. Module(nrow - 2, 0, chr, 1);
  1087. Module(nrow - 1, 0, chr, 2);
  1088. Module(0, ncol - 4, chr, 3);
  1089. Module(0, ncol - 3, chr, 4);
  1090. Module(0, ncol - 2, chr, 5);
  1091. Module(0, ncol - 1, chr, 6);
  1092. Module(1, ncol - 1, chr, 7);
  1093. }
  1094. private void Corner3(int chr)
  1095. {
  1096. Module(nrow - 3, 0, chr, 0);
  1097. Module(nrow - 2, 0, chr, 1);
  1098. Module(nrow - 1, 0, chr, 2);
  1099. Module(0, ncol - 2, chr, 3);
  1100. Module(0, ncol - 1, chr, 4);
  1101. Module(1, ncol - 1, chr, 5);
  1102. Module(2, ncol - 1, chr, 6);
  1103. Module(3, ncol - 1, chr, 7);
  1104. }
  1105. private void Corner4(int chr)
  1106. {
  1107. Module(nrow - 1, 0, chr, 0);
  1108. Module(nrow - 1, ncol - 1, chr, 1);
  1109. Module(0, ncol - 3, chr, 2);
  1110. Module(0, ncol - 2, chr, 3);
  1111. Module(0, ncol - 1, chr, 4);
  1112. Module(1, ncol - 3, chr, 5);
  1113. Module(1, ncol - 2, chr, 6);
  1114. Module(1, ncol - 1, chr, 7);
  1115. }
  1116. /* "ECC200" fills an nrow x ncol array with appropriate values for ECC200 */
  1117. private void Ecc200()
  1118. {
  1119. int row, col, chr;
  1120. /* First, fill the array[] with invalid entries */
  1121. for (int k = 0; k < array.Length; ++k)
  1122. array[k] = (short)0;
  1123. /* Starting in the correct location for character #1, bit 8,... */
  1124. chr = 1; row = 4; col = 0;
  1125. do
  1126. {
  1127. /* repeatedly first check for one of the special corner cases, then... */
  1128. if ((row == nrow) && (col == 0)) Corner1(chr++);
  1129. if ((row == nrow - 2) && (col == 0) && (ncol % 4 != 0)) Corner2(chr++);
  1130. if ((row == nrow - 2) && (col == 0) && (ncol % 8 == 4)) Corner3(chr++);
  1131. if ((row == nrow + 4) && (col == 2) && (ncol % 8 == 0)) Corner4(chr++);
  1132. /* sweep upward diagonally, inserting successive characters,... */
  1133. do
  1134. {
  1135. if ((row < nrow) && (col >= 0) && array[row * ncol + col] == 0)
  1136. Utah(row, col, chr++);
  1137. row -= 2; col += 2;
  1138. } while ((row >= 0) && (col < ncol));
  1139. row += 1; col += 3;
  1140. /* & then sweep downward diagonally, inserting successive characters,... */
  1141. do
  1142. {
  1143. if ((row >= 0) && (col < ncol) && array[row * ncol + col] == 0)
  1144. Utah(row, col, chr++);
  1145. row += 2; col -= 2;
  1146. } while ((row < nrow) && (col >= 0));
  1147. row += 3; col += 1;
  1148. /* ... until the entire array is scanned */
  1149. } while ((row < nrow) || (col < ncol));
  1150. /* Lastly, if the lower righthand corner is untouched, fill in fixed pattern */
  1151. if (array[nrow * ncol - 1] == 0)
  1152. {
  1153. array[nrow * ncol - 1] = array[nrow * ncol - ncol - 2] = 1;
  1154. }
  1155. }
  1156. }
  1157. private class ReedSolomon
  1158. {
  1159. private static readonly int[] log = {
  1160. 0, 255, 1, 240, 2, 225, 241, 53, 3, 38, 226, 133, 242, 43, 54, 210,
  1161. 4, 195, 39, 114, 227, 106, 134, 28, 243, 140, 44, 23, 55, 118, 211, 234,
  1162. 5, 219, 196, 96, 40, 222, 115, 103, 228, 78, 107, 125, 135, 8, 29, 162,
  1163. 244, 186, 141, 180, 45, 99, 24, 49, 56, 13, 119, 153, 212, 199, 235, 91,
  1164. 6, 76, 220, 217, 197, 11, 97, 184, 41, 36, 223, 253, 116, 138, 104, 193,
  1165. 229, 86, 79, 171, 108, 165, 126, 145, 136, 34, 9, 74, 30, 32, 163, 84,
  1166. 245, 173, 187, 204, 142, 81, 181, 190, 46, 88, 100, 159, 25, 231, 50, 207,
  1167. 57, 147, 14, 67, 120, 128, 154, 248, 213, 167, 200, 63, 236, 110, 92, 176,
  1168. 7, 161, 77, 124, 221, 102, 218, 95, 198, 90, 12, 152, 98, 48, 185, 179,
  1169. 42, 209, 37, 132, 224, 52, 254, 239, 117, 233, 139, 22, 105, 27, 194, 113,
  1170. 230, 206, 87, 158, 80, 189, 172, 203, 109, 175, 166, 62, 127, 247, 146, 66,
  1171. 137, 192, 35, 252, 10, 183, 75, 216, 31, 83, 33, 73, 164, 144, 85, 170,
  1172. 246, 65, 174, 61, 188, 202, 205, 157, 143, 169, 82, 72, 182, 215, 191, 251,
  1173. 47, 178, 89, 151, 101, 94, 160, 123, 26, 112, 232, 21, 51, 238, 208, 131,
  1174. 58, 69, 148, 18, 15, 16, 68, 17, 121, 149, 129, 19, 155, 59, 249, 70,
  1175. 214, 250, 168, 71, 201, 156, 64, 60, 237, 130, 111, 20, 93, 122, 177, 150
  1176. };
  1177. private static readonly int[] alog = {
  1178. 1, 2, 4, 8, 16, 32, 64, 128, 45, 90, 180, 69, 138, 57, 114, 228,
  1179. 229, 231, 227, 235, 251, 219, 155, 27, 54, 108, 216, 157, 23, 46, 92, 184,
  1180. 93, 186, 89, 178, 73, 146, 9, 18, 36, 72, 144, 13, 26, 52, 104, 208,
  1181. 141, 55, 110, 220, 149, 7, 14, 28, 56, 112, 224, 237, 247, 195, 171, 123,
  1182. 246, 193, 175, 115, 230, 225, 239, 243, 203, 187, 91, 182, 65, 130, 41, 82,
  1183. 164, 101, 202, 185, 95, 190, 81, 162, 105, 210, 137, 63, 126, 252, 213, 135,
  1184. 35, 70, 140, 53, 106, 212, 133, 39, 78, 156, 21, 42, 84, 168, 125, 250,
  1185. 217, 159, 19, 38, 76, 152, 29, 58, 116, 232, 253, 215, 131, 43, 86, 172,
  1186. 117, 234, 249, 223, 147, 11, 22, 44, 88, 176, 77, 154, 25, 50, 100, 200,
  1187. 189, 87, 174, 113, 226, 233, 255, 211, 139, 59, 118, 236, 245, 199, 163, 107,
  1188. 214, 129, 47, 94, 188, 85, 170, 121, 242, 201, 191, 83, 166, 97, 194, 169,
  1189. 127, 254, 209, 143, 51, 102, 204, 181, 71, 142, 49, 98, 196, 165, 103, 206,
  1190. 177, 79, 158, 17, 34, 68, 136, 61, 122, 244, 197, 167, 99, 198, 161, 111,
  1191. 222, 145, 15, 30, 60, 120, 240, 205, 183, 67, 134, 33, 66, 132, 37, 74,
  1192. 148, 5, 10, 20, 40, 80, 160, 109, 218, 153, 31, 62, 124, 248, 221, 151,
  1193. 3, 6, 12, 24, 48, 96, 192, 173, 119, 238, 241, 207, 179, 75, 150, 1
  1194. };
  1195. private static readonly int[] poly5 = {
  1196. 228, 48, 15, 111, 62
  1197. };
  1198. private static readonly int[] poly7 = {
  1199. 23, 68, 144, 134, 240, 92, 254
  1200. };
  1201. private static readonly int[] poly10 = {
  1202. 28, 24, 185, 166, 223, 248, 116, 255, 110, 61
  1203. };
  1204. private static readonly int[] poly11 = {
  1205. 175, 138, 205, 12, 194, 168, 39, 245, 60, 97, 120
  1206. };
  1207. private static readonly int[] poly12 = {
  1208. 41, 153, 158, 91, 61, 42, 142, 213, 97, 178, 100, 242
  1209. };
  1210. private static readonly int[] poly14 = {
  1211. 156, 97, 192, 252, 95, 9, 157, 119, 138, 45, 18, 186, 83, 185
  1212. };
  1213. private static readonly int[] poly18 = {
  1214. 83, 195, 100, 39, 188, 75, 66, 61, 241, 213, 109, 129, 94, 254, 225, 48,
  1215. 90, 188
  1216. };
  1217. private static readonly int[] poly20 = {
  1218. 15, 195, 244, 9, 233, 71, 168, 2, 188, 160, 153, 145, 253, 79, 108, 82,
  1219. 27, 174, 186, 172
  1220. };
  1221. private static readonly int[] poly24 = {
  1222. 52, 190, 88, 205, 109, 39, 176, 21, 155, 197, 251, 223, 155, 21, 5, 172,
  1223. 254, 124, 12, 181, 184, 96, 50, 193
  1224. };
  1225. private static readonly int[] poly28 = {
  1226. 211, 231, 43, 97, 71, 96, 103, 174, 37, 151, 170, 53, 75, 34, 249, 121,
  1227. 17, 138, 110, 213, 141, 136, 120, 151, 233, 168, 93, 255
  1228. };
  1229. private static readonly int[] poly36 = {
  1230. 245, 127, 242, 218, 130, 250, 162, 181, 102, 120, 84, 179, 220, 251, 80, 182,
  1231. 229, 18, 2, 4, 68, 33, 101, 137, 95, 119, 115, 44, 175, 184, 59, 25,
  1232. 225, 98, 81, 112
  1233. };
  1234. private static readonly int[] poly42 = {
  1235. 77, 193, 137, 31, 19, 38, 22, 153, 247, 105, 122, 2, 245, 133, 242, 8,
  1236. 175, 95, 100, 9, 167, 105, 214, 111, 57, 121, 21, 1, 253, 57, 54, 101,
  1237. 248, 202, 69, 50, 150, 177, 226, 5, 9, 5
  1238. };
  1239. private static readonly int[] poly48 = {
  1240. 245, 132, 172, 223, 96, 32, 117, 22, 238, 133, 238, 231, 205, 188, 237, 87,
  1241. 191, 106, 16, 147, 118, 23, 37, 90, 170, 205, 131, 88, 120, 100, 66, 138,
  1242. 186, 240, 82, 44, 176, 87, 187, 147, 160, 175, 69, 213, 92, 253, 225, 19
  1243. };
  1244. private static readonly int[] poly56 = {
  1245. 175, 9, 223, 238, 12, 17, 220, 208, 100, 29, 175, 170, 230, 192, 215, 235,
  1246. 150, 159, 36, 223, 38, 200, 132, 54, 228, 146, 218, 234, 117, 203, 29, 232,
  1247. 144, 238, 22, 150, 201, 117, 62, 207, 164, 13, 137, 245, 127, 67, 247, 28,
  1248. 155, 43, 203, 107, 233, 53, 143, 46
  1249. };
  1250. private static readonly int[] poly62 = {
  1251. 242, 93, 169, 50, 144, 210, 39, 118, 202, 188, 201, 189, 143, 108, 196, 37,
  1252. 185, 112, 134, 230, 245, 63, 197, 190, 250, 106, 185, 221, 175, 64, 114, 71,
  1253. 161, 44, 147, 6, 27, 218, 51, 63, 87, 10, 40, 130, 188, 17, 163, 31,
  1254. 176, 170, 4, 107, 232, 7, 94, 166, 224, 124, 86, 47, 11, 204
  1255. };
  1256. private static readonly int[] poly68 = {
  1257. 220, 228, 173, 89, 251, 149, 159, 56, 89, 33, 147, 244, 154, 36, 73, 127,
  1258. 213, 136, 248, 180, 234, 197, 158, 177, 68, 122, 93, 213, 15, 160, 227, 236,
  1259. 66, 139, 153, 185, 202, 167, 179, 25, 220, 232, 96, 210, 231, 136, 223, 239,
  1260. 181, 241, 59, 52, 172, 25, 49, 232, 211, 189, 64, 54, 108, 153, 132, 63,
  1261. 96, 103, 82, 186
  1262. };
  1263. private static int[] GetPoly(int nc)
  1264. {
  1265. switch (nc)
  1266. {
  1267. case 5:
  1268. return poly5;
  1269. case 7:
  1270. return poly7;
  1271. case 10:
  1272. return poly10;
  1273. case 11:
  1274. return poly11;
  1275. case 12:
  1276. return poly12;
  1277. case 14:
  1278. return poly14;
  1279. case 18:
  1280. return poly18;
  1281. case 20:
  1282. return poly20;
  1283. case 24:
  1284. return poly24;
  1285. case 28:
  1286. return poly28;
  1287. case 36:
  1288. return poly36;
  1289. case 42:
  1290. return poly42;
  1291. case 48:
  1292. return poly48;
  1293. case 56:
  1294. return poly56;
  1295. case 62:
  1296. return poly62;
  1297. case 68:
  1298. return poly68;
  1299. }
  1300. return null;
  1301. }
  1302. private static void ReedSolomonBlock(byte[] wd, int nd, byte[] ncout, int nc, int[] c)
  1303. {
  1304. int i, j, k;
  1305. for (i = 0; i <= nc; i++) ncout[i] = 0;
  1306. for (i = 0; i < nd; i++)
  1307. {
  1308. k = (ncout[0] ^ wd[i]) & 0xff;
  1309. for (j = 0; j < nc; j++)
  1310. {
  1311. ncout[j] = (byte)(ncout[j + 1] ^ (k == 0 ? (byte)0 : (byte)alog[(log[k] + log[c[nc - j - 1]]) % (255)]));
  1312. }
  1313. }
  1314. }
  1315. internal static void GenerateECC(byte[] wd, int nd, int datablock, int nc)
  1316. {
  1317. int blocks = (nd + 2) / datablock;
  1318. int b;
  1319. byte[] buf = new byte[256];
  1320. byte[] ecc = new byte[256];
  1321. int[] c = GetPoly(nc);
  1322. if (c == null)
  1323. return;
  1324. for (b = 0; b < blocks; b++)
  1325. {
  1326. int n, p = 0;
  1327. for (n = b; n < nd; n += blocks)
  1328. buf[p++] = wd[n];
  1329. ReedSolomonBlock(buf, p, ecc, nc, c);
  1330. p = 0;
  1331. for (n = b; n < nc * blocks; n += blocks)
  1332. wd[nd + n] = ecc[p++];
  1333. }
  1334. }
  1335. }
  1336. }
  1337. }