123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- using System.Collections.Generic;
- using System.IO;
- using System.Collections;
- using System.Drawing.Imaging;
- using FastReport.Utils;
- using System.Drawing;
- namespace FastReport.Export.Svg
- {
- /// <summary>
- /// Represents the SVG export filter.
- /// </summary>
- public partial class SVGExport : ExportBase
- {
- private XmlDocument doc;
- #region Private Fields
- private string path;
- private string fileNameWOext;
- private string extension;
- private string pageFileName;
- private SvgGraphics graphics;
- private int currentPage;
- private bool pictures;
- private bool embedPictures;
- private bool useWidthAndHeight;
- private bool useViewBox;
- private AspectRatio preserveAspectRatio;
- private string prefixStyle;
- private float pageWidth;
- private float pageHeight;
- #endregion
- #region Properties
- /// <summary>
- /// Enable or disable the pictures in SVG export
- /// </summary>
- public bool Pictures
- {
- get { return pictures; }
- set { pictures = value; }
- }
- /// <summary>
- /// Gets or sets the image format used when exporting.
- /// </summary>
- public SVGImageFormat ImageFormat { get; set; }
- /// <summary>
- /// Embed images into svg
- /// </summary>
- public bool EmbedPictures
- {
- get { return embedPictures; }
- set { embedPictures = value; }
- }
- /// <summary>
- /// Gets or sets value indicating whether or not should to force uniform scaling of SVG document
- /// </summary>
- public AspectRatio PreserveAspectRatio
- {
- get { return preserveAspectRatio; }
- set { preserveAspectRatio = value; }
- }
- /// <summary>
- /// Gets or sets value indicating whether or not should be added 'viewBox' attribute to the svg tag
- /// </summary>
- public bool UseViewBox
- {
- get { return useViewBox; }
- set { useViewBox = value; }
- }
- /// <summary>
- /// Gets or sets value indicating whether or not should be added 'width' and 'height' attributes to the svg tag
- /// </summary>
- public bool UseWidthAndHeight
- {
- get { return useWidthAndHeight; }
- set { useWidthAndHeight = value; }
- }
- /// <summary>
- /// Gets or sets the prefix for style classes and object ids
- /// </summary>
- public string PrefixStyle
- {
- get { return prefixStyle; }
- set { prefixStyle = value; }
- }
- #endregion
- #region Private XML Methods
- private void Save(string filename)
- {
- doc.Save(filename);
- }
- private void Save(Stream stream)
- {
- doc.Save(stream);
- }
- private void CreateDoc(string imagePathAndPrefix, int pageNo = 0)
- {
- doc = new XmlDocument();
- doc.AutoIndent = true;
- if (prefixStyle == null)
- prefixStyle = string.Empty;
- graphics = new SvgGraphics(doc);
- graphics.PrefixStyle = prefixStyle + pageNo + "_";
- graphics.SvgImageFormat = this.ImageFormat;
- graphics.EmbeddedImages = this.EmbedPictures;
- if (!EmbedPictures)
- graphics.ImageFilePrefix = imagePathAndPrefix;
- }
- private void UpdateSize(float width, float height)
- {
- if (useWidthAndHeight)
- graphics.Size = new SizeF(width, height);
- if (useViewBox)
- graphics.ViewBox = new RectangleF(0, 0, width, height);
- if (preserveAspectRatio != null)
- {
- FastString ratioVal = new FastString(preserveAspectRatio.Align.ToString());
- if (preserveAspectRatio.MeetOrSlice != null)
- {
- ratioVal.Append(" ").Append(preserveAspectRatio.MeetOrSlice.ToString());
- }
- doc.Root.SetProp("preserveAspectRatio", ratioVal.ToString());
- }
- }
- private void AddImageWatermark(ReportPage page)
- {
- page.Watermark.DrawImage(new FRPaintEventArgs(graphics, 1, 1, Report.GraphicCache),
- new RectangleF(-page.LeftMargin * Units.Millimeters, -page.TopMargin * Units.Millimeters, page.WidthInPixels, page.HeightInPixels),
- page.Report, false);
- }
- private void AddTextWatermark(ReportPage page)
- {
- if (string.IsNullOrEmpty(page.Watermark.Text))
- return;
- page.Watermark.DrawText(new FRPaintEventArgs(graphics, 1, 1, Report.GraphicCache),
- new RectangleF(-page.LeftMargin * Units.Millimeters, -page.TopMargin * Units.Millimeters, page.WidthInPixels, page.HeightInPixels),
- page.Report, false);
- }
- #endregion
- #region Protected Methods
- /// <inheritdoc/>
- protected override void Start()
- {
- base.Start();
- GeneratedStreams = new List<Stream>();
- currentPage = 0;
- pageWidth = 0;
- pageHeight = 0;
- if (FileName != "" && FileName != null)
- {
- path = Path.GetDirectoryName(FileName);
- fileNameWOext = Path.GetFileNameWithoutExtension(FileName);
- extension = Path.GetExtension(FileName);
- }
- else
- {
- path = "";
- fileNameWOext = "svgreport";
- }
- if (!HasMultipleFiles)
- CreateDoc(Path.Combine(path, fileNameWOext));
- }
- /// <summary>
- /// Begin exporting of page
- /// </summary>
- /// <param name="page"></param>
- protected override void ExportPageBegin(ReportPage page)
- {
- base.ExportPageBegin(page);
- if (path != null && path != "")
- pageFileName = Path.Combine(path, fileNameWOext + currentPage.ToString() + extension);
- else
- pageFileName = null;
- if (HasMultipleFiles)
- {
- CreateDoc(Path.Combine(path, fileNameWOext + currentPage.ToString()), currentPage);
- UpdateSize(page.WidthInPixels, page.HeightInPixels);
- }
- graphics.TranslateTransform(page.LeftMargin * Units.Millimeters, page.TopMargin * Units.Millimeters);
- // export bottom watermark
- if (page.Watermark.Enabled && !page.Watermark.ShowImageOnTop)
- AddImageWatermark(page);
- if (page.Watermark.Enabled && !page.Watermark.ShowTextOnTop)
- AddTextWatermark(page);
- // create a bookmark as a hyperlink target with kind is page number
- XmlItem xml = graphics.OpenContainer("a");
- xml.SetProp("id", $"page{currentPage + 1}");
- graphics.CloseContainer();
- }
- /// <inheritdoc/>
- protected override void ExportBand(BandBase band)
- {
- List<Point> spanCoords = new List<Point>();
- base.ExportBand(band);
- ExportObj(band);
- foreach (Base c in band.AllObjects)
- {
- if (c is Table.TableCell)
- {
- Table.TableCell cell = (c as Table.TableCell);
- if (spanCoords.Contains(cell.Address))
- continue;
- for (int i = 1; i < cell.ColSpan; i++)
- spanCoords.Add(new Point(cell.Address.X + i, cell.Address.Y));
- for (int i = 1; i < cell.RowSpan; i++)
- spanCoords.Add(new Point(cell.Address.X, cell.Address.Y + i));
- }
- else
- ExportObj(c);
- }
- }
- private void ExportObj(Base obj)
- {
- if (obj is ReportComponentBase reportComponent && reportComponent.Exportable)
- {
- if (!string.IsNullOrEmpty(reportComponent.Hyperlink.Value) || !string.IsNullOrEmpty(reportComponent.Bookmark))
- {
- XmlItem xml = graphics.OpenContainer(!string.IsNullOrEmpty(reportComponent.Hyperlink.Value) ? "a" : "g");
- if (!string.IsNullOrEmpty(reportComponent.Bookmark))
- xml.SetProp("id", reportComponent.Bookmark);
- if (!string.IsNullOrEmpty(reportComponent.Hyperlink.Value))
- {
- switch (reportComponent.Hyperlink.Kind)
- {
- case HyperlinkKind.URL:
- xml.SetProp("href", reportComponent.Hyperlink.Value.ToString());
- break;
- case HyperlinkKind.PageNumber:
- xml.SetProp("href", $"#page{reportComponent.Hyperlink.Value}");
- break;
- case HyperlinkKind.DetailPage:
- case HyperlinkKind.DetailReport:
- break;
- case HyperlinkKind.Bookmark:
- xml.SetProp("href", $"#{reportComponent.Hyperlink.Value}");
- break;
- default:
- xml.SetProp("href", reportComponent.Hyperlink.Value.ToString());
- break;
- }
- if (reportComponent.Hyperlink.OpenLinkInNewTab)
- xml.SetProp("target", "_blank");
- }
- }
- reportComponent.Draw(new FRPaintEventArgs(graphics, 1, 1, Report.GraphicCache));
- if (!string.IsNullOrEmpty(reportComponent.Hyperlink.Value) || !string.IsNullOrEmpty(reportComponent.Bookmark))
- graphics.CloseContainer();
- }
- }
- /// <summary>
- /// End exporting
- /// </summary>
- /// <param name="page"></param>
- protected override void ExportPageEnd(ReportPage page)
- {
- base.ExportPageEnd(page);
- // export top watermark
- if (page.Watermark.Enabled && page.Watermark.ShowImageOnTop)
- AddImageWatermark(page);
- if (page.Watermark.Enabled && page.Watermark.ShowTextOnTop)
- AddTextWatermark(page);
- if (HasMultipleFiles)
- {
- if (Directory.Exists(path) && !string.IsNullOrEmpty(FileName))
- {
- // desktop mode
- if (currentPage == 0)
- {
- // save first page in parent Stream
- Save(Stream);
- Stream.Position = 0;
- GeneratedStreams.Add(Stream);
- GeneratedFiles.Add(FileName);
- }
- else
- {
- // save all pages after first in files
- Save(pageFileName);
- GeneratedFiles.Add(pageFileName);
- }
- }
- else if (string.IsNullOrEmpty(path))
- {
- // server mode, save in internal stream collection
- if (currentPage == 0)
- {
- // save first page in parent Stream
- Save(Stream);
- Stream.Position = 0;
- GeneratedStreams.Add(Stream);
- GeneratedFiles.Add(FileName);
- }
- else
- {
- MemoryStream pageStream = new MemoryStream();
- Save(pageStream);
- pageStream.Position = 0;
- GeneratedStreams.Add(pageStream);
- GeneratedFiles.Add(pageFileName);
- }
- }
- }
- else
- {
- graphics.TranslateTransform(-page.LeftMargin * Units.Millimeters, -page.TopMargin * Units.Millimeters + page.HeightInPixels);
- if (pageWidth < page.WidthInPixels)
- pageWidth = page.WidthInPixels;
- pageHeight += page.HeightInPixels;
- }
- // increment page number
- currentPage++;
- }
- /// <inheritdoc/>
- protected override void Finish()
- {
- if (!HasMultipleFiles)
- {
- UpdateSize(pageWidth, pageHeight);
- Save(Stream);
- Stream.Position = 0;
- GeneratedFiles.Add(FileName);
- }
- graphics.Dispose();
- graphics = null;
- doc.Dispose();
- doc = null;
- GeneratedFiles.Clear();
- GeneratedStreams.Clear();
- }
- /// <inheritdoc/>
- protected override string GetFileFilter()
- {
- return new MyRes("FileFilters").Get("SVGFile");
- }
- #endregion
- /// <inheritdoc/>
- public override void Serialize(FRWriter writer)
- {
- base.Serialize(writer);
- writer.WriteValue("ImageFormat", ImageFormat);
- writer.WriteBool("HasMultipleFiles", HasMultipleFiles);
- writer.WriteValue("EmbedPictures", EmbedPictures);
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="SVGExport"/> class.
- /// </summary>
- public SVGExport()
- {
- HasMultipleFiles = false;
- pictures = true;
- ImageFormat = SVGImageFormat.Png;
- preserveAspectRatio = null;
- useWidthAndHeight = true;
- useViewBox = true;
- prefixStyle = "p";
- }
- }
- }
|