/// <summary> /// Create PDF document from given HTML.<br/> /// </summary> /// <param name="html">HTML source to create PDF from</param> /// <param name="pageSize">the page size to use for each page in the generated pdf </param> /// <param name="margin">the margin to use between the HTML and the edges of each page</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the generated image of the html</returns> public static PdfDocument GeneratePdf(string html, PageSize pageSize, int margin = 20, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { var config = new PdfGenerateConfig(); config.PageSize = pageSize; config.SetMargins(margin); return GeneratePdf(html, config, cssData, stylesheetLoad, imageLoad); }
/// <summary> /// Create PDF pages from given HTML and appends them to the provided PDF document.<br/> /// </summary> /// <param name="document">PDF document to append pages to</param> /// <param name="html">HTML source to create PDF from</param> /// <param name="config">the configuration to use for the PDF generation (page size/page orientation/margins/etc.)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the generated image of the html</returns> public static void AddPdfPages(PdfDocument document, string html, PdfGenerateConfig config, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { XSize orgPageSize; // get the size of each page to layout the HTML in if (config.PageSize != PageSize.Undefined) orgPageSize = PageSizeConverter.ToSize(config.PageSize); else orgPageSize = config.ManualPageSize; if (config.PageOrientation == PageOrientation.Landscape) { // invert pagesize for landscape orgPageSize = new XSize(orgPageSize.Height, orgPageSize.Width); } var pageSize = new XSize(orgPageSize.Width - config.MarginLeft - config.MarginRight, orgPageSize.Height - config.MarginTop - config.MarginBottom); if (!string.IsNullOrEmpty(html)) { using (var container = new HtmlContainer()) { if (stylesheetLoad != null) container.StylesheetLoad += stylesheetLoad; if (imageLoad != null) container.ImageLoad += imageLoad; container.Location = new XPoint(config.MarginLeft, config.MarginTop); container.MaxSize = new XSize(pageSize.Width, 0); container.SetHtml(html, cssData); container.PageSize = pageSize; container.MarginBottom = config.MarginBottom; container.MarginLeft = config.MarginLeft; container.MarginRight = config.MarginRight; container.MarginTop = config.MarginTop; // layout the HTML with the page width restriction to know how many pages are required using (var measure = XGraphics.CreateMeasureContext(pageSize, XGraphicsUnit.Point, XPageDirection.Downwards)) { container.PerformLayout(measure); } // while there is un-rendered HTML, create another PDF page and render with proper offset for the next page double scrollOffset = 0; while (scrollOffset > -container.ActualSize.Height) { var page = document.AddPage(); page.Height = orgPageSize.Height; page.Width = orgPageSize.Width; using (var g = XGraphics.FromPdfPage(page)) { //g.IntersectClip(new XRect(config.MarginLeft, config.MarginTop, pageSize.Width, pageSize.Height)); g.IntersectClip(new XRect(0, 0, page.Width, page.Height)); container.ScrollOffset = new XPoint(0, scrollOffset); container.PerformPaint(g); } scrollOffset -= pageSize.Height; } // add web links and anchors HandleLinks(document, container, orgPageSize, pageSize); } } }
/// <summary> /// Create PDF document from given HTML.<br/> /// </summary> /// <param name="html">HTML source to create PDF from</param> /// <param name="config">the configuration to use for the PDF generation (page size/page orientation/margins/etc.)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the generated image of the html</returns> public static PdfDocument GeneratePdf(string html, PdfGenerateConfig config, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { // create PDF document to render the HTML into var document = new PdfDocument(); // add rendered PDF pages to document AddPdfPages(document, html, config, cssData, stylesheetLoad, imageLoad); return document; }
/// <summary> /// Create PDF pages from given HTML and appends them to the provided PDF document.<br/> /// </summary> /// <param name="document">PDF document to append pages to</param> /// <param name="html">HTML source to create PDF from</param> /// <param name="config">the configuration to use for the PDF generation (page size/page orientation/margins/etc.)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the generated image of the html</returns> public static void AddPdfPages(PdfDocument document, string html, PdfGenerateConfig config, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { XSize orgPageSize; // get the size of each page to layout the HTML in if (config.PageSize != PageSize.Undefined) orgPageSize = PageSizeConverter.ToSize(config.PageSize); else orgPageSize = config.ManualPageSize; if (config.PageOrientation == PageOrientation.Landscape) { // invert pagesize for landscape orgPageSize = new XSize(orgPageSize.Height, orgPageSize.Width); } var pageSize = new XSize(orgPageSize.Width - config.MarginLeft - config.MarginRight, orgPageSize.Height - config.MarginTop - config.MarginBottom); if (!string.IsNullOrEmpty(html)) { using (var container = new HtmlContainer()) { if (stylesheetLoad != null) container.StylesheetLoad += stylesheetLoad; if (imageLoad != null) container.ImageLoad += imageLoad; container.Location = new XPoint(config.MarginLeft, config.MarginTop); container.MaxSize = new XSize(pageSize.Width, 0); container.SetHtml(html, cssData); container.PageSize = pageSize; container.MarginBottom = config.MarginBottom; container.MarginLeft = config.MarginLeft; container.MarginRight = config.MarginRight; container.MarginTop = config.MarginTop; // layout the HTML with the page width restriction to know how many pages are required var measure = XGraphics.CreateMeasureContext(pageSize, XGraphicsUnit.Point, XPageDirection.Downwards); container.PerformLayout(measure); // while there is un-rendered HTML, create another PDF page and render with proper offset for the next page double scrollOffset = 0; //SL: if there is more than one page, increase the bottom margin to allow space for the page number container.MarginBottom += scrollOffset > -container.ActualSize.Height ? 20 : 0; container.PerformLayout(measure); //SL: This still does not increase the margin for the first page of a multi page.. welp while (scrollOffset > -container.ActualSize.Height) { var page = document.AddPage(); page.Height = orgPageSize.Height; page.Width = orgPageSize.Width; using (var g = XGraphics.FromPdfPage(page)) { //g.IntersectClip(new XRect(config.MarginLeft, config.MarginTop, pageSize.Width, pageSize.Height)); g.IntersectClip(new XRect(0, 0, page.Width, page.Height)); container.ScrollOffset = new XPoint(0, scrollOffset); container.PerformPaint(g); } scrollOffset -= pageSize.Height; } if (config.AddPageCountFoooter && document.PageCount > 1) //Only add page numbers if more than one page AddPageCountFoooter(document, pageSize); // SL: Set config option to handle links or not as it crashes for // some valid html links. // TODO: Investigate reason for crashing. if (config.HandleLinks) HandleLinks(document, container, orgPageSize, pageSize); } } }
/// <summary> /// Renders the specified HTML into a new image of unknown size that will be determined by max width/height and HTML layout.<br/> /// If <paramref name="maxWidth"/> is zero the html will use all the required width, otherwise it will perform line /// wrap as specified in the html<br/> /// If <paramref name="maxHeight"/> is zero the html will use all the required height, otherwise it will clip at the /// given max height not rendering the html below it.<br/> /// <p> /// Limitation: The image cannot have transparent background, by default it will be white.<br/> /// See "Rendering to image" remarks section on <see cref="HtmlRender"/>.<br/> /// </p> /// </summary> /// <param name="html">HTML source to render</param> /// <param name="maxWidth">optional: the max width of the rendered html, if not zero and html cannot be layout within the limit it will be clipped</param> /// <param name="maxHeight">optional: the max height of the rendered html, if not zero and html cannot be layout within the limit it will be clipped</param> /// <param name="backgroundColor">optional: the color to fill the image with (default - white)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the generated image of the html</returns> /// <exception cref="ArgumentOutOfRangeException">if <paramref name="backgroundColor"/> is <see cref="Color.Transparent"/></exception>. public static Image RenderToImage(string html, int maxWidth = 0, int maxHeight = 0, Color backgroundColor = new Color(), CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { return RenderToImage(html, Size.Empty, new Size(maxWidth, maxHeight), backgroundColor, cssData, stylesheetLoad, imageLoad); }
/// <summary> /// Renders the specified HTML into a new image of the requested size.<br/> /// The HTML will be layout by the given size but will be clipped if cannot fit.<br/> /// <p> /// Limitation: The image cannot have transparent background, by default it will be white.<br/> /// See "Rendering to image" remarks section on <see cref="HtmlRender"/>.<br/> /// </p> /// </summary> /// <param name="html">HTML source to render</param> /// <param name="size">The size of the image to render into, layout html by width and clipped by height</param> /// <param name="backgroundColor">optional: the color to fill the image with (default - white)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the generated image of the html</returns> /// <exception cref="ArgumentOutOfRangeException">if <paramref name="backgroundColor"/> is <see cref="Color.Transparent"/></exception>. public static Image RenderToImage(string html, Size size, Color backgroundColor = new Color(), CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { if (backgroundColor == Color.Transparent) throw new ArgumentOutOfRangeException("backgroundColor", "Transparent background in not supported"); // create the final image to render into var image = new Bitmap(size.Width, size.Height, PixelFormat.Format32bppArgb); if (!string.IsNullOrEmpty(html)) { // create memory buffer from desktop handle that supports alpha channel IntPtr dib; var memoryHdc = Win32Utils.CreateMemoryHdc(IntPtr.Zero, image.Width, image.Height, out dib); try { // create memory buffer graphics to use for HTML rendering using (var memoryGraphics = Graphics.FromHdc(memoryHdc)) { memoryGraphics.Clear(backgroundColor != Color.Empty ? backgroundColor : Color.White); // render HTML into the memory buffer RenderHtml(memoryGraphics, html, PointF.Empty, size, cssData, true, stylesheetLoad, imageLoad); } // copy from memory buffer to image CopyBufferToImage(memoryHdc, image); } finally { Win32Utils.ReleaseMemoryHdc(memoryHdc, dib); } } return image; }
/// <summary> /// Renders the specified HTML into a new image of the requested size.<br/> /// The HTML will be layout by the given size but will be clipped if cannot fit.<br/> /// </summary> /// <param name="html">HTML source to render</param> /// <param name="size">The size of the image to render into, layout html by width and clipped by height</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the generated image of the html</returns> public static BitmapFrame RenderToImage(string html, Size size, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { var renderTarget = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32); if (!string.IsNullOrEmpty(html)) { // render HTML into the visual DrawingVisual drawingVisual = new DrawingVisual(); using (DrawingContext g = drawingVisual.RenderOpen()) { RenderHtml(g, html, new Point(), size, cssData, stylesheetLoad, imageLoad); } // render visual into target bitmap renderTarget.Render(drawingVisual); } return BitmapFrame.Create(renderTarget); }
/// <summary> /// Init with optional document and stylesheet. /// </summary> /// <param name="htmlSource">the html to init with, init empty if not given</param> /// <param name="baseCssData">optional: the stylesheet to init with, init default if not given</param> public void SetHtml(string htmlSource, CssData baseCssData = null) { _htmlContainerInt.SetHtml(htmlSource, baseCssData); }
/// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> private void Dispose(bool all) { try { if (all) { LinkClicked = null; Refresh = null; RenderError = null; StylesheetLoad = null; ImageLoad = null; } _cssData = null; if (_root != null) _root.Dispose(); _root = null; if (_selectionHandler != null) _selectionHandler.Dispose(); _selectionHandler = null; } catch { } }
/// <summary> /// Renders the specified HTML source on the specified location and max size restriction.<br/> /// If <paramref name="maxSize"/>.Width is zero the html will use all the required width, otherwise it will perform line /// wrap as specified in the html<br/> /// If <paramref name="maxSize"/>.Height is zero the html will use all the required height, otherwise it will clip at the /// given max height not rendering the html below it.<br/> /// Clip the graphics so the html will not be rendered outside the max height bound given.<br/> /// Returned is the actual width and height of the rendered html.<br/> /// </summary> /// <param name="g">Device to render with</param> /// <param name="html">HTML source to render</param> /// <param name="location">the top-left most location to start render the html at</param> /// <param name="maxSize">the max size of the rendered html (if height above zero it will be clipped)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="useGdiPlusTextRendering">true - use GDI+ text rendering, false - use GDI text rendering</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the actual size of the rendered html</returns> private static SizeF RenderClip(Graphics g, string html, PointF location, SizeF maxSize, CssData cssData, bool useGdiPlusTextRendering, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad, EventHandler<HtmlImageLoadEventArgs> imageLoad) { Region prevClip = null; if (maxSize.Height > 0) { prevClip = g.Clip; g.SetClip(new RectangleF(location, maxSize)); } var actualSize = RenderHtml(g, html, location, maxSize, cssData, useGdiPlusTextRendering, stylesheetLoad, imageLoad); if (prevClip != null) { g.SetClip(prevClip, CombineMode.Replace); } return actualSize; }
/// <summary> /// Renders the specified HTML into a new image of unknown size that will be determined by max width/height and HTML layout.<br/> /// If <paramref name="maxWidth"/> is zero the html will use all the required width, otherwise it will perform line /// wrap as specified in the html<br/> /// If <paramref name="maxHeight"/> is zero the html will use all the required height, otherwise it will clip at the /// given max height not rendering the html below it.<br/> /// The generated image have transparent background that the html is rendered on.<br/> /// GDI+ text rending can be controlled by providing <see cref="TextRenderingHint"/>.<br/> /// See "Rendering to image" remarks section on <see cref="HtmlRender"/>.<br/> /// </summary> /// <param name="html">HTML source to render</param> /// <param name="maxWidth">optional: the max width of the rendered html, if not zero and html cannot be layout within the limit it will be clipped</param> /// <param name="maxHeight">optional: the max height of the rendered html, if not zero and html cannot be layout within the limit it will be clipped</param> /// <param name="textRenderingHint">optional: (default - SingleBitPerPixelGridFit)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the generated image of the html</returns> public static Image RenderToImageGdiPlus(string html, int maxWidth = 0, int maxHeight = 0, TextRenderingHint textRenderingHint = TextRenderingHint.AntiAlias, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { return RenderToImageGdiPlus(html, Size.Empty, new Size(maxWidth, maxHeight), textRenderingHint, cssData, stylesheetLoad, imageLoad); }
/// <summary> /// Create deep copy of the css data with cloned css blocks. /// </summary> /// <returns>cloned object</returns> public CssData Clone() { var clone = new CssData(); foreach (var mid in _mediaBlocks) { var cloneMid = new Dictionary<string, List<CssBlock>>(StringComparer.OrdinalIgnoreCase); foreach (var blocks in mid.Value) { var cloneList = new List<CssBlock>(); foreach (var cssBlock in blocks.Value) { cloneList.Add(cssBlock.Clone()); } cloneMid[blocks.Key] = cloneList; } clone._mediaBlocks[mid.Key] = cloneMid; } return clone; }
/// <summary> /// Combine this CSS data blocks with <paramref name="other"/> CSS blocks for each media.<br/> /// Merge blocks if exists in both. /// </summary> /// <param name="other">the CSS data to combine with</param> public void Combine(CssData other) { ArgChecker.AssertArgNotNull(other, "other"); // for each media block foreach (var mediaBlock in other.MediaBlocks) { // for each css class in the media block foreach (var bla in mediaBlock.Value) { // for each css block of the css class foreach (var cssBlock in bla.Value) { // combine with this AddCssBlock(mediaBlock.Key, cssBlock); } } } }
/// <summary> /// Renders the specified HTML source on the specified location and max size restriction.<br/> /// If <paramref name="maxSize"/>.Width is zero the html will use all the required width, otherwise it will perform line /// wrap as specified in the html<br/> /// If <paramref name="maxSize"/>.Height is zero the html will use all the required height, otherwise it will clip at the /// given max height not rendering the html below it.<br/> /// Returned is the actual width and height of the rendered html.<br/> /// </summary> /// <param name="g">Device to render with</param> /// <param name="html">HTML source to render</param> /// <param name="location">the top-left most location to start render the html at</param> /// <param name="maxSize">the max size of the rendered html (if height above zero it will be clipped)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the actual size of the rendered html</returns> private static Size RenderHtml(DrawingContext g, string html, Point location, Size maxSize, CssData cssData, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad, EventHandler<HtmlImageLoadEventArgs> imageLoad) { Size actualSize = Size.Empty; if (!string.IsNullOrEmpty(html)) { using (var container = new HtmlContainer()) { container.Location = location; container.MaxSize = maxSize; container.AvoidAsyncImagesLoading = true; container.AvoidImagesLateLoading = true; if (stylesheetLoad != null) container.StylesheetLoad += stylesheetLoad; if (imageLoad != null) container.ImageLoad += imageLoad; container.SetHtml(html, cssData); container.PerformLayout(); container.PerformPaint(g, new Rect(0, 0, double.MaxValue, double.MaxValue)); actualSize = container.ActualSize; } } return actualSize; }
/// <summary> /// Renders the specified HTML source on the specified location and max size restriction.<br/> /// If <paramref name="maxSize"/>.Width is zero the html will use all the required width, otherwise it will perform line /// wrap as specified in the html<br/> /// If <paramref name="maxSize"/>.Height is zero the html will use all the required height, otherwise it will clip at the /// given max height not rendering the html below it.<br/> /// Clip the graphics so the html will not be rendered outside the max height bound given.<br/> /// Returned is the actual width and height of the rendered html.<br/> /// </summary> /// <param name="g">Device to render with</param> /// <param name="html">HTML source to render</param> /// <param name="location">the top-left most location to start render the html at</param> /// <param name="maxSize">the max size of the rendered html (if height above zero it will be clipped)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the actual size of the rendered html</returns> private static Size RenderClip(DrawingContext g, string html, Point location, Size maxSize, CssData cssData, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad, EventHandler<HtmlImageLoadEventArgs> imageLoad) { if (maxSize.Height > 0) g.PushClip(new RectangleGeometry(new Rect(location, maxSize))); var actualSize = RenderHtml(g, html, location, maxSize, cssData, stylesheetLoad, imageLoad); if (maxSize.Height > 0) g.Pop(); return actualSize; }
/// <summary> /// Renders the specified HTML into a new image of unknown size that will be determined by min/max width/height and HTML layout.<br/> /// If <paramref name="maxSize.Width"/> is zero the html will use all the required width, otherwise it will perform line /// wrap as specified in the html<br/> /// If <paramref name="maxSize.Height"/> is zero the html will use all the required height, otherwise it will clip at the /// given max height not rendering the html below it.<br/> /// If <paramref name="minSize"/> (Width/Height) is above zero the rendered image will not be smaller than the given min size.<br/> /// <p> /// Limitation: The image cannot have transparent background, by default it will be white.<br/> /// See "Rendering to image" remarks section on <see cref="HtmlRender"/>.<br/> /// </p> /// </summary> /// <param name="html">HTML source to render</param> /// <param name="minSize">optional: the min size of the rendered html (zero - not limit the width/height)</param> /// <param name="maxSize">optional: the max size of the rendered html, if not zero and html cannot be layout within the limit it will be clipped (zero - not limit the width/height)</param> /// <param name="backgroundColor">optional: the color to fill the image with (default - white)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the generated image of the html</returns> public static BitmapFrame RenderToImage(string html, Size minSize, Size maxSize, Color backgroundColor = new Color(), CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { RenderTargetBitmap renderTarget; if (!string.IsNullOrEmpty(html)) { using (var container = new HtmlContainer()) { container.AvoidAsyncImagesLoading = true; container.AvoidImagesLateLoading = true; if (stylesheetLoad != null) container.StylesheetLoad += stylesheetLoad; if (imageLoad != null) container.ImageLoad += imageLoad; container.SetHtml(html, cssData); var finalSize = MeasureHtmlByRestrictions(container, minSize, maxSize); container.MaxSize = finalSize; renderTarget = new RenderTargetBitmap((int)finalSize.Width, (int)finalSize.Height, 96, 96, PixelFormats.Pbgra32); // render HTML into the visual DrawingVisual drawingVisual = new DrawingVisual(); using (DrawingContext g = drawingVisual.RenderOpen()) { container.PerformPaint(g, new Rect(new Size(maxSize.Width > 0 ? maxSize.Width : double.MaxValue, maxSize.Height > 0 ? maxSize.Height : double.MaxValue))); } // render visual into target bitmap renderTarget.Render(drawingVisual); } } else { renderTarget = new RenderTargetBitmap(0, 0, 96, 96, PixelFormats.Pbgra32); } return BitmapFrame.Create(renderTarget); }
/// <summary> /// Renders the specified HTML into a new image of unknown size that will be determined by min/max width/height and HTML layout.<br/> /// If <paramref name="maxSize.Width"/> is zero the html will use all the required width, otherwise it will perform line /// wrap as specified in the html<br/> /// If <paramref name="maxSize.Height"/> is zero the html will use all the required height, otherwise it will clip at the /// given max height not rendering the html below it.<br/> /// If <paramref name="minSize"/> (Width/Height) is above zero the rendered image will not be smaller than the given min size.<br/> /// <p> /// Limitation: The image cannot have transparent background, by default it will be white.<br/> /// See "Rendering to image" remarks section on <see cref="HtmlRender"/>.<br/> /// </p> /// </summary> /// <param name="html">HTML source to render</param> /// <param name="minSize">optional: the min size of the rendered html (zero - not limit the width/height)</param> /// <param name="maxSize">optional: the max size of the rendered html, if not zero and html cannot be layout within the limit it will be clipped (zero - not limit the width/height)</param> /// <param name="backgroundColor">optional: the color to fill the image with (default - white)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the generated image of the html</returns> /// <exception cref="ArgumentOutOfRangeException">if <paramref name="backgroundColor"/> is <see cref="Color.Transparent"/></exception>. public static Image RenderToImage(string html, Size minSize, Size maxSize, Color backgroundColor = new Color(), CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { if (backgroundColor == Color.Transparent) throw new ArgumentOutOfRangeException("backgroundColor", "Transparent background in not supported"); if (string.IsNullOrEmpty(html)) return new Bitmap(0, 0, PixelFormat.Format32bppArgb); using (var container = new HtmlContainer()) { container.AvoidAsyncImagesLoading = true; container.AvoidImagesLateLoading = true; if (stylesheetLoad != null) container.StylesheetLoad += stylesheetLoad; if (imageLoad != null) container.ImageLoad += imageLoad; container.SetHtml(html, cssData); var finalSize = MeasureHtmlByRestrictions(container, minSize, maxSize); container.MaxSize = finalSize; // create the final image to render into by measured size var image = new Bitmap(finalSize.Width, finalSize.Height, PixelFormat.Format32bppArgb); // create memory buffer from desktop handle that supports alpha channel IntPtr dib; var memoryHdc = Win32Utils.CreateMemoryHdc(IntPtr.Zero, image.Width, image.Height, out dib); try { // render HTML into the memory buffer using (var memoryGraphics = Graphics.FromHdc(memoryHdc)) { memoryGraphics.Clear(backgroundColor != Color.Empty ? backgroundColor : Color.White); container.PerformPaint(memoryGraphics); } // copy from memory buffer to image CopyBufferToImage(memoryHdc, image); } finally { Win32Utils.ReleaseMemoryHdc(memoryHdc, dib); } return image; } }
/// <summary> /// Measure the size (width and height) required to draw the given html under given max width restriction.<br/> /// If no max width restriction is given the layout will use the maximum possible width required by the content, /// it can be the longest text line or full image width.<br/> /// Use GDI+ text rending, use <see cref="Graphics.TextRenderingHint"/> to control text rendering. /// </summary> /// <param name="g">Device to use for measure</param> /// <param name="html">HTML source to render</param> /// <param name="maxWidth">optional: bound the width of the html to render in (default - 0, unlimited)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the size required for the html</returns> public static SizeF MeasureGdiPlus(Graphics g, string html, float maxWidth = 0, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { ArgChecker.AssertArgNotNull(g, "g"); return Measure(g, html, maxWidth, cssData, true, stylesheetLoad, imageLoad); }
/// <summary> /// Renders the specified HTML into a new image of the requested size.<br/> /// The HTML will be layout by the given size but will be clipped if cannot fit.<br/> /// The generated image have transparent background that the html is rendered on.<br/> /// GDI+ text rending can be controlled by providing <see cref="TextRenderingHint"/>.<br/> /// See "Rendering to image" remarks section on <see cref="HtmlRender"/>.<br/> /// </summary> /// <param name="html">HTML source to render</param> /// <param name="size">The size of the image to render into, layout html by width and clipped by height</param> /// <param name="textRenderingHint">optional: (default - SingleBitPerPixelGridFit)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the generated image of the html</returns> public static Image RenderToImageGdiPlus(string html, Size size, TextRenderingHint textRenderingHint = TextRenderingHint.AntiAlias, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { var image = new Bitmap(size.Width, size.Height, PixelFormat.Format32bppArgb); using (var g = Graphics.FromImage(image)) { g.TextRenderingHint = textRenderingHint; RenderHtml(g, html, PointF.Empty, size, cssData, true, stylesheetLoad, imageLoad); } return image; }
/// <summary> /// Renders the specified HTML source on the specified location and max size restriction.<br/> /// Use GDI+ text rending, use <see cref="Graphics.TextRenderingHint"/> to control text rendering.<br/> /// If <paramref name="maxWidth"/> is zero the html will use all the required width, otherwise it will perform line /// wrap as specified in the html<br/> /// Returned is the actual width and height of the rendered html.<br/> /// </summary> /// <param name="g">Device to render with</param> /// <param name="html">HTML source to render</param> /// <param name="left">optional: the left most location to start render the html at (default - 0)</param> /// <param name="top">optional: the top most location to start render the html at (default - 0)</param> /// <param name="maxWidth">optional: bound the width of the html to render in (default - 0, unlimited)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the actual size of the rendered html</returns> public static SizeF RenderGdiPlus(Graphics g, string html, float left = 0, float top = 0, float maxWidth = 0, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { ArgChecker.AssertArgNotNull(g, "g"); return RenderClip(g, html, new PointF(left, top), new SizeF(maxWidth, 0), cssData, true, stylesheetLoad, imageLoad); }
/// <summary> /// Renders the specified HTML into a new image of unknown size that will be determined by min/max width/height and HTML layout.<br/> /// If <paramref name="maxSize.Width"/> is zero the html will use all the required width, otherwise it will perform line /// wrap as specified in the html<br/> /// If <paramref name="maxSize.Height"/> is zero the html will use all the required height, otherwise it will clip at the /// given max height not rendering the html below it.<br/> /// If <paramref name="minSize"/> (Width/Height) is above zero the rendered image will not be smaller than the given min size.<br/> /// The generated image have transparent background that the html is rendered on.<br/> /// GDI+ text rending can be controlled by providing <see cref="TextRenderingHint"/>.<br/> /// See "Rendering to image" remarks section on <see cref="HtmlRender"/>.<br/> /// </summary> /// <param name="html">HTML source to render</param> /// <param name="minSize">optional: the min size of the rendered html (zero - not limit the width/height)</param> /// <param name="maxSize">optional: the max size of the rendered html, if not zero and html cannot be layout within the limit it will be clipped (zero - not limit the width/height)</param> /// <param name="textRenderingHint">optional: (default - SingleBitPerPixelGridFit)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the generated image of the html</returns> public static Image RenderToImageGdiPlus(string html, Size minSize, Size maxSize, TextRenderingHint textRenderingHint = TextRenderingHint.AntiAlias, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { if (string.IsNullOrEmpty(html)) return new Bitmap(0, 0, PixelFormat.Format32bppArgb); using (var container = new HtmlContainer()) { container.AvoidAsyncImagesLoading = true; container.AvoidImagesLateLoading = true; container.UseGdiPlusTextRendering = true; if (stylesheetLoad != null) container.StylesheetLoad += stylesheetLoad; if (imageLoad != null) container.ImageLoad += imageLoad; container.SetHtml(html, cssData); var finalSize = MeasureHtmlByRestrictions(container, minSize, maxSize); container.MaxSize = finalSize; // create the final image to render into by measured size var image = new Bitmap(finalSize.Width, finalSize.Height, PixelFormat.Format32bppArgb); // render HTML into the image using (var g = Graphics.FromImage(image)) { g.TextRenderingHint = textRenderingHint; container.PerformPaint(g); } return image; } }
/// <summary> /// Renders the specified HTML source on the specified location and max size restriction.<br/> /// Use GDI+ text rending, use <see cref="Graphics.TextRenderingHint"/> to control text rendering.<br/> /// If <paramref name="maxSize"/>.Width is zero the html will use all the required width, otherwise it will perform line /// wrap as specified in the html<br/> /// If <paramref name="maxSize"/>.Height is zero the html will use all the required height, otherwise it will clip at the /// given max height not rendering the html below it.<br/> /// Returned is the actual width and height of the rendered html.<br/> /// </summary> /// <param name="g">Device to render with</param> /// <param name="html">HTML source to render</param> /// <param name="location">the top-left most location to start render the html at</param> /// <param name="maxSize">the max size of the rendered html (if height above zero it will be clipped)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the actual size of the rendered html</returns> public static SizeF RenderGdiPlus(Graphics g, string html, PointF location, SizeF maxSize, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { ArgChecker.AssertArgNotNull(g, "g"); return RenderClip(g, html, location, maxSize, cssData, true, stylesheetLoad, imageLoad); }
/// <summary> /// Renders the specified HTML source on the specified location and max size restriction.<br/> /// If <paramref name="maxSize"/>.Width is zero the html will use all the required width, otherwise it will perform line /// wrap as specified in the html<br/> /// If <paramref name="maxSize"/>.Height is zero the html will use all the required height, otherwise it will clip at the /// given max height not rendering the html below it.<br/> /// Returned is the actual width and height of the rendered html.<br/> /// </summary> /// <param name="g">Device to render with</param> /// <param name="html">HTML source to render</param> /// <param name="location">the top-left most location to start render the html at</param> /// <param name="maxSize">the max size of the rendered html (if height above zero it will be clipped)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="useGdiPlusTextRendering">true - use GDI+ text rendering, false - use GDI text rendering</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the actual size of the rendered html</returns> private static SizeF RenderHtml(Graphics g, string html, PointF location, SizeF maxSize, CssData cssData, bool useGdiPlusTextRendering, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad, EventHandler<HtmlImageLoadEventArgs> imageLoad) { SizeF actualSize = SizeF.Empty; if (!string.IsNullOrEmpty(html)) { using (var container = new HtmlContainer()) { container.Location = location; container.MaxSize = maxSize; container.AvoidAsyncImagesLoading = true; container.AvoidImagesLateLoading = true; container.UseGdiPlusTextRendering = useGdiPlusTextRendering; if (stylesheetLoad != null) container.StylesheetLoad += stylesheetLoad; if (imageLoad != null) container.ImageLoad += imageLoad; container.SetHtml(html, cssData); container.PerformLayout(g); container.PerformPaint(g); actualSize = container.ActualSize; } } return actualSize; }
/// <summary> /// Renders the specified HTML source on the specified location and max width restriction.<br/> /// If <paramref name="maxWidth"/> is zero the html will use all the required width, otherwise it will perform line /// wrap as specified in the html<br/> /// Returned is the actual width and height of the rendered html.<br/> /// </summary> /// <param name="g">Device to render with</param> /// <param name="html">HTML source to render</param> /// <param name="left">optional: the left most location to start render the html at (default - 0)</param> /// <param name="top">optional: the top most location to start render the html at (default - 0)</param> /// <param name="maxWidth">optional: bound the width of the html to render in (default - 0, unlimited)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the actual size of the rendered html</returns> public static Size Render(DrawingContext g, string html, double left = 0, double top = 0, double maxWidth = 0, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { ArgChecker.AssertArgNotNull(g, "g"); return RenderClip(g, html, new Point(left, top), new Size(maxWidth, 0), cssData, stylesheetLoad, imageLoad); }
/// <summary> /// Init with optional document and stylesheet. /// </summary> /// <param name="htmlSource">the html to init with, init empty if not given</param> /// <param name="baseCssData">optional: the stylesheet to init with, init default if not given</param> public void SetHtml(string htmlSource, CssData baseCssData = null) { Clear(); if (!string.IsNullOrEmpty(htmlSource)) { _loadComplete = false; _cssData = baseCssData ?? _adapter.DefaultCssData; DomParser parser = new DomParser(_cssParser); _root = parser.GenerateCssTree(htmlSource, this, ref _cssData); if (_root != null) { _selectionHandler = new SelectionHandler(_root); _imageDownloader = new ImageDownloader(); } } }
/// <summary> /// Measure the size (width and height) required to draw the given html under given max width restriction.<br/> /// If no max width restriction is given the layout will use the maximum possible width required by the content, /// it can be the longest text line or full image width.<br/> /// </summary> /// <param name="html">HTML source to render</param> /// <param name="maxWidth">optional: bound the width of the html to render in (default - 0, unlimited)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the size required for the html</returns> public static Size Measure(string html, double maxWidth = 0, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { Size actualSize = Size.Empty; if (!string.IsNullOrEmpty(html)) { using (var container = new HtmlContainer()) { container.MaxSize = new Size(maxWidth, 0); container.AvoidAsyncImagesLoading = true; container.AvoidImagesLateLoading = true; if (stylesheetLoad != null) container.StylesheetLoad += stylesheetLoad; if (imageLoad != null) container.ImageLoad += imageLoad; container.SetHtml(html, cssData); container.PerformLayout(); actualSize = container.ActualSize; } } return actualSize; }
/// <summary> /// Renders the specified HTML on top of the given image.<br/> /// <paramref name="image"/> will contain the rendered html in it on top of original content.<br/> /// <paramref name="image"/> must not contain transparent pixels as it will corrupt the rendered html text.<br/> /// The HTML will be layout by the given image size but may be clipped if cannot fit.<br/> /// See "Rendering to image" remarks section on <see cref="HtmlRender"/>.<br/> /// </summary> /// <param name="image">the image to render the html on</param> /// <param name="html">HTML source to render</param> /// <param name="location">optional: the top-left most location to start render the html at (default - 0,0)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> public static void RenderToImage(Image image, string html, PointF location = new PointF(), CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { ArgChecker.AssertArgNotNull(image, "image"); var maxSize = new SizeF(image.Size.Width - location.X, image.Size.Height - location.Y); RenderToImage(image, html, location, maxSize, cssData, stylesheetLoad, imageLoad); }
/// <summary> /// Renders the specified HTML source on the specified location and max size restriction.<br/> /// If <paramref name="maxSize"/>.Width is zero the html will use all the required width, otherwise it will perform line /// wrap as specified in the html<br/> /// If <paramref name="maxSize"/>.Height is zero the html will use all the required height, otherwise it will clip at the /// given max height not rendering the html below it.<br/> /// Returned is the actual width and height of the rendered html.<br/> /// </summary> /// <param name="g">Device to render with</param> /// <param name="html">HTML source to render</param> /// <param name="location">the top-left most location to start render the html at</param> /// <param name="maxSize">the max size of the rendered html (if height above zero it will be clipped)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the actual size of the rendered html</returns> public static Size Render(DrawingContext g, string html, Point location, Size maxSize, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { ArgChecker.AssertArgNotNull(g, "g"); return RenderClip(g, html, location, maxSize, cssData, stylesheetLoad, imageLoad); }
/// <summary> /// Renders the specified HTML on top of the given image.<br/> /// <paramref name="image"/> will contain the rendered html in it on top of original content.<br/> /// <paramref name="image"/> must not contain transparent pixels as it will corrupt the rendered html text.<br/> /// See "Rendering to image" remarks section on <see cref="HtmlRender"/>.<br/> /// </summary> /// <param name="image">the image to render the html on</param> /// <param name="html">HTML source to render</param> /// <param name="location">the top-left most location to start render the html at</param> /// <param name="maxSize">the max size of the rendered html (if height above zero it will be clipped)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> public static void RenderToImage(Image image, string html, PointF location, SizeF maxSize, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { ArgChecker.AssertArgNotNull(image, "image"); if (!string.IsNullOrEmpty(html)) { // create memory buffer from desktop handle that supports alpha channel IntPtr dib; var memoryHdc = Win32Utils.CreateMemoryHdc(IntPtr.Zero, image.Width, image.Height, out dib); try { // create memory buffer graphics to use for HTML rendering using (var memoryGraphics = Graphics.FromHdc(memoryHdc)) { // draw the image to the memory buffer to be the background of the rendered html memoryGraphics.DrawImageUnscaled(image, 0, 0); // render HTML into the memory buffer RenderHtml(memoryGraphics, html, location, maxSize, cssData, false, stylesheetLoad, imageLoad); } // copy from memory buffer to image CopyBufferToImage(memoryHdc, image); } finally { Win32Utils.ReleaseMemoryHdc(memoryHdc, dib); } } }
public static Metafile RenderToMetafile(string html, float left = 0, float top = 0, float maxWidth = 0, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { Metafile image; IntPtr dib; var memoryHdc = Win32Utils.CreateMemoryHdc(IntPtr.Zero, 1, 1, out dib); try { image = new Metafile(memoryHdc, EmfType.EmfPlusDual, ".."); using (var g = Graphics.FromImage(image)) { Render(g, html, left, top, maxWidth, cssData, stylesheetLoad, imageLoad); } } finally { Win32Utils.ReleaseMemoryHdc(memoryHdc, dib); } return image; }