DxfExport.cs 22 KB

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