HpglExport.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  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.Drawing2D;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Text;
  11. namespace FastReport.Export.Hpgl
  12. {
  13. /// <summary>
  14. /// Variants of filling
  15. /// </summary>
  16. public enum HpglFillMode
  17. {
  18. /// <summary>
  19. /// Solid filling of hatch and solid objects
  20. /// </summary>
  21. Solid,
  22. /// <summary>
  23. /// Draw only borders of hatch and solid objects
  24. /// </summary>
  25. Border
  26. }
  27. public partial class HpglExport : ExportBase
  28. {
  29. #region Fields
  30. private string path;
  31. private string fileNameWOext;
  32. private string extension;
  33. private string pageFileName;
  34. private int currentPage;
  35. private HpglDocument hpglDocument;
  36. private float pageHeight;
  37. private float pageWidth;
  38. private IGraphics hpglMeasureGraphics;
  39. private HpglFillMode fillMode;
  40. private float barcodesGap;
  41. #endregion // Fields
  42. /// <summary>
  43. /// Gets or sets lines/polygons gap for barcodes object
  44. /// </summary>
  45. public float BarcodesGap
  46. {
  47. get { return barcodesGap; }
  48. set { barcodesGap = value; }
  49. }
  50. /// <summary>
  51. /// Gets or sets the hpgl objects fill mode
  52. /// </summary>
  53. public HpglFillMode FillMode
  54. {
  55. get { return fillMode; }
  56. set { fillMode = value; }
  57. }
  58. /// <summary>
  59. /// Initializes a new instance of the <see cref="HpglExport"/> class.
  60. /// </summary>
  61. public HpglExport()
  62. {
  63. hpglDocument = new HpglDocument();
  64. HasMultipleFiles = true;
  65. hpglMeasureGraphics = new GdiGraphics(new Bitmap(1, 1));
  66. }
  67. #region Private Methods
  68. /// <summary>
  69. /// Save hpgl file.
  70. /// </summary>
  71. private void Save(string filename)
  72. {
  73. string hpglString = hpglDocument.ToString();
  74. File.WriteAllText(filename, hpglString);
  75. }
  76. /// <summary>
  77. /// Save hpgl stream.
  78. /// </summary>
  79. private void Save(Stream stream)
  80. {
  81. string hpglString = hpglDocument.ToString();
  82. byte[] encodedDfx = Encoding.UTF8.GetBytes(hpglString);
  83. stream.Write(encodedDfx, 0, encodedDfx.Length);
  84. }
  85. /// <summary>
  86. /// Add BandObject.
  87. /// </summary>
  88. private void AddBandObject(BandBase band)
  89. {
  90. using (TextObject newObj = new TextObject())
  91. {
  92. newObj.Left = band.AbsLeft;
  93. newObj.Top = band.AbsTop;
  94. newObj.Width = band.Width;
  95. newObj.Height = band.Height;
  96. newObj.Fill = band.Fill;
  97. newObj.Border = band.Border;
  98. AddTextObject(newObj, true);
  99. }
  100. }
  101. private void AddTable(TableBase table)
  102. {
  103. float y = 0;
  104. for (int i = 0; i < table.RowCount; i++)
  105. {
  106. float x = 0;
  107. for (int j = 0; j < table.ColumnCount; j++)
  108. {
  109. if (!table.IsInsideSpan(table[j, i]))
  110. {
  111. TableCell textcell = table[j, i];
  112. textcell.Left = x;
  113. textcell.Top = y;
  114. Border oldBorder = textcell.Border.Clone();
  115. textcell.Border.Lines = BorderLines.None;
  116. if (textcell is TextObject)
  117. AddTextObject(textcell as TextObject, /*false*/ true);
  118. //else
  119. // AddPictureObject(textcell as ReportComponentBase);
  120. textcell.Border = oldBorder;
  121. AddBorder(textcell.Border, textcell.AbsLeft, textcell.AbsTop, textcell.Width, textcell.Height);
  122. }
  123. x += (table.Columns[j]).Width;
  124. }
  125. y += (table.Rows[i]).Height;
  126. }
  127. }
  128. /// <summary>
  129. /// Add TextObject.
  130. /// </summary>
  131. private void AddTextObject(TextObject obj, bool drawBorder)
  132. {
  133. float AbsLeft = obj.AbsLeft;
  134. float AbsTop = pageHeight * Units.Millimeters - obj.AbsTop;
  135. float Width = obj.Width;
  136. float Height = obj.Height;
  137. bool transformNeeded = obj.Angle != 0 || obj.FontWidthRatio != 1;
  138. if (transformNeeded)
  139. return;
  140. // draw background
  141. //if (obj.FillColor != Color.Transparent)
  142. // AddRectangleFill(AbsLeft, AbsTop, Width, Height, obj.FillColor);
  143. // WIP: draw text here
  144. //if (!string.IsNullOrWhiteSpace(obj.Text))
  145. //{
  146. // GraphicsPath myPath = new GraphicsPath();
  147. // // Set up all the string parameters.
  148. // string stringText = obj.Text;
  149. // FontFamily family = obj.Font.FontFamily;
  150. // int fontStyle = (int)obj.Font.Style;
  151. // float emSize = obj.Font.Size;
  152. // PointF origin = new PointF(0, 0);
  153. // StringFormat format = StringFormat.GenericDefault;
  154. // // Add the string to the path.
  155. // myPath.AddString(stringText,
  156. // family,
  157. // fontStyle,
  158. // emSize,
  159. // origin,
  160. // format);
  161. // AddGraphicsPath(myPath, obj.TextColor, 1, LineStyle.Solid, AbsLeft + Width / 2, AbsTop - Height / 2, true, true);
  162. // }
  163. // if (obj.Clip)
  164. if (obj.Underlines)
  165. AddUnderlines(obj);
  166. if (!String.IsNullOrEmpty(obj.Text))
  167. {
  168. using (Font f = new Font(obj.Font.FontFamily, obj.Font.Size, obj.Font.Style))
  169. {
  170. RectangleF textRect = new RectangleF(
  171. obj.AbsLeft + obj.Padding.Left,
  172. obj.AbsTop + obj.Padding.Top,
  173. obj.Width - obj.Padding.Horizontal,
  174. obj.Height - obj.Padding.Vertical);
  175. // break the text to paragraphs, lines, words and runs
  176. StringFormat format = obj.GetStringFormat(Report.GraphicCache /*cache*/, 0);
  177. Brush textBrush = Report.GraphicCache.GetBrush(obj.TextColor);
  178. AdvancedTextRenderer renderer = new AdvancedTextRenderer(obj.Text, hpglMeasureGraphics, f, textBrush, null,
  179. textRect, format, obj.HorzAlign, obj.VertAlign, obj.LineHeight, obj.Angle, obj.FontWidthRatio,
  180. obj.ForceJustify, obj.Wysiwyg, obj.HasHtmlTags, false, Zoom, Zoom, obj.InlineImageCache);
  181. float w = f.Height * 0.1f; // to match .net char X offset
  182. // invert offset in case of rtl
  183. if (obj.RightToLeft)
  184. w = -w;
  185. // we don't need this offset if text is centered
  186. if (obj.HorzAlign == HorzAlign.Center)
  187. w = 0;
  188. //XmlElement textContainer = DrawTextContainer(obj.AbsLeft, obj.AbsTop, f, obj.TextColor);
  189. // transform, rotate and scale coordinates if needed
  190. if (transformNeeded)
  191. {
  192. textRect.X = -textRect.Width / 2;
  193. textRect.Y = -textRect.Height / 2;
  194. float angle = (float)(obj.Angle * Math.PI / 180);
  195. float x = (obj.AbsLeft + obj.Width / 2);
  196. float y = (obj.AbsTop + obj.Height / 2);
  197. //AppndAngle(textContainer, angle, x, y);
  198. }
  199. // render
  200. foreach (AdvancedTextRenderer.Paragraph paragraph in renderer.Paragraphs)
  201. foreach (AdvancedTextRenderer.Line line in paragraph.Lines)
  202. {
  203. float lineOffset = 0;
  204. float lineHeight = line.CalcHeight();
  205. if (lineHeight > obj.Height)
  206. {
  207. if (obj.VertAlign == VertAlign.Center)
  208. lineOffset = -lineHeight / 2;//-
  209. else if (obj.VertAlign == VertAlign.Bottom)
  210. lineOffset = -lineHeight;//-
  211. }
  212. /* foreach (RectangleF rect in line.Underlines)
  213. {
  214. // DrawPDFUnderline(ObjectFontNumber, f, rect.Left, rect.Top, rect.Width, w,
  215. // obj.TextColor, transformNeeded, sb);
  216. }*/
  217. /*foreach (RectangleF rect in line.Strikeouts)
  218. {
  219. DrawStrikeout(f, rect.Left, rect.Top, rect.Width, w, obj.TextColor, transformNeeded);
  220. }*/
  221. foreach (AdvancedTextRenderer.Word word in line.Words)
  222. {
  223. //if (renderer.HtmlTags)
  224. // foreach (AdvancedTextRenderer.Run run in word.Runs)
  225. // using (Font fnt = run.GetFont())
  226. // {
  227. // AppndTspan(textContainer, run.Left, run.Top + lineOffset + lineHeight * 72 / 96/*magic*/,
  228. // w, run.Text, f);
  229. // }
  230. //else
  231. //AppndTspan(textContainer, word.Left, word.Top + lineOffset + lineHeight * 72 / 96/*magic*/,
  232. // w, word.Text, f);
  233. // --
  234. if (!string.IsNullOrWhiteSpace(word.Text))
  235. {
  236. GraphicsPath myPath = new GraphicsPath();
  237. // Set up all the string parameters.
  238. string stringText = word.Text;
  239. FontFamily family = obj.Font.FontFamily;
  240. int fontStyle = (int)obj.Font.Style;
  241. float emSize = obj.Font.Size;
  242. PointF origin = new PointF(0, 0 /*+ lineOffset + lineHeight*//*magic*/);
  243. // StringFormat format = StringFormat.GenericDefault;
  244. // Add the string to the path.
  245. myPath.AddString(stringText,
  246. family,
  247. fontStyle,
  248. emSize,
  249. origin,
  250. StringFormat.GenericDefault);
  251. float x = word.Left + w + (transformNeeded ? obj.AbsLeft : 0);
  252. float y = pageHeight * Units.Millimeters - word.Top - lineOffset - (transformNeeded ? obj.AbsTop : 0);
  253. float centerX = (obj.Width / 2) / Units.Millimeters;
  254. float centerY = (obj.Height / 2) / Units.Millimeters;
  255. PointF center = new PointF(centerX, centerY);
  256. float angle = (float)(obj.Angle * Math.PI / 180);
  257. AddGraphicsPath(myPath, obj.TextColor, 1 / 100.0f, LineStyle.Solid, x,
  258. y, true, true, angle, center);
  259. }
  260. // --
  261. }
  262. }
  263. }
  264. }
  265. if (drawBorder)
  266. AddBorder(obj.Border, obj.AbsLeft, obj.AbsTop, obj.Width, obj.Height);
  267. }
  268. #endregion // Private Methods
  269. #region Protected Methods
  270. /// <inheritdoc/>
  271. protected override void Start()
  272. {
  273. currentPage = 0;
  274. GeneratedStreams = new List<Stream>();
  275. if (FileName != "" && FileName != null)
  276. {
  277. path = Path.GetDirectoryName(FileName);
  278. fileNameWOext = Path.GetFileNameWithoutExtension(FileName);
  279. extension = Path.GetExtension(FileName);
  280. }
  281. else
  282. fileNameWOext = "hpglReport";
  283. }
  284. /// <summary>
  285. /// Begin exporting of page
  286. /// </summary>
  287. /// <param name="page"></param>
  288. protected override void ExportPageBegin(ReportPage page)
  289. {
  290. base.ExportPageBegin(page);
  291. pageHeight = ExportUtils.GetPageHeight(page);
  292. pageWidth = ExportUtils.GetPageWidth(page);
  293. hpglDocument = new HpglDocument();
  294. hpglDocument.Start(new SizeF(4000, 4000));
  295. // page borders
  296. if (page.Border.Lines != BorderLines.None)
  297. {
  298. using (TextObject pageBorder = new TextObject())
  299. {
  300. pageBorder.Border = page.Border;
  301. pageBorder.Left = 0;
  302. pageBorder.Top = 0;
  303. pageBorder.Width = (pageWidth - page.LeftMargin - page.RightMargin);
  304. pageBorder.Height = (pageHeight - page.TopMargin - page.BottomMargin);
  305. // AddTextObject(pageBorder, true);
  306. }
  307. }
  308. if (path != null && path != "")
  309. pageFileName = Path.Combine(path, fileNameWOext + currentPage.ToString() + extension);
  310. else
  311. pageFileName = null;
  312. }
  313. /// <summary>
  314. /// Export of Band
  315. /// </summary>
  316. /// <param name="band"></param>
  317. protected override void ExportBand(BandBase band)
  318. {
  319. base.ExportBand(band);
  320. ExportObj(band);
  321. foreach (Base c in band.ForEachAllConvectedObjects(this))
  322. {
  323. ExportObj(c);
  324. }
  325. }
  326. /// <summary>
  327. /// End exporting
  328. /// </summary>
  329. /// <param name="page"></param>
  330. protected override void ExportPageEnd(ReportPage page)
  331. {
  332. base.ExportPageEnd(page);
  333. //hpglDocument.Finish();
  334. if (HasMultipleFiles)
  335. {
  336. //export to MultipleFiles
  337. if (Directory.Exists(path) && !string.IsNullOrEmpty(FileName))
  338. {
  339. // desktop mode
  340. if (currentPage == 0)
  341. {
  342. // save first page in parent Stream
  343. Save(Stream);
  344. Stream.Position = 0;
  345. GeneratedStreams.Add(Stream);
  346. GeneratedFiles.Add(FileName);
  347. }
  348. else
  349. {
  350. // save all page after first in files
  351. Save(pageFileName);
  352. GeneratedFiles.Add(pageFileName);
  353. }
  354. }
  355. else if (string.IsNullOrEmpty(path))
  356. {
  357. if (currentPage == 0)
  358. {
  359. // save first page in parent Stream
  360. Save(Stream);
  361. Stream.Position = 0;
  362. GeneratedStreams.Add(Stream);
  363. GeneratedFiles.Add(FileName);
  364. }
  365. else
  366. {
  367. // server mode, save in internal stream collection
  368. MemoryStream pageStream = new MemoryStream();
  369. Save(pageStream);
  370. pageStream.Position = 0;
  371. GeneratedStreams.Add(pageStream);
  372. GeneratedFiles.Add(pageFileName);
  373. }
  374. }
  375. }
  376. // increment page number
  377. currentPage++;
  378. }
  379. /// <inheritdoc/>
  380. protected override void Finish()
  381. {
  382. if (!HasMultipleFiles)
  383. {
  384. Save(Stream);
  385. Stream.Position = 0;
  386. GeneratedFiles.Add(FileName);
  387. }
  388. GeneratedFiles.Clear();
  389. GeneratedStreams.Clear();
  390. }
  391. /// <inheritdoc/>
  392. protected override string GetFileFilter()
  393. {
  394. return new MyRes("FileFilters").Get("HpglFile");
  395. }
  396. #endregion
  397. /// <inheritdoc/>
  398. public override void Serialize(FRWriter writer)
  399. {
  400. base.Serialize(writer);
  401. writer.WriteBool("HasMultipleFiles", HasMultipleFiles);
  402. writer.WriteValue("FillMode", FillMode);
  403. }
  404. /// <summary>
  405. /// Export all report objects
  406. /// </summary>
  407. /// <param name="c"></param>
  408. public virtual void ExportObj(Base c)
  409. {
  410. if (c is ReportComponentBase && (c as ReportComponentBase).Exportable)
  411. {
  412. ReportComponentBase obj = c as ReportComponentBase;
  413. if (obj is CellularTextObject)
  414. obj = (obj as CellularTextObject).GetTable();
  415. if (obj is TableCell) return;
  416. else if (obj is TableBase)
  417. {
  418. TableBase table = obj as TableBase;
  419. if (table.ColumnCount > 0 && table.RowCount > 0)
  420. {
  421. using (TextObject tableback = new TextObject())
  422. {
  423. tableback.Border = table.Border;
  424. tableback.Fill = table.Fill;
  425. tableback.FillColor = table.FillColor;
  426. tableback.Left = table.AbsLeft;
  427. tableback.Top = table.AbsTop;
  428. float tableWidth = 0;
  429. float tableHeight = 0;
  430. for (int i = 0; i < table.ColumnCount; i++)
  431. tableWidth += table[i, 0].Width;
  432. for (int i = 0; i < table.RowCount; i++)
  433. tableHeight += table.Rows[i].Height;
  434. tableback.Width = (tableWidth < table.Width) ? tableWidth : table.Width;
  435. tableback.Height = tableHeight;
  436. //AddTextObject(tableback, false);
  437. // draw table border
  438. // AddBorder(tableback.Border, tableback.AbsLeft, tableback.AbsTop, tableback.Width, tableback.Height);
  439. }
  440. // draw cells
  441. AddTable(table);
  442. }
  443. }
  444. else if (obj is TextObject)
  445. AddTextObject(obj as TextObject, true);
  446. else if (obj is BandBase)
  447. AddBandObject(obj as BandBase);
  448. else if (obj is LineObject)
  449. AddLine(obj as LineObject);
  450. else if (obj is PolygonObject)
  451. AddPolygon(obj as PolygonObject);
  452. else if (obj is PolyLineObject)
  453. AddPolyLine(obj as PolyLineObject);
  454. else if (obj is ShapeObject)
  455. AddShape(obj as ShapeObject);
  456. //#if DOTNET_4
  457. // else if (obj is SVGObject)
  458. // AddBarcodeFromSvg(obj as BarcodeObject);
  459. //#endif
  460. else if (obj is BarcodeObject)
  461. AddBarcode(obj as BarcodeObject);
  462. //#if DOTNET_4
  463. // else if (obj is SVGObject)
  464. // AddSVGObject(c as SVGObject);
  465. //#endif
  466. // else
  467. // AddPictureObject(obj);
  468. }
  469. }
  470. private void AddBarcode(BarcodeObject barcodeObject)
  471. {
  472. using (var renderer = new HpglGraphicsRenderer(hpglDocument, fillMode, BarcodesGap))
  473. {
  474. bool error = false;
  475. string errorText = "";
  476. if (string.IsNullOrEmpty(barcodeObject.Text))
  477. {
  478. error = true;
  479. errorText = barcodeObject.NoDataText;
  480. }
  481. else
  482. try
  483. {
  484. // That line makes barcode not an invalid
  485. barcodeObject.UpdateAutoSize();
  486. }
  487. catch (Exception ex)
  488. {
  489. error = true;
  490. errorText = ex.Message;
  491. }
  492. if (!error)
  493. barcodeObject.Barcode.DrawBarcode(renderer, new RectangleF(barcodeObject.AbsLeft / Units.Millimeters,
  494. pageHeight - barcodeObject.AbsTop / Units.Millimeters, barcodeObject.Width / Units.Millimeters, barcodeObject.Height / Units.Millimeters));
  495. else
  496. {
  497. renderer.DrawString(errorText, DrawUtils.DefaultReportFont, Brushes.Red,
  498. new RectangleF(0, 0, barcodeObject.Width, barcodeObject.Height));
  499. }
  500. //barcodeObject.Barcode.DrawBarcode(renderer, new RectangleF(barcodeObject.AbsLeft,
  501. // barcodeObject.AbsTop, barcodeObject.Width, barcodeObject.Height));
  502. }
  503. }
  504. private string FloatToString(double flt)
  505. {
  506. return ExportUtils.FloatToString(flt);
  507. }
  508. }
  509. }