/// <summary> /// Creates a new HtmlPanel and sets a basic css for it's styling. /// </summary> protected HtmlControl() { // shitty WPF rendering, have no idea why this actually makes everything sharper =/ SnapsToDevicePixels = false; _htmlContainer = new HtmlContainer(); _htmlContainer.LoadComplete += OnLoadComplete; _htmlContainer.LinkClicked += OnLinkClicked; _htmlContainer.RenderError += OnRenderError; _htmlContainer.Refresh += OnRefresh; _htmlContainer.StylesheetLoad += OnStylesheetLoad; _htmlContainer.ImageLoad += OnImageLoad; }
/// <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 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> /// Measure the size of the html by performing layout under the given restrictions. /// </summary> /// <param name="htmlContainer">the html to calculate the layout for</param> /// <param name="minSize">the minimal size of the rendered html (zero - not limit the width/height)</param> /// <param name="maxSize">the maximum 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> /// <returns>return: the size of the html to be rendered within the min/max limits</returns> private static Size MeasureHtmlByRestrictions(HtmlContainer htmlContainer, Size minSize, Size maxSize) { // use desktop created graphics to measure the HTML using (var mg = new GraphicsAdapter()) { var sizeInt = HtmlRendererUtils.MeasureHtmlByRestrictions(mg, htmlContainer.HtmlContainerInt, Utils.Convert(minSize), Utils.Convert(maxSize)); return Utils.ConvertRound(sizeInt); } }
/// <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; }