using FastReport.Utils;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Text;
namespace FastReport.Export.Html
{
///
/// Represents the HTML export filter.
///
public partial class HTMLExport : ExportBase
{
///
/// Draw any custom controls
///
public event EventHandler CustomDraw;
///
/// Draw any custom controls.
///
///
private void OnCustomDraw(CustomDrawEventArgs e)
{
if (CustomDraw != null)
{
CustomDraw(this, e);
}
}
#region Private fields
#if READONLY_STRUCTS
private readonly struct HTMLData
#else
private struct HTMLData
#endif
{
public readonly int ReportPage;
public readonly int PageNumber;
public readonly int CurrentPage;
public readonly ReportPage page;
public readonly Stream PagesStream;
public HTMLData(int reportPage, int pageNumber, int currentPage, ReportPage page, Stream pagesStream)
{
ReportPage = reportPage;
PageNumber = pageNumber;
CurrentPage = currentPage;
this.page = page;
PagesStream = pagesStream;
}
}
#if READONLY_STRUCTS
private readonly struct PicsArchiveItem
#else
private struct PicsArchiveItem
#endif
{
public readonly string FileName;
public readonly MemoryStream Stream;
public PicsArchiveItem(string fileName, MemoryStream stream)
{
FileName = fileName;
Stream = stream;
}
}
///
/// Types of html export
///
public enum ExportType
{
///
/// Simple export
///
Export,
///
/// Web preview mode
///
WebPreview,
///
/// Web print mode
///
WebPrint
}
private bool layers;
private bool wysiwyg;
private bool notRotateLandscapePage;
private bool highQualitySVG;
private readonly MyRes res;
private readonly HtmlTemplates templates;
private string targetPath;
private string targetIndexPath;
private string targetFileName;
private string fileName;
private string navFileName;
//private string FOutlineFileName;
private int pagesCount;
private string documentTitle;
private ImageFormat imageFormat;
private bool subFolder;
private bool navigator;
private bool singlePage;
private bool pictures;
private bool embedPictures;
private bool webMode;
private List pages;
private HTMLPageData printPageData;
private int count;
private string webImagePrefix;
private string webImageSuffix;
private string stylePrefix;
private string prevWatermarkName;
private long prevWatermarkSize;
private HtmlSizeUnits widthUnits;
private HtmlSizeUnits heightUnits;
private string singlePageFileName;
private string subFolderPath;
private HTMLExportFormat format;
private MemoryStream mimeStream;
private String boundary;
private List picsArchive;
private List prevStyleList;
private int prevStyleListIndex;
private bool pageBreaks;
private bool print;
private bool preview;
private readonly List cssStyles;
private float hPos;
private string pageStyleName;
private bool saveStreams;
private string onClickTemplate = String.Empty;
private string reportID;
private const string BODY_BEGIN = "\r\n";
private const string BODY_END = "";
private const string PRINT_JS = "";
private const string NBSP = " ";
private int currentPage = 0;
private HTMLData d;
private IGraphics htmlMeasureGraphics;
private float maxWidth, maxHeight;
private readonly FastString css = new FastString();
private readonly FastString htmlPage = new FastString();
private float leftMargin, topMargin;
private bool enableMargins = false;
private ExportType exportMode;
private bool enableVectorObjects = true;
///
/// hash:base64Image
///
private Dictionary embeddedImages;
#endregion Private fields
#region Public properties
///
/// Gets or sets images, embedded in html (hash:base64Image)
///
public Dictionary EmbeddedImages
{
get { return embeddedImages; }
set { embeddedImages = value; }
}
///
/// Sets a ID of report
///
public string ReportID
{
get { return reportID; }
set { reportID = value; }
}
///
/// Sets an onclick template
///
public string OnClickTemplate
{
get { return onClickTemplate; }
set { onClickTemplate = value; }
}
///
/// Enable or disable layers export mode
///
public bool Layers
{
get { return layers; }
set { layers = value; }
}
///
/// For internal use only.
///
public string StylePrefix
{
get { return stylePrefix; }
set { stylePrefix = value; }
}
///
/// For internal use only.
///
public string WebImagePrefix
{
get { return webImagePrefix; }
set { webImagePrefix = value; }
}
///
/// For internal use only.
///
public string WebImageSuffix
{
get { return webImageSuffix; }
set { webImageSuffix = value; }
}
///
/// For internal use only.
///
public int Count
{
get { return count; }
}
///
/// For internal use only.
///
public List PreparedPages
{
get { return pages; }
}
///
/// Enable or disable showing of print dialog in browser when html document is opened
///
public bool Print
{
get { return print; }
set { print = value; }
}
///
/// Enable or disable a picture optimization.
///
public bool HighQualitySVG
{
get { return highQualitySVG; }
set { highQualitySVG = value; }
}
///
/// Enable or disable preview in Web settings
///
public bool Preview
{
get { return preview; }
set { preview = value; }
}
///
/// Enable or disable the breaks between pages in print preview when single page mode is enabled
///
public bool PageBreaks
{
get { return pageBreaks; }
set { pageBreaks = value; }
}
///
/// Specifies the output format
///
public HTMLExportFormat Format
{
get { return format; }
set { format = value; }
}
///
/// Specifies the width units in HTML export
///
public HtmlSizeUnits WidthUnits
{
get { return widthUnits; }
set { widthUnits = value; }
}
///
/// Specifies the height units in HTML export
///
public HtmlSizeUnits HeightUnits
{
get { return heightUnits; }
set { heightUnits = value; }
}
///
/// Enable or disable the pictures in HTML export
///
public bool Pictures
{
get { return pictures; }
set { pictures = value; }
}
///
/// Enable or disable embedding pictures in HTML export
///
public bool EmbedPictures
{
get { return embedPictures; }
set { embedPictures = value; }
}
///
/// Enable or disable the WEB mode in HTML export
///
internal bool WebMode
{
get { return webMode; }
set { webMode = value; }
}
///
/// Gets or sets html export mode
///
public ExportType ExportMode
{
get { return exportMode; }
set { exportMode = value; }
}
///
/// Enable or disable the single HTML page creation
///
public bool SinglePage
{
get { return singlePage; }
set { singlePage = value; }
}
///
/// Enable or disable the page navigator in html export
///
public bool Navigator
{
get { return navigator; }
set { navigator = value; }
}
///
/// Enable or disable the sub-folder for files of export
///
public bool SubFolder
{
get { return subFolder; }
set { subFolder = value; }
}
///
/// Gets or sets the WYSIWYG quality of export
///
public bool Wysiwyg
{
get { return wysiwyg; }
set { wysiwyg = value; }
}
///
/// Gets or sets the image format.
///
public ImageFormat ImageFormat
{
get { return imageFormat; }
set { imageFormat = value; }
}
///
/// Gets print page data
///
public HTMLPageData PrintPageData
{
get { return printPageData; }
}
///
/// Enable or disable saving streams in GeneratedStreams collection.
///
public bool SaveStreams
{
get { return saveStreams; }
set { saveStreams = value; }
}
///
/// Enable or disable margins for pages. Works only for Layers-mode.
///
public bool EnableMargins
{
get { return enableMargins; }
set { enableMargins = value; }
}
///
/// Enable or disable export of vector objects such as Barcodes in SVG format.
///
public bool EnableVectorObjects
{
get { return enableVectorObjects; }
set { enableVectorObjects = value; }
}
///
/// Not rotate landscape page when print.
///
public bool NotRotateLandscapePage
{
get { return notRotateLandscapePage; }
set { notRotateLandscapePage = value; }
}
#endregion Public properties
#region Private methods
private void GeneratedUpdate(string filename, Stream stream)
{
int i = GeneratedFiles.IndexOf(filename);
if (i == -1)
{
GeneratedFiles.Add(filename);
GeneratedStreams.Add(stream);
}
else
{
GeneratedStreams[i] = stream;
}
}
private void ExportHTMLPageStart(FastString Page, int PageNumber, int CurrentPage)
{
if (webMode)
{
if (!layers)
{
pages[CurrentPage].CSSText = Page.ToString();
Page.Clear();
}
pages[CurrentPage].PageNumber = PageNumber;
}
if (!webMode && !singlePage)
{
Page.AppendLine(BODY_BEGIN);
}
}
private void ExportHTMLPageFinal(FastString CSS, FastString Page, HTMLData d, float MaxWidth, float MaxHeight)
{
if (!webMode)
{
if (!singlePage)
Page.AppendLine(BODY_END);
if (d.PagesStream == null)
{
string pageFileName = targetIndexPath + targetFileName + d.PageNumber.ToString() + ".html";
if (saveStreams)
{
string fileName = singlePage ? singlePageFileName : pageFileName;
int i = GeneratedFiles.IndexOf(fileName);
Stream outStream = (i == -1) ? new MemoryStream() : GeneratedStreams[i];
DoPage(outStream, documentTitle, CSS, Page);
GeneratedUpdate(fileName, outStream);
}
else
{
GeneratedFiles.Add(pageFileName);
using (FileStream outStream = new FileStream(pageFileName, FileMode.Create))
{
DoPage(outStream, documentTitle, CSS, Page);
}
}
}
else
{
DoPage(d.PagesStream, documentTitle, CSS, Page);
}
}
else
{
ExportHTMLPageFinalWeb(CSS, Page, d, MaxWidth, MaxHeight);
}
}
private void ExportHTMLPageFinalWeb(FastString CSS, FastString Page, HTMLData d, float MaxWidth, float MaxHeight)
{
CalcPageSize(pages[d.CurrentPage], MaxWidth, MaxHeight);
if (Page != null)
{
pages[d.CurrentPage].PageText = Page.ToString();
Page.Clear();
}
if (CSS != null)
{
pages[d.CurrentPage].CSSText = CSS.ToString();
CSS.Clear();
}
pages[d.CurrentPage].PageEvent.Set();
}
private void CalcPageSize(HTMLPageData page, float MaxWidth, float MaxHeight)
{
if (!layers)
{
page.Width = MaxWidth / Zoom;
page.Height = MaxHeight / Zoom;
}
else
{
page.Width = MaxWidth;
page.Height = MaxHeight;
}
}
private void DoPage(Stream stream, string documentTitle, FastString CSS, FastString Page)
{
if (!singlePage)
ExportUtils.Write(stream, String.Format(templates.PageTemplateTitle, documentTitle));
if (CSS != null)
{
ExportUtils.Write(stream, CSS.ToString());
CSS.Clear();
}
if (Page != null)
{
ExportUtils.Write(stream, Page.ToString());
Page.Clear();
}
if (!singlePage)
ExportUtils.Write(stream, templates.PageTemplateFooter);
}
private void ExportHTMLOutline(Stream OutStream)
{
if (!webMode)
{
// under construction
}
else
{
// under construction
}
}
private void DoPageStart(Stream stream, string documentTitle, bool print)
{
ExportUtils.Write(stream, String.Format(templates.PageTemplateTitle, documentTitle));
if (print)
ExportUtils.WriteLn(stream, PRINT_JS);
ExportUtils.WriteLn(stream, BODY_BEGIN);
}
private void DoPageEnd(Stream stream)
{
ExportUtils.WriteLn(stream, BODY_END);
ExportUtils.Write(stream, templates.PageTemplateFooter);
}
private void ExportHTMLIndex(Stream stream)
{
ExportUtils.Write(stream, String.Format(templates.IndexTemplate,
documentTitle, ExportUtils.HtmlURL(navFileName),
ExportUtils.HtmlURL(targetFileName +
(singlePage ? ".main" : "1") + ".html")));
}
private void ExportHTMLNavigator(Stream stream)
{
string prefix = ExportUtils.HtmlURL(fileName);
// {0} - pages count {1} - name of report {2} multipage document {3} prefix of pages
// {4} first caption {5} previous caption {6} next caption {7} last caption
// {8} total caption
ExportUtils.Write(stream, String.Format(templates.NavigatorTemplate,
pagesCount.ToString(),
documentTitle, (singlePage ? "0" : "1"),
prefix, res.Get("First"), res.Get("Prev"),
res.Get("Next"), res.Get("Last"), res.Get("Total")));
}
private void Init()
{
htmlMeasureGraphics = Report.MeasureGraphics;
cssStyles.Clear();
hPos = 0;
count = Report.PreparedPages.Count;
pagesCount = 0;
prevWatermarkName = String.Empty;
prevWatermarkSize = 0;
prevStyleList = null;
prevStyleListIndex = 0;
picsArchive = new List();
GeneratedStreams = new List();
}
private void StartMHT()
{
subFolder = false;
singlePage = true;
navigator = false;
mimeStream = new MemoryStream();
boundary = ExportUtils.GetID();
}
private void StartWeb()
{
pages.Clear();
for (int i = 0; i < count; i++)
pages.Add(new HTMLPageData());
}
private void StartSaveStreams()
{
if (singlePage)
GeneratedUpdate("index.html", null);
subFolder = false;
navigator = false;
}
private void FinishMHT()
{
DoPageEnd(mimeStream);
WriteMHTHeader(Stream, FileName);
WriteMimePart(mimeStream, "text/html", "utf-8", "index.html");
for (int i = 0; i < picsArchive.Count; i++)
{
string imagename = picsArchive[i].FileName;
WriteMimePart(picsArchive[i].Stream, "image/" + imagename.Substring(imagename.LastIndexOf('.') + 1), "utf-8", imagename);
}
string last = "--" + boundary + "--";
Stream.Write(Encoding.ASCII.GetBytes(last), 0, last.Length);
}
private void FinishSaveStreams()
{
// do append in memory stream
int fileIndex = GeneratedFiles.IndexOf(singlePageFileName);
ExportHTMLIndex(GeneratedStreams[fileIndex]);
MemoryStream outStream = new MemoryStream();
ExportHTMLNavigator(outStream);
GeneratedUpdate(targetIndexPath + navFileName, outStream);
}
#endregion Private methods
#region Protected methods
///
protected override string GetFileFilter()
{
if (Format == HTMLExportFormat.HTML)
return new MyRes("FileFilters").Get("HtmlFile");
else
return new MyRes("FileFilters").Get("MhtFile");
}
///
protected override void Start()
{
base.Start();
Init();
if (saveStreams)
{
StartSaveStreams();
}
if (!webMode)
{
if (format == HTMLExportFormat.MessageHTML)
{
StartMHT();
}
if (FileName == "" && Stream != null)
{
targetFileName = "html";
singlePage = true;
subFolder = false;
navigator = false;
if (ExportMode == ExportType.WebPrint)
{
NotRotateLandscapePage = true;
for (int i = 0; i < Report.PreparedPages.Count; i++)
{
if (!Report.PreparedPages.GetPage(i).Landscape)
{
NotRotateLandscapePage = false;
break;
}
}
}
if (format == HTMLExportFormat.HTML && !embedPictures)
pictures = false;
}
else
{
targetFileName = Path.GetFileNameWithoutExtension(FileName);
fileName = targetFileName;
targetIndexPath = !String.IsNullOrEmpty(FileName) ? Path.GetDirectoryName(FileName) : FileName;
}
if (!String.IsNullOrEmpty(targetIndexPath))
targetIndexPath += Path.DirectorySeparatorChar;
if (preview)
{
pictures = true;
printPageData = new HTMLPageData();
}
else if (subFolder)
{
subFolderPath = targetFileName + ".files" + Path.DirectorySeparatorChar;
targetPath = targetIndexPath + subFolderPath;
targetFileName = subFolderPath + targetFileName;
if (!Directory.Exists(targetPath))
Directory.CreateDirectory(targetPath);
}
else
targetPath = targetIndexPath;
navFileName = targetFileName + ".nav.html";
//FOutlineFileName = FTargetFileName + ".outline.html";
documentTitle = (!String.IsNullOrEmpty(Report.ReportInfo.Name) ?
Report.ReportInfo.Name : Path.GetFileNameWithoutExtension(FileName));
if (singlePage)
{
if (navigator)
{
singlePageFileName = targetIndexPath + targetFileName + ".main.html";
if (saveStreams)
{
MemoryStream pageStream = new MemoryStream();
DoPageStart(pageStream, documentTitle, print);
GeneratedUpdate(singlePageFileName, pageStream);
}
else
{
using (Stream pageStream = new FileStream(singlePageFileName,
FileMode.Create))
{
DoPageStart(pageStream, documentTitle, print);
}
}
}
else
{
singlePageFileName = String.IsNullOrEmpty(FileName) ? "index.html" : FileName;
if (saveStreams)
{
GeneratedUpdate(singlePageFileName, new MemoryStream());
}
DoPageStart((format == HTMLExportFormat.HTML) ? Stream : mimeStream, documentTitle, print);
}
}
}
else
{
StartWeb();
}
}
///
protected override void ExportPageBegin(ReportPage page)
{
if (ExportMode == ExportType.Export)
base.ExportPageBegin(page);
pagesCount++;
if (!WebMode)
{
if (singlePage)
{
Stream stream;
if (navigator)
{
if (saveStreams)
stream = new MemoryStream();
else
stream = new FileStream(singlePageFileName, FileMode.Append);
d = new HTMLData(pagesCount, pagesCount, 0, page, stream);
ExportHTMLPageBegin(d);
}
else
{
if (format == HTMLExportFormat.HTML)
stream = Stream;
else
stream = mimeStream;
d = new HTMLData(pagesCount, pagesCount, 0, page, stream);
ExportHTMLPageBegin(d);
}
}
else
ProcessPageBegin(pagesCount - 1, pagesCount, page);
}
else
// Web
ProcessPageBegin(pagesCount - 1, pagesCount, page);
}
///
protected override void ExportPageEnd(ReportPage page)
{
if (!WebMode)
{
if (singlePage)
{
if (navigator)
{
if (saveStreams)
{
ExportHTMLPageEnd(d);
GeneratedUpdate(singlePageFileName, d.PagesStream);
}
else
{
ExportHTMLPageEnd(d);
d.PagesStream.Close();
d.PagesStream.Dispose();
}
}
else
{
ExportHTMLPageEnd(d);
}
}
else
ProcessPageEnd(pagesCount - 1, pagesCount);
}
else
// Web
ProcessPageEnd(pagesCount - 1, pagesCount);
}
///
/// Process Page with number p and real page ReportPage
///
///
///
///
public void ProcessPageBegin(int p, int ReportPage, ReportPage page)
{
d = new HTMLData(ReportPage, pagesCount, p, page, null);
ExportHTMLPageBegin(d);
}
///
/// Process Page with number p and real page ReportPage
///
///
///
public void ProcessPageEnd(int p, int ReportPage)
{
ExportHTMLPageEnd(d);
}
///
protected override void Finish()
{
if (!webMode)
{
if (navigator)
{
if (saveStreams)
{
FinishSaveStreams();
}
else
{
if (singlePage)
{
//if (saveStreams) // Commented because saveStreams is always false!!
//{
// int fileIndex = GeneratedFiles.IndexOf(singlePageFileName);
// DoPageEnd(generatedStreams[fileIndex]);
//}
//else
//{
using (Stream pageStream = new FileStream(singlePageFileName, FileMode.Append))
{
DoPageEnd(pageStream);
}
//} // Commented because saveStreams is always false!!
}
ExportHTMLIndex(Stream);
GeneratedFiles.Add(targetIndexPath + navFileName);
using (FileStream outStream = new FileStream(targetIndexPath + navFileName, FileMode.Create))
{
ExportHTMLNavigator(outStream);
}
//GeneratedFiles.Add(FTargetIndexPath + FOutlineFileName);
//using (FileStream OutStream = new FileStream(FTargetIndexPath + FOutlineFileName, FileMode.Create))
// ExportHTMLOutline(OutStream);
}
}
else if (format == HTMLExportFormat.MessageHTML)
{
FinishMHT();
}
else
{
if (saveStreams)
{
if (!String.IsNullOrEmpty(singlePageFileName))
{
int fileIndex = GeneratedFiles.IndexOf(singlePageFileName);
DoPageEnd(GeneratedStreams[fileIndex]);
}
}
else
{
if (!singlePage)
{
DoPageStart(Stream, documentTitle, false);
int pageCounter = 0;
foreach (string genFile in GeneratedFiles)
{
string ext = Path.GetExtension(genFile);
if (ext == ".html" && genFile != FileName)
{
string file = Path.GetFileName(genFile);
if (subFolder)
file = Path.Combine(subFolderPath, file);
ExportUtils.WriteLn(Stream, String.Format("Page {1}
", file, ++pageCounter));
}
}
}
DoPageEnd(Stream);
}
}
}
}
#endregion Protected methods
///
public override void Serialize(FRWriter writer)
{
base.Serialize(writer);
writer.WriteBool("Layers", Layers);
writer.WriteBool("Wysiwyg", Wysiwyg);
writer.WriteBool("Pictures", Pictures);
writer.WriteBool("EmbedPictures", EmbedPictures);
writer.WriteBool("SubFolder", SubFolder);
writer.WriteBool("Navigator", Navigator);
writer.WriteBool("SinglePage", SinglePage);
writer.WriteBool("NotRotateLandscapePage", NotRotateLandscapePage);
writer.WriteBool("HighQualitySVG", HighQualitySVG);
}
///
/// For internal use only.
///
public void Init_WebMode()
{
subFolder = false;
navigator = false;
ShowProgress = false;
pages = new List();
webMode = true;
OpenAfterExport = false;
}
internal void Finish_WebMode()
{
pages.Clear();
}
///
/// Initializes a new instance of the class.
///
public HTMLExport()
{
Zoom = 1.0f;
HasMultipleFiles = true;
layers = true;
wysiwyg = true;
pictures = true;
webMode = false;
subFolder = true;
navigator = true;
singlePage = false;
widthUnits = HtmlSizeUnits.Pixel;
heightUnits = HtmlSizeUnits.Pixel;
imageFormat = ImageFormat.Png;
templates = new HtmlTemplates();
format = HTMLExportFormat.HTML;
prevStyleList = null;
prevStyleListIndex = 0;
pageBreaks = true;
print = false;
preview = false;
saveStreams = false;
cssStyles = new List();
exportMode = ExportType.Export;
res = new MyRes("Export,Html");
embeddedImages = new Dictionary();
notRotateLandscapePage = false;
highQualitySVG = false;
}
///
/// Initializes a new instance of the class for WebPreview mode.
///
public HTMLExport(bool webPreview) : this()
{
this.webPreview = webPreview;
if (webPreview)
exportMode = ExportType.WebPreview;
}
}
///
/// Event arguments for custom drawing of report objects.
///
public class CustomDrawEventArgs : EventArgs
{
///
/// Report object
///
public Report report;
///
/// ReportObject.
///
public ReportComponentBase reportObject;
///
/// Resulting successful drawing flag.
///
public bool done = false;
///
/// Resulting HTML string.
///
public string html;
///
/// Resulting CSS string.
///
public string css;
///
/// Layers mode when true or Table mode when false.
///
public bool layers;
///
/// Zoom value for scale position and sizes.
///
public float zoom;
///
/// Left position.
///
public float left;
///
/// Top position.
///
public float top;
///
/// Width of object.
///
public float width;
///
/// Height of object.
///
public float height;
}
}