ZplExport.cs 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233
  1. using FastReport.Barcode;
  2. using FastReport.Table;
  3. using FastReport.Utils;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Drawing;
  7. using System.Drawing.Imaging;
  8. using System.IO;
  9. using System.Runtime.InteropServices;
  10. using System.Text;
  11. namespace FastReport.Export.Zpl
  12. {
  13. /// <summary>
  14. /// Represents the Zpl export filter.
  15. /// </summary>
  16. public partial class ZplExport : ExportBase
  17. {
  18. #region Public properties
  19. /// <summary>
  20. /// Enum of ZPL format versions.
  21. /// </summary>
  22. public enum ZplVersions
  23. {
  24. /// <summary>
  25. /// Standart ZPL
  26. /// </summary>
  27. ZPL1,
  28. /// <summary>
  29. /// ZPL II
  30. /// </summary>
  31. ZPL2
  32. }
  33. /// <summary>
  34. /// Enum of densty types of Zebra printers.
  35. /// </summary>
  36. public enum ZplDensity
  37. {
  38. /// <summary>
  39. /// 6 dpmm(152 dpi)
  40. /// </summary>
  41. d6_dpmm_152_dpi,
  42. /// <summary>
  43. /// 8 dpmm(203 dpi)
  44. /// </summary>
  45. d8_dpmm_203_dpi,
  46. /// <summary>
  47. /// 12 dpmm(300 dpi)
  48. /// </summary>
  49. d12_dpmm_300_dpi,
  50. /// <summary>
  51. /// 24 dpmm(600 dpi)
  52. /// </summary>
  53. d24_dpmm_600_dpi
  54. }
  55. /// <summary>
  56. /// Sets the density of printer.
  57. /// </summary>
  58. public ZplDensity Density
  59. {
  60. get { return density; }
  61. set { density = value; }
  62. }
  63. /// <summary>
  64. /// Gets or sets the version of ZPL.
  65. /// </summary>
  66. public ZplVersions Version
  67. {
  68. get { return version; }
  69. set { version = value; }
  70. }
  71. /// <summary>
  72. /// Sets the init string for sending before printing the document.
  73. /// </summary>
  74. public string PrinterInit
  75. {
  76. get { return printerInit; }
  77. set { printerInit = value; }
  78. }
  79. /// <summary>
  80. /// Sets the code page of document. Default is UTF-8 (^CI28).
  81. /// </summary>
  82. public string CodePage
  83. {
  84. get { return codePage; }
  85. set { codePage = value; }
  86. }
  87. /// <summary>
  88. /// Sets the string for sending after printing the document.
  89. /// </summary>
  90. public string PrinterFinish
  91. {
  92. get { return printerFinish; }
  93. set { printerFinish = value; }
  94. }
  95. /// <summary>
  96. /// Sets the string for sending before printing each page.
  97. /// </summary>
  98. public string PageInit
  99. {
  100. get { return pageInit; }
  101. set { pageInit = value; }
  102. }
  103. /// <summary>
  104. /// Sets the scale font size.
  105. /// </summary>
  106. public float FontScale
  107. {
  108. get { return fontScale / defaultFontScale; }
  109. set { fontScale = value * defaultFontScale; }
  110. }
  111. /// <summary>
  112. /// Sets the scale barcode size.
  113. /// </summary>
  114. public float BarcodeScale
  115. {
  116. get { return barcodeScale; }
  117. set { barcodeScale = value; }
  118. }
  119. /// <summary>
  120. /// Sets the Printer Font, default value is "A".
  121. /// </summary>
  122. public string PrinterFont
  123. {
  124. get { return font; }
  125. set { font = value; }
  126. }
  127. /// <summary>
  128. /// Enable or disable export as bitmap.
  129. /// </summary>
  130. public bool PrintAsBitmap
  131. {
  132. get { return printAsBitmap; }
  133. set { printAsBitmap = value; }
  134. }
  135. #endregion Public properties
  136. #region Private constants
  137. private const float millimeters = 3.78f;
  138. private const float defaultFontScale = 1.4f;
  139. private const float defaultBarcodeScale = 2f;
  140. #endregion Private constants
  141. #region Private Fields
  142. #if READONLY_STRUCTS
  143. private readonly struct ZplScale
  144. #else
  145. private struct ZplScale
  146. #endif
  147. {
  148. public readonly float PageScale;
  149. public readonly int TwoDCodeScale;
  150. public ZplScale(float pageScale, int qrCodeScale)
  151. {
  152. PageScale = pageScale;
  153. TwoDCodeScale = qrCodeScale;
  154. }
  155. }
  156. // scales of X and Y position and sized depend by ZplDensity
  157. // second value is multiplier for barcode zoom
  158. private ZplScale[] zplScaleArray =
  159. {
  160. //6 dpmm(152 dpi)
  161. new ZplScale(1.5833f, 7),
  162. //8 dpmm(203 dpi)
  163. new ZplScale(2.11458f, 8),
  164. //12 dpmm(300 dpi)
  165. new ZplScale(3.16667f, 10),
  166. //24 dpmm(600 dpi)
  167. new ZplScale(6.34375f, 10)
  168. };
  169. // Enable for Print as Bitmap;
  170. private bool printAsBitmap = true;
  171. private ZplDensity density = ZplDensity.d8_dpmm_203_dpi;
  172. private ZplVersions version = ZplVersions.ZPL1;
  173. // Printer Init String. Sends before document.
  174. private string printerInit;
  175. // Printer Finish String. Sends after document.
  176. private string printerFinish;
  177. // Printer page init string. Sends before page.
  178. private string pageInit;
  179. // Font scale factor.
  180. private float fontScale = defaultFontScale;
  181. // Barcode scale factor (BY..).
  182. private static float barcodeScale = defaultBarcodeScale;
  183. // Position in ZipScale array by default (8 dpmm(203 dpi)
  184. private int scaleIndex = 1;
  185. private float leftMargin = 0;
  186. private float topMargin = 0;
  187. // font
  188. private string font = "A";
  189. private string codePage = "^CI28";
  190. // Bitmap for rendering objects
  191. private Bitmap pageBitmap = null;
  192. // Table with counters for compression the bitmaps
  193. private Dictionary<int, char> countTable;
  194. private int[] counts;
  195. #endregion Private Fields
  196. #region Private Methods
  197. /// <summary>
  198. /// Writes the string value in stream.
  199. /// </summary>
  200. /// <param name="stream"></param>
  201. /// <param name="value"></param>
  202. private void Write(Stream stream, string value)
  203. {
  204. if (!String.IsNullOrEmpty(value))
  205. {
  206. byte[] buf = Encoding.UTF8.GetBytes(value);
  207. stream.Write(buf, 0, buf.Length);
  208. }
  209. }
  210. /// <summary>
  211. /// Writes the string value in stream with CRLF.
  212. /// </summary>
  213. /// <param name="stream"></param>
  214. /// <param name="value"></param>
  215. private void WriteLn(Stream stream, string value)
  216. {
  217. if (!String.IsNullOrEmpty(value))
  218. {
  219. byte[] buf = Encoding.UTF8.GetBytes(value);
  220. stream.Write(buf, 0, buf.Length);
  221. stream.WriteByte(13);
  222. stream.WriteByte(10);
  223. }
  224. }
  225. /// <summary>
  226. /// Gets the left position in zpl units.
  227. /// </summary>
  228. /// <param name="left"></param>
  229. /// <returns></returns>
  230. private int GetLeft(float left)
  231. {
  232. return (int)Math.Round(left * zplScaleArray[scaleIndex].PageScale + leftMargin);
  233. }
  234. /// <summary>
  235. /// Gets the top position in zpl units.
  236. /// </summary>
  237. /// <param name="top"></param>
  238. /// <returns></returns>
  239. private int GetTop(float top)
  240. {
  241. return (int)Math.Round(top * zplScaleArray[scaleIndex].PageScale + topMargin);
  242. }
  243. private int GetWidth(float width, float height, int angle)
  244. {
  245. if (angle == 90 || angle == 270)
  246. return (int)Math.Round(height * zplScaleArray[scaleIndex].PageScale);
  247. else
  248. return (int)Math.Round(width * zplScaleArray[scaleIndex].PageScale);
  249. }
  250. private int GetHeight(float width, float height, int angle)
  251. {
  252. if (angle == 90 || angle == 270)
  253. return (int)Math.Round(width * zplScaleArray[scaleIndex].PageScale);
  254. else
  255. return (int)Math.Round(height * zplScaleArray[scaleIndex].PageScale);
  256. }
  257. private string GetBarcodeZoom(float zoom, BarcodeBase b)
  258. {
  259. return (Math.Round(zoom * barcodeScale) * (b is BarcodePDF417 ? 2 : 1)).ToString();
  260. }
  261. private string GetZPLText(string source)
  262. {
  263. source = source.Replace("\\", "\\\\").Replace("\r\n", "\\&").Replace("$", "\\$");
  264. return source;
  265. }
  266. private string GetOrientation(int angle)
  267. {
  268. if (angle == 90)
  269. return "^FWR";
  270. else if (angle == 180)
  271. return "^FWI";
  272. else if (angle == 270)
  273. return "^FWB";
  274. else
  275. return "^FWN";
  276. }
  277. /// <summary>
  278. /// Exports the TableObject.
  279. /// </summary>
  280. /// <param name="table"></param>
  281. private void ExportTableObject(TableBase table)
  282. {
  283. if (table.ColumnCount > 0 && table.RowCount > 0)
  284. {
  285. StringBuilder tableBorder = new StringBuilder(64);
  286. using (TextObject tableback = new TextObject())
  287. {
  288. tableback.Border = table.Border;
  289. tableback.Fill = table.Fill;
  290. tableback.FillColor = table.FillColor;
  291. tableback.Left = table.AbsLeft;
  292. tableback.Top = table.AbsTop;
  293. float tableWidth = 0;
  294. float tableHeight = 0;
  295. for (int i = 0; i < table.ColumnCount; i++)
  296. tableWidth += table[i, 0].Width;
  297. for (int i = 0; i < table.RowCount; i++)
  298. tableHeight += table.Rows[i].Height;
  299. tableback.Width = (tableWidth < table.Width) ? tableWidth : table.Width;
  300. tableback.Height = tableHeight;
  301. ExportTextObject(tableback);
  302. }
  303. AddTable(table);
  304. }
  305. }
  306. private void AddTable(TableBase table)
  307. {
  308. float y = 0;
  309. for (int i = 0; i < table.RowCount; i++)
  310. {
  311. float x = 0;
  312. for (int j = 0; j < table.ColumnCount; j++)
  313. {
  314. if (!table.IsInsideSpan(table[j, i]))
  315. {
  316. TableCell textcell = table[j, i];
  317. textcell.Left = x;
  318. textcell.Top = y;
  319. if (textcell is TextObject)
  320. ExportTextObject(textcell as TextObject);
  321. else
  322. ExportPictureObject(textcell as ReportComponentBase);
  323. }
  324. x += (table.Columns[j]).Width;
  325. }
  326. y += (table.Rows[i]).Height;
  327. }
  328. }
  329. // Copied from TIFF export with some changes
  330. private Bitmap ConvertToBitonal(Bitmap original)
  331. {
  332. Bitmap source = null;
  333. if (original.PixelFormat != PixelFormat.Format32bppArgb)
  334. {
  335. source = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb);
  336. source.SetResolution(original.HorizontalResolution, original.VerticalResolution);
  337. using (Graphics g = Graphics.FromImage(source))
  338. g.DrawImageUnscaled(original, 0, 0);
  339. }
  340. else
  341. source = original;
  342. BitmapData sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height),
  343. ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
  344. int imageSize = sourceData.Stride * sourceData.Height;
  345. byte[] sourceBuffer = new byte[imageSize];
  346. Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize);
  347. source.UnlockBits(sourceData);
  348. Bitmap destination = new Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed);
  349. BitmapData destinationData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height),
  350. ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
  351. imageSize = destinationData.Stride * destinationData.Height;
  352. byte[] destinationBuffer = new byte[imageSize];
  353. int sourceIndex = 0;
  354. int destinationIndex = 0;
  355. int pixelTotal = 0;
  356. byte destinationValue = 0;
  357. int pixelValue = 128;
  358. int height = source.Height;
  359. int width = source.Width;
  360. int threshold = 500;
  361. for (int y = 0; y < height; y++)
  362. {
  363. sourceIndex = y * sourceData.Stride;
  364. destinationIndex = y * destinationData.Stride;
  365. destinationValue = 0;
  366. pixelValue = 128;
  367. for (int x = 0; x < width; x++)
  368. {
  369. pixelTotal = sourceBuffer[sourceIndex + 1] +
  370. sourceBuffer[sourceIndex + 2] +
  371. sourceBuffer[sourceIndex + 3];
  372. if (pixelTotal > threshold)
  373. destinationValue += (byte)pixelValue;
  374. if (pixelValue == 1)
  375. {
  376. destinationBuffer[destinationIndex++] = destinationValue;
  377. destinationValue = 0;
  378. pixelValue = 128;
  379. }
  380. else
  381. pixelValue >>= 1;
  382. sourceIndex += 4;
  383. }
  384. if (pixelValue != 128)
  385. destinationBuffer[destinationIndex] = destinationValue;
  386. }
  387. Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize);
  388. destination.UnlockBits(destinationData);
  389. if (source != original)
  390. source.Dispose();
  391. return destination;
  392. }
  393. private void ExportPictureObject(ReportComponentBase pic)
  394. {
  395. WriteLn(Stream, SetPosition(GetLeft(pic.AbsLeft), GetTop(pic.AbsTop)));
  396. Border existingBorder = pic.Border.Clone();
  397. pic.Border.Lines = BorderLines.None;
  398. WriteLn(Stream, DrawPictureObject(pic));
  399. pic.Border = existingBorder;
  400. DrawBorders(pic.Border, pic.AbsLeft, pic.AbsTop, pic.Width, pic.Height);
  401. }
  402. private string DrawPictureObject(ReportComponentBase pic)
  403. {
  404. string result = String.Empty;
  405. if (pic.Width > 0 && pic.Height > 0)
  406. {
  407. float zoom = zplScaleArray[scaleIndex].PageScale;
  408. int picWidth = (int)Math.Ceiling(pic.Width * zoom);
  409. int picHeight = (int)Math.Ceiling(pic.Height * zoom);
  410. using (Bitmap image = new Bitmap(picWidth, picHeight, PixelFormat.Format32bppArgb))
  411. {
  412. DrawObjectOnBitmap(image, pic, false);
  413. result = DrawBWPicture(image);
  414. }
  415. }
  416. return result;
  417. }
  418. private void DrawObjectOnBitmap(Bitmap image, ReportComponentBase pic, bool usePosition)
  419. {
  420. using (Graphics g = Graphics.FromImage(image))
  421. {
  422. using (GraphicCache cache = new GraphicCache())
  423. {
  424. if (!usePosition)
  425. g.Clear(Color.White);
  426. float Left = pic.Width >= 0 ? pic.AbsLeft : pic.AbsLeft + pic.Width;
  427. float Top = pic.Height >= 0 ? pic.AbsTop : pic.AbsTop + pic.Height;
  428. float zoom = zplScaleArray[scaleIndex].PageScale;
  429. if (!usePosition)
  430. g.TranslateTransform(-Left * zoom, -Top * zoom);
  431. pic.Draw(new FRPaintEventArgs(g, zoom, zoom, cache));
  432. }
  433. }
  434. }
  435. private string DrawBWPicture(Bitmap image)
  436. {
  437. string result = String.Empty;
  438. // Convert to BW
  439. using (Bitmap bwImage = ConvertToBitonal(image))
  440. // Save in ZPL
  441. {
  442. result = CompressBWImage(bwImage);
  443. }
  444. return result;
  445. }
  446. private string CompressBWImage(Bitmap image)
  447. {
  448. BitmapData imgData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height),
  449. ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed);
  450. int imageBitsSize = imgData.Stride * imgData.Height;
  451. byte[] picBytes = new byte[imageBitsSize];
  452. Marshal.Copy(imgData.Scan0, picBytes, 0, imageBitsSize);
  453. image.UnlockBits(imgData);
  454. int widthInBytes = (int)Math.Ceiling(image.Width / 8f);
  455. int imageSize = widthInBytes * image.Height;
  456. int freeBits = 8 - image.Width % 8;
  457. byte lastByteMask = (byte)((1 << freeBits) - 1);
  458. StringBuilder zplImage = new StringBuilder(imageSize * 2);
  459. zplImage.AppendFormat("^GFA,{0},{1},{2},",
  460. imageSize.ToString(),
  461. imageSize.ToString(),
  462. widthInBytes.ToString());
  463. StringBuilder previousLine = new StringBuilder();
  464. for (int i = 0; i < image.Height; i++)
  465. {
  466. StringBuilder line = new StringBuilder(widthInBytes * 2);
  467. StringBuilder computedLine = new StringBuilder(widthInBytes);
  468. bool lastZeros = true;
  469. for (int j = 0; j < widthInBytes; j++)
  470. {
  471. byte b = (byte)~(picBytes[i * imgData.Stride + j]);
  472. if (j == widthInBytes - 1)
  473. {
  474. b = (byte)(b & ~lastByteMask);
  475. }
  476. if (b != 0)
  477. {
  478. lastZeros = false;
  479. computedLine.Append(line);
  480. line.Length = 0;
  481. }
  482. else
  483. {
  484. if (!lastZeros)
  485. {
  486. computedLine.Append(line);
  487. line.Length = 0;
  488. }
  489. lastZeros = true;
  490. }
  491. line.Append(b.ToString("X2"));
  492. }
  493. if (lastZeros)
  494. computedLine.Append(",");
  495. else
  496. computedLine.Append(line);
  497. if (previousLine.Equals(computedLine))
  498. zplImage.Append(":");
  499. else
  500. {
  501. zplImage.Append(CompressLine(computedLine));
  502. previousLine = computedLine;
  503. }
  504. }
  505. zplImage.Append("^FS");
  506. return zplImage.ToString();
  507. }
  508. private StringBuilder CompressLine(StringBuilder line)
  509. {
  510. StringBuilder result = new StringBuilder();
  511. char previousChar = '-'; // different initial char
  512. int counter = 0;
  513. for (int i = 0; i < line.Length; i++)
  514. {
  515. char currentChar = line[i]; // this line for better understanding
  516. if (currentChar == previousChar) // char is repeating
  517. {
  518. if (counter == 0) // char is not counted
  519. {
  520. result.Length = result.Length - 1; // remove last char and keep count
  521. counter += 2; // add previous and current
  522. }
  523. else
  524. counter++; // keep count
  525. }
  526. else
  527. {
  528. if (counter > 0) // current char is different and we have repeated before
  529. {
  530. result. // append to result
  531. Append(GetCount(counter)). // count
  532. Append(previousChar). // compressed char
  533. Append(currentChar); // current char
  534. counter = 0; // reset counter
  535. }
  536. else
  537. result.Append(currentChar); // just add current char to result
  538. previousChar = currentChar; // save current char as previous
  539. }
  540. }
  541. if (counter > 0)
  542. {
  543. result.Append(GetCount(counter)).Append(previousChar);
  544. }
  545. return result;
  546. }
  547. private StringBuilder GetCount(int counter)
  548. {
  549. StringBuilder sb = new StringBuilder();
  550. int remainder = counter;
  551. int index = counts.Length - 1;
  552. while (remainder > 0 && index >= 0)
  553. {
  554. if (counts[index] <= remainder)
  555. {
  556. sb.Append(countTable[counts[index]]);
  557. remainder -= counts[index];
  558. }
  559. index--;
  560. }
  561. return sb;
  562. }
  563. /// <summary>
  564. /// Exports the LineObject.
  565. /// </summary>
  566. /// <param name="lineObject"></param>
  567. private void ExportLineObject(LineObject lineObject)
  568. {
  569. if (lineObject.Width == 0 || lineObject.Height == 0)
  570. ExportRectangle(lineObject.AbsLeft,
  571. lineObject.AbsTop,
  572. lineObject.Width,
  573. lineObject.Height,
  574. lineObject.Border.Width);
  575. else
  576. ExportLine(lineObject.AbsLeft,
  577. lineObject.AbsTop,
  578. lineObject.Width,
  579. lineObject.Height,
  580. lineObject.Border.Width);
  581. }
  582. /// <summary>
  583. /// Exports the ShapeObject.
  584. /// </summary>
  585. /// <param name="shapeObject"></param>
  586. private void ExportShapeObject(ShapeObject shapeObject)
  587. {
  588. if (shapeObject.Shape == ShapeKind.Ellipse) //-V3024
  589. ExportEllipse(shapeObject.AbsLeft,
  590. shapeObject.AbsTop,
  591. shapeObject.Width,
  592. shapeObject.Height,
  593. shapeObject.Border.Width);
  594. else
  595. ExportRectangle(shapeObject.AbsLeft,
  596. shapeObject.AbsTop,
  597. shapeObject.Width,
  598. shapeObject.Height,
  599. shapeObject.Border.Width);
  600. }
  601. private void ExportRectangle(float Left, float Top, float Width, float Height, float LineWidth)
  602. {
  603. int left = Width > 0 ? GetLeft(Left) : GetLeft(Left + Width);
  604. int top = Height > 0 ? GetLeft(Top) : GetTop(Top + Height);
  605. int width = (int)Math.Abs(Math.Round(Width * zplScaleArray[scaleIndex].PageScale));
  606. int height = (int)Math.Abs(Math.Round(Height * zplScaleArray[scaleIndex].PageScale));
  607. int lineWidth = (int)Math.Round(LineWidth * zplScaleArray[scaleIndex].PageScale);
  608. WriteLn(Stream, SetPosition(left, top));
  609. WriteLn(Stream, DrawRectangle(width, height, lineWidth));
  610. }
  611. private void ExportEllipse(float Left, float Top, float Width, float Height, float LineWidth)
  612. {
  613. int left = Width > 0 ? GetLeft(Left) : GetLeft(Left + Width);
  614. int top = Height > 0 ? GetLeft(Top) : GetTop(Top + Height);
  615. int width = (int)Math.Abs(Math.Round(Width * zplScaleArray[scaleIndex].PageScale));
  616. int height = (int)Math.Abs(Math.Round(Height * zplScaleArray[scaleIndex].PageScale));
  617. int lineWidth = (int)Math.Round(LineWidth * zplScaleArray[scaleIndex].PageScale);
  618. WriteLn(Stream, SetPosition(left, top));
  619. WriteLn(Stream, DrawEllipse(width, height, lineWidth));
  620. }
  621. private void ExportLine(float Left, float Top, float Width, float Height, float LineWidth)
  622. {
  623. int left = Width > 0 ? GetLeft(Left) : GetLeft(Left + Width);
  624. int top = Height > 0 ? GetLeft(Top) : GetTop(Top + Height);
  625. int width = (int)Math.Abs(Math.Round(Width * zplScaleArray[scaleIndex].PageScale));
  626. int height = (int)Math.Abs(Math.Round(Height * zplScaleArray[scaleIndex].PageScale));
  627. bool direction = (Width > 0 && Height > 0) || (Width < 0 && Height < 0);
  628. int lineWidth = (int)Math.Round(LineWidth * zplScaleArray[scaleIndex].PageScale);
  629. WriteLn(Stream, SetPosition(left, top));
  630. WriteLn(Stream, DrawLine(width, height, lineWidth, direction));
  631. }
  632. /// <summary>
  633. /// Exports the TextObject.
  634. /// </summary>
  635. /// <param name="textObject"></param>
  636. private void ExportTextObject(TextObject textObject)
  637. {
  638. // calc the width of object
  639. int width = GetWidth(textObject.Width, textObject.Height, textObject.Angle);
  640. // calc lines count
  641. // to-do: need fix with AdvancedTextRenderer
  642. int lines = (int)Math.Round(textObject.Height / Math.Round(textObject.Font.Height * DrawUtils.ScreenDpiFX));
  643. // calc line height
  644. int lineHeight = (int)Math.Round(textObject.Font.Height * zplScaleArray[scaleIndex].PageScale);
  645. // calc font height
  646. int fontHeight = (int)Math.Round(Math.Round(textObject.Font.Height * DrawUtils.ScreenDpiFX) * zplScaleArray[scaleIndex].PageScale / fontScale);
  647. // calc font width
  648. int fontWidth = (int)Math.Round((float)fontHeight / 2);
  649. // calc top position of text
  650. int top;
  651. if (textObject.VertAlign == VertAlign.Top)
  652. top = GetTop(textObject.AbsTop);
  653. else if (textObject.VertAlign == VertAlign.Bottom)
  654. top = GetTop(textObject.AbsTop) +
  655. GetHeight(textObject.Width, textObject.Height, textObject.Angle) -
  656. fontHeight * lines;
  657. else
  658. top = GetTop(textObject.AbsTop) +
  659. (int)(GetHeight(textObject.Width, textObject.Height, textObject.Angle) / 2) -
  660. (int)Math.Round((float)(fontHeight * lines) / 2);
  661. // set-up position
  662. //TO DO: for TextObject you need to redo the formula
  663. //The text moves to the left by 10 points because of this I put +10
  664. WriteLn(Stream, SetPosition(GetLeft(textObject.AbsLeft) + 10, top));
  665. // set-up the text attribs
  666. WriteLn(Stream, SetTextAttributes(width, lines, 0, textObject.HorzAlign, 0));
  667. WriteLn(Stream, GetOrientation(textObject.Angle));
  668. // draw text
  669. WriteLn(Stream, DrawText(fontHeight, fontWidth, textObject.Text));
  670. // draw borders
  671. DrawBorders(textObject.Border, textObject.AbsLeft, textObject.AbsTop, textObject.Width, textObject.Height);
  672. }
  673. private void DrawBorders(Border border, float AbsLeft, float AbsTop, float Width, float Height)
  674. {
  675. if (border.Width > 0)
  676. {
  677. if (border.Lines == BorderLines.All)
  678. ExportRectangle(AbsLeft, AbsTop, Width, Height, border.Width);
  679. else
  680. {
  681. int left = Width > 0 ? GetLeft(AbsLeft) : GetLeft(AbsLeft + Width);
  682. int top = Height > 0 ? GetLeft(AbsTop) : GetTop(AbsTop + Height);
  683. int width = (int)Math.Abs(Math.Round(Width * zplScaleArray[scaleIndex].PageScale));
  684. int height = (int)Math.Abs(Math.Round(Height * zplScaleArray[scaleIndex].PageScale));
  685. int lineWidth = (int)Math.Round(border.Width * zplScaleArray[scaleIndex].PageScale);
  686. if ((BorderLines.Top & border.Lines) != 0)
  687. {
  688. lineWidth = (int)Math.Round(border.TopLine.Width * zplScaleArray[scaleIndex].PageScale);
  689. WriteLn(Stream, SetPosition(left, top));
  690. WriteLn(Stream, DrawRectangle(width, 0, lineWidth));
  691. }
  692. if ((BorderLines.Left & border.Lines) != 0)
  693. {
  694. lineWidth = (int)Math.Round(border.LeftLine.Width * zplScaleArray[scaleIndex].PageScale);
  695. WriteLn(Stream, SetPosition(left, top));
  696. WriteLn(Stream, DrawRectangle(0, height, lineWidth));
  697. }
  698. if ((BorderLines.Bottom & border.Lines) != 0)
  699. {
  700. lineWidth = (int)Math.Round(border.BottomLine.Width * zplScaleArray[scaleIndex].PageScale);
  701. WriteLn(Stream, SetPosition(left, top + height));
  702. WriteLn(Stream, DrawRectangle(width, 0, lineWidth));
  703. }
  704. if ((BorderLines.Right & border.Lines) != 0)
  705. {
  706. lineWidth = (int)Math.Round(border.RightLine.Width * zplScaleArray[scaleIndex].PageScale);
  707. WriteLn(Stream, SetPosition(left + width, top));
  708. WriteLn(Stream, DrawRectangle(0, height, lineWidth));
  709. }
  710. }
  711. }
  712. }
  713. private void ExportBarcodeObject(BarcodeObject b)
  714. {
  715. int height = GetHeight(b.Width, b.Height, b.Angle);
  716. WriteLn(Stream, SetPosition(GetLeft(b.AbsLeft), GetTop(b.AbsTop)));
  717. if (!(b.Barcode is BarcodeQR))
  718. {
  719. WriteLn(Stream, "^BY" + GetBarcodeZoom(b.Zoom, b.Barcode) + ",," + height.ToString());
  720. WriteLn(Stream, GetOrientation(b.Angle));
  721. char printLine = (b.ShowText ? 'Y' : 'N');
  722. //TO DO: It makes sense for some barcodes to set the height
  723. if (b.Barcode is Barcode128 || b.Barcode is BarcodeEAN128)
  724. WriteLn(Stream, String.Format("^BC,,{0},N,N", printLine));
  725. else if (b.Barcode is Barcode2of5Industrial)
  726. WriteLn(Stream, String.Format("^BI,,{0},N", printLine));
  727. else if (b.Barcode is Barcode2of5Interleaved)
  728. WriteLn(Stream, String.Format("^B2,,{0},N,N", printLine));
  729. else if (b.Barcode is Barcode2of5Matrix)
  730. WriteLn(Stream, String.Format("^BJ,,{0},N", printLine));
  731. else if (b.Barcode is Barcode39Extended)
  732. WriteLn(Stream, String.Format("^B3,Y,,{0},N", printLine));
  733. else if (b.Barcode is Barcode39)
  734. WriteLn(Stream, String.Format("^B3,N,,{0},N", printLine));
  735. else if (b.Barcode is Barcode93Extended)
  736. WriteLn(Stream, String.Format("^BA,,{0},N,N", printLine));
  737. else if (b.Barcode is Barcode93)
  738. WriteLn(Stream, String.Format("^BA,,{0},N,N", printLine));
  739. else if (b.Barcode is BarcodeCodabar)
  740. WriteLn(Stream, String.Format("^BK,N,{0},N,,", printLine));
  741. else if (b.Barcode is BarcodeUPC_A)
  742. WriteLn(Stream, String.Format("^BU,,{0},N,Y", printLine));
  743. else if (b.Barcode is BarcodeUPC_E0)
  744. WriteLn(Stream, String.Format("^B9,,{0},N,Y", printLine));
  745. else if (b.Barcode is BarcodeUPC_E1)
  746. WriteLn(Stream, String.Format("^B9,,{0},N,Y", printLine));
  747. else if (b.Barcode is BarcodeEAN8)
  748. WriteLn(Stream, String.Format("^B8,,{0},N", printLine));
  749. else if (b.Barcode is BarcodeEAN13)
  750. WriteLn(Stream, String.Format("^BE,,{0},N", printLine));
  751. else if (b.Barcode is BarcodeIntelligentMail)
  752. WriteLn(Stream, String.Format("^BZ,,{0},N,3", printLine));
  753. else if (b.Barcode is BarcodeMSI)
  754. WriteLn(Stream, String.Format("^BM,,,{0},N,N", printLine));
  755. else if (b.Barcode is BarcodePDF417)
  756. WriteLn(Stream, "^B7,,,,,");
  757. else if (b.Barcode is BarcodePlessey)
  758. WriteLn(Stream, String.Format("^BP,,{0},N", printLine));
  759. else if (b.Barcode is BarcodePostNet)
  760. WriteLn(Stream, String.Format("^BZ,,{0},N,0", printLine));
  761. else if (b.Barcode is BarcodeAztec)
  762. WriteLn(Stream, String.Format("^BO,{0},,,,,",
  763. zplScaleArray[scaleIndex].TwoDCodeScale.ToString()));
  764. else if (b.Barcode is BarcodeDatamatrix)
  765. WriteLn(Stream, "^BX,,,,,,");
  766. else if (b.Barcode is BarcodeMaxiCode)
  767. {
  768. BarcodeMaxiCode maxiCode = b.Barcode as BarcodeMaxiCode;
  769. WriteLn(Stream, String.Format("^BD{0},,", maxiCode.Mode.ToString()));
  770. }
  771. WriteLn(Stream, "^FD" + GetZPLText(b.Text) + "^FS");
  772. // to-do BarcodeSupplement2, BarcodeSupplement5, BarcodePharmacode - didn't match
  773. }
  774. else // QR code
  775. {
  776. WriteLn(Stream, "^BY2,2,0");
  777. WriteLn(Stream, String.Format("^BQ,2,{0}",
  778. Math.Round((float)zplScaleArray[scaleIndex].TwoDCodeScale * b.Zoom).ToString()));
  779. WriteLn(Stream, "^FDMA," + GetZPLText(b.Text) + "^FS");
  780. }
  781. }
  782. /// <summary>
  783. /// Gets the position of object in ZPL code.
  784. /// </summary>
  785. /// <param name="left"></param>
  786. /// <param name="top"></param>
  787. /// <returns></returns>
  788. private string SetPosition(int left, int top)
  789. {
  790. return String.Format("^FO{0},{1}", left, top);
  791. }
  792. /// <summary>
  793. /// Gets the text attributes in ZPL code.
  794. /// </summary>
  795. /// <param name="width"></param>
  796. /// <param name="lines"></param>
  797. /// <param name="leading"></param>
  798. /// <param name="horizAlign"></param>
  799. /// <param name="gap"></param>
  800. /// <returns></returns>
  801. private string SetTextAttributes(int width, int lines, int leading, HorzAlign horizAlign, int gap)
  802. {
  803. return String.Format("^FB{0},{1},{2},{3},{4}",
  804. width,
  805. lines,
  806. leading,
  807. GetHorizAlign(horizAlign),
  808. gap
  809. );
  810. }
  811. /// <summary>
  812. /// Gets the text with font width and height in ZPL code.
  813. /// </summary>
  814. /// <param name="fontHeight"></param>
  815. /// <param name="fontWidth"></param>
  816. /// <param name="text"></param>
  817. /// <returns></returns>
  818. private string DrawText(int fontHeight, int fontWidth, string text)
  819. {
  820. return String.Format("^A{0},{1},{2}^FD{3}^FS",
  821. font,
  822. fontHeight,
  823. fontWidth,
  824. GetZPLText(text)
  825. );
  826. }
  827. /// <summary>
  828. /// Gets the horiz align in ZPL code.
  829. /// </summary>
  830. /// <param name="horizAlign"></param>
  831. /// <returns></returns>
  832. private string GetHorizAlign(HorzAlign horizAlign)
  833. {
  834. switch (horizAlign)
  835. {
  836. case HorzAlign.Left:
  837. return "L";
  838. case HorzAlign.Center:
  839. return "C";
  840. case HorzAlign.Right:
  841. return "R";
  842. default:
  843. return "J";
  844. }
  845. }
  846. /// <summary>
  847. /// Gets the rectangle in ZPL code.
  848. /// </summary>
  849. /// <param name="width"></param>
  850. /// <param name="height"></param>
  851. /// <param name="lineWidth"></param>
  852. /// <returns></returns>
  853. private string DrawRectangle(int width, int height, int lineWidth)
  854. {
  855. return String.Format((version == ZplVersions.ZPL2 ? "^LRN" : "") + "^GB{0},{1},{2}^FS",
  856. width,
  857. height,
  858. lineWidth);
  859. }
  860. private string DrawEllipse(int width, int height, int lineWidth)
  861. {
  862. return String.Format("^GE{0},{1},{2}^FS",
  863. width,
  864. height,
  865. lineWidth);
  866. }
  867. private string DrawLine(int width, int height, int lineWidth, bool direction)
  868. {
  869. return String.Format("^GD{0},{1},{2},,{3}^FS",
  870. width.ToString(),
  871. height.ToString(),
  872. lineWidth.ToString(),
  873. direction ? "L" : "R");
  874. }
  875. #endregion Private Methods
  876. #region Protected Methods
  877. /// <inheritdoc/>
  878. protected override void Start()
  879. {
  880. base.Start();
  881. // Init of scale index.
  882. switch (density)
  883. {
  884. case ZplDensity.d6_dpmm_152_dpi:
  885. scaleIndex = 0;
  886. break;
  887. case ZplDensity.d8_dpmm_203_dpi:
  888. scaleIndex = 1;
  889. break;
  890. case ZplDensity.d12_dpmm_300_dpi:
  891. scaleIndex = 2;
  892. break;
  893. case ZplDensity.d24_dpmm_600_dpi:
  894. scaleIndex = 3;
  895. break;
  896. }
  897. WriteLn(Stream, printerInit);
  898. }
  899. /// <inheritdoc/>
  900. protected override void Finish()
  901. {
  902. WriteLn(Stream, printerFinish);
  903. }
  904. /// <inheritdoc/>
  905. protected override string GetFileFilter()
  906. {
  907. return new MyRes("FileFilters").Get("ZplFile");
  908. }
  909. /// <inheritdoc/>
  910. protected override void ExportPageBegin(ReportPage page)
  911. {
  912. base.ExportPageBegin(page);
  913. WriteLn(Stream, String.Format("^XA{0}", codePage));
  914. WriteLn(Stream, pageInit);
  915. leftMargin = page.LeftMargin * millimeters * zplScaleArray[scaleIndex].PageScale;
  916. topMargin = page.TopMargin * millimeters * zplScaleArray[scaleIndex].PageScale;
  917. if (printAsBitmap)
  918. {
  919. pageBitmap = new Bitmap(
  920. (int)Math.Round(ExportUtils.GetPageWidth(page) * millimeters * zplScaleArray[scaleIndex].PageScale),
  921. (int)Math.Round(ExportUtils.GetPageHeight(page) * millimeters * zplScaleArray[scaleIndex].PageScale),
  922. PixelFormat.Format32bppArgb);
  923. using (Graphics g = Graphics.FromImage(pageBitmap))
  924. g.Clear(Color.White);
  925. }
  926. }
  927. /// <inheritdoc/>
  928. protected override void ExportPageEnd(ReportPage page)
  929. {
  930. if (printAsBitmap)
  931. {
  932. WriteLn(Stream, SetPosition((int)leftMargin, (int)topMargin));
  933. WriteLn(Stream, DrawBWPicture(pageBitmap));
  934. pageBitmap.Dispose();
  935. }
  936. base.ExportPageEnd(page);
  937. WriteLn(Stream, "^XZ");
  938. }
  939. /// <inheritdoc/>
  940. protected override void ExportBand(BandBase band)
  941. {
  942. base.ExportBand(band);
  943. if (band.Parent == null)
  944. return;
  945. if (printAsBitmap)
  946. DrawObjectOnBitmap(pageBitmap, band, true);
  947. foreach (Base c in band.ForEachAllConvectedObjects(this))
  948. {
  949. if (c is ReportComponentBase && (c as ReportComponentBase).Exportable)
  950. {
  951. ReportComponentBase bandObject = c as ReportComponentBase;
  952. if (printAsBitmap)
  953. DrawObjectOnBitmap(pageBitmap, bandObject, true);
  954. else
  955. {
  956. if (bandObject is CellularTextObject)
  957. bandObject = (bandObject as CellularTextObject).GetTable();
  958. if (bandObject is TableCell)
  959. continue;
  960. else if (bandObject is TableBase)
  961. ExportTableObject(bandObject as TableBase);
  962. else if (bandObject is TextObject)
  963. ExportTextObject(bandObject as TextObject);
  964. else if (bandObject is ShapeObject)
  965. ExportShapeObject(bandObject as ShapeObject);
  966. else if (bandObject is LineObject)
  967. ExportLineObject(bandObject as LineObject);
  968. else if (bandObject is RFIDLabel)
  969. ExportRFIDLabel(bandObject as RFIDLabel);
  970. else if (bandObject is BarcodeObject)
  971. ExportBarcodeObject(bandObject as BarcodeObject);
  972. else
  973. ExportPictureObject(bandObject);
  974. }
  975. }
  976. }
  977. }
  978. private void ExportRFIDLabel(RFIDLabel rfidLabel)
  979. {
  980. //data
  981. if (!string.IsNullOrEmpty(rfidLabel.EpcBank.Data))
  982. {
  983. //RF parametrs
  984. // 1. R - read, W - write, S - password
  985. // 2. Format H - Hex, A - ASCII, E - EPC
  986. // 3. start block in bank
  987. // 4. number of bytes to read or write
  988. // 5. index of bank. 0 - Reserved(passwords), 1 - EPC, 2 - TID, 3 - User, E - EPC 20th bit, A - EPC 20th bit with auto adjust bits
  989. if (!string.IsNullOrEmpty(rfidLabel.EpcFormat))
  990. {
  991. WriteLn(Stream, $"^RB{rfidLabel.EpcFormat}^FS");
  992. WriteLn(Stream, $"^RFW,E^FD{rfidLabel.EpcBank.Data}^FS");
  993. }
  994. else if (rfidLabel.RewriteEPCbank)
  995. WriteLn(Stream, $"^RFW,{(char)rfidLabel.EpcBank.DataFormat},{rfidLabel.EpcBank.Offset},{rfidLabel.EpcBank.CountByte},1^FD{rfidLabel.EpcBank.Data}^FS");//2,,A/E
  996. else if (rfidLabel.UseAdjustForEPC)
  997. WriteLn(Stream, $"^RFW,{(char)rfidLabel.EpcBank.DataFormat},2,,E^FD{rfidLabel.EpcBank.Data}^FS");
  998. else
  999. WriteLn(Stream, $"^RFW,{(char)rfidLabel.EpcBank.DataFormat},2,,A^FD{rfidLabel.EpcBank.Data}^FS");
  1000. }
  1001. if (!string.IsNullOrEmpty(rfidLabel.TIDBank.Data))
  1002. {
  1003. WriteLn(Stream, $"^RFW,{(char)rfidLabel.TIDBank.DataFormat},{rfidLabel.TIDBank.Offset},{rfidLabel.TIDBank.CountByte},2^FD{rfidLabel.TIDBank.Data}^FS");
  1004. }
  1005. if (!string.IsNullOrEmpty(rfidLabel.UserBank.Data))
  1006. {
  1007. WriteLn(Stream, $"^RFW,{(char)rfidLabel.UserBank.DataFormat},{rfidLabel.UserBank.CountByte},{rfidLabel.UserBank.CountByte},3^FD{rfidLabel.UserBank.Data}^FS");
  1008. }
  1009. if (!string.IsNullOrEmpty(rfidLabel.AccessPassword) && rfidLabel.AccessPassword != "00000000" || !string.IsNullOrEmpty(rfidLabel.KillPassword) && rfidLabel.KillPassword != "00000000")
  1010. {
  1011. WriteLn(Stream, $"^RFW,H,P^FD{rfidLabel.AccessPassword}{(string.IsNullOrEmpty(rfidLabel.KillPassword) ? "" : $",{rfidLabel.KillPassword}")}^FS");
  1012. }
  1013. if (!string.IsNullOrEmpty(rfidLabel.AccessPassword) && rfidLabel.AccessPassword != "00000000")
  1014. WriteLn(Stream, $"^RLM,{(char)rfidLabel.LockKillPassword},{(char)rfidLabel.LockAccessPassword},{(char)rfidLabel.LockEPCBank},{(char)rfidLabel.LockUserBank}");
  1015. if (rfidLabel.CountPermaLock > 0)
  1016. WriteLn(Stream, $"^RLB{rfidLabel.StartPermaLock},{rfidLabel.CountPermaLock}");
  1017. WriteLn(Stream, $"^RS,,,,{rfidLabel.ErrorHandle}");
  1018. if (rfidLabel.AdaptiveAntenna)
  1019. WriteLn(Stream, "^RR,1");
  1020. if (rfidLabel.ReadPower != 16 || rfidLabel.WritePower != 16)
  1021. {
  1022. WriteLn(Stream, $"^RW{rfidLabel.ReadPower},{rfidLabel.WritePower}^FS");
  1023. }
  1024. if (printAsBitmap)
  1025. DrawObjectOnBitmap(pageBitmap, rfidLabel, true);
  1026. foreach (Base c in rfidLabel.ForEachAllConvectedObjects(this))
  1027. {
  1028. if (c is ReportComponentBase && (c as ReportComponentBase).Exportable)
  1029. {
  1030. ReportComponentBase bandObject = c as ReportComponentBase;
  1031. if (printAsBitmap)
  1032. DrawObjectOnBitmap(pageBitmap, bandObject, true);
  1033. else
  1034. {
  1035. if (bandObject is CellularTextObject)
  1036. bandObject = (bandObject as CellularTextObject).GetTable();
  1037. if (bandObject is TableCell)
  1038. continue;
  1039. else if (bandObject is TableBase)
  1040. ExportTableObject(bandObject as TableBase);
  1041. else if (bandObject is TextObject)
  1042. ExportTextObject(bandObject as TextObject);
  1043. else if (bandObject is ShapeObject)
  1044. ExportShapeObject(bandObject as ShapeObject);
  1045. else if (bandObject is LineObject)
  1046. ExportLineObject(bandObject as LineObject);
  1047. else if (bandObject is RFIDLabel)
  1048. ExportRFIDLabel(bandObject as RFIDLabel);
  1049. else if (bandObject is BarcodeObject)
  1050. ExportBarcodeObject(bandObject as BarcodeObject);
  1051. else
  1052. ExportPictureObject(bandObject);
  1053. }
  1054. }
  1055. }
  1056. }
  1057. #endregion Protected Methods
  1058. #region Public Methods
  1059. /// <inheritdoc/>
  1060. public override void Serialize(FRWriter writer)
  1061. {
  1062. base.Serialize(writer);
  1063. // Options
  1064. writer.WriteValue("Density", Density);
  1065. writer.WriteValue("Version", Version);
  1066. writer.WriteBool("PrintAsBitmap", PrintAsBitmap);
  1067. writer.WriteValue("FontScale", FontScale);
  1068. writer.WriteValue("BarcodeScale", BarcodeScale);
  1069. // end
  1070. }
  1071. #endregion Public Methods
  1072. /// <summary>
  1073. /// Initializes a new instance of the <see cref="ZplExport"/> class.
  1074. /// </summary>
  1075. public ZplExport()
  1076. {
  1077. countTable = new Dictionary<int, char>();
  1078. countTable.Add(1, 'G');
  1079. countTable.Add(2, 'H');
  1080. countTable.Add(3, 'I');
  1081. countTable.Add(4, 'J');
  1082. countTable.Add(5, 'K');
  1083. countTable.Add(6, 'L');
  1084. countTable.Add(7, 'M');
  1085. countTable.Add(8, 'N');
  1086. countTable.Add(9, 'O');
  1087. countTable.Add(10, 'P');
  1088. countTable.Add(11, 'Q');
  1089. countTable.Add(12, 'R');
  1090. countTable.Add(13, 'S');
  1091. countTable.Add(14, 'T');
  1092. countTable.Add(15, 'U');
  1093. countTable.Add(16, 'V');
  1094. countTable.Add(17, 'W');
  1095. countTable.Add(18, 'X');
  1096. countTable.Add(19, 'Y');
  1097. countTable.Add(20, 'g');
  1098. countTable.Add(40, 'h');
  1099. countTable.Add(60, 'i');
  1100. countTable.Add(80, 'j');
  1101. countTable.Add(100, 'k');
  1102. countTable.Add(120, 'l');
  1103. countTable.Add(140, 'm');
  1104. countTable.Add(160, 'n');
  1105. countTable.Add(180, 'o');
  1106. countTable.Add(200, 'p');
  1107. countTable.Add(220, 'q');
  1108. countTable.Add(240, 'r');
  1109. countTable.Add(260, 's');
  1110. countTable.Add(280, 't');
  1111. countTable.Add(300, 'u');
  1112. countTable.Add(320, 'v');
  1113. countTable.Add(340, 'w');
  1114. countTable.Add(360, 'x');
  1115. countTable.Add(380, 'y');
  1116. countTable.Add(400, 'z');
  1117. // prepare for indexed access to keys
  1118. counts = new int[countTable.Count];
  1119. countTable.Keys.CopyTo(counts, 0);
  1120. }
  1121. }
  1122. }