Skip to content

Commit

Permalink
Merge pull request #10 from alfattack/auto-size-images
Browse files Browse the repository at this point in the history
Automatically determine image height if one isn't provided
  • Loading branch information
mstancombe authored Apr 8, 2024
2 parents f107d80 + 6c9c962 commit e2fd2d2
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 50 deletions.
6 changes: 4 additions & 2 deletions Source/Demos/HtmlRenderer.Demo.Console/SkiaSvgConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@ public SkiaSvgConverter(string sampleRunIdentifier, string basePath) : base(samp
public async Task GenerateSampleAsync(HtmlSample sample)
{
var size = new SKSize(500, 1000);
int width = 500;
int height = 50;

using (var fileStream = File.Open(GetSamplePath(sample, ".svg"), FileMode.CreateNew))
{
await ImageGenerator.GenerateSvgAsync(sample.Html, fileStream, size, imageLoad: OnImageLoaded);
await ImageGenerator.GenerateSvgAsync(sample.Html, fileStream, width, height, imageLoad: OnImageLoaded);
fileStream.Flush();
}

using (var fileStream = File.Open(GetSamplePath(sample, ".png"), FileMode.CreateNew))
{
await ImageGenerator.GenerateBitmapAsync(sample.Html, fileStream, size, SKEncodedImageFormat.Png, 100, imageLoad: OnImageLoaded);
await ImageGenerator.GenerateBitmapAsync(sample.Html, fileStream, SKEncodedImageFormat.Png, width, imageLoad: OnImageLoaded);
fileStream.Flush();
}
}
Expand Down
93 changes: 45 additions & 48 deletions Source/HtmlRenderer.SkiaSharp/ImageGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,92 +67,89 @@ public static CssData ParseStyleSheet(string stylesheet, bool combineWithDefault
/// <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 async Task<SKCanvas> GenerateSvgAsync(
public static async Task GenerateSvgAsync(
string html,
Stream outputStream,
SKSize size,
int width,
int? height = null,
CssData cssData = null,

Check warning on line 75 in Source/HtmlRenderer.SkiaSharp/ImageGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.

Check warning on line 75 in Source/HtmlRenderer.SkiaSharp/ImageGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.
EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null,

Check warning on line 76 in Source/HtmlRenderer.SkiaSharp/ImageGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.

Check warning on line 76 in Source/HtmlRenderer.SkiaSharp/ImageGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.
EventHandler<HtmlImageLoadEventArgs> imageLoad = null)

Check warning on line 77 in Source/HtmlRenderer.SkiaSharp/ImageGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.

Check warning on line 77 in Source/HtmlRenderer.SkiaSharp/ImageGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.
{
// create svg document to render the HTML into
var canvas = SKSvgCanvas.Create(new SKRect(0, 0, size.Width, size.Height), outputStream);

// add rendered image
await DrawSvgAsync(canvas, html, size, cssData, stylesheetLoad, imageLoad);
canvas.Dispose();

return canvas;
using (var container = await CreateHtmlContainer(html, width, cssData, stylesheetLoad, imageLoad))
{
var size = new SKSize(width, height ?? container.ActualSize.Height);
var canvas = SKSvgCanvas.Create(new SKRect(0, 0, width, height ?? container.ActualSize.Height), outputStream);
await DrawHtmlToCanvas(container, canvas);
canvas.Dispose();
}
}

/// <summary>
/// Writes html to a bitmap image
/// </summary>
/// <param name="html">HTML source to create image from</param>
/// <param name="size">The size of the image</param>
/// <param name="imageFormat">The file format used to encode the image.</param>
/// <param name="quality">The quality level to use for the image. Quality range from 0-100. Higher values correspond to improved visual quality, but less compression.</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></returns>
public static async Task<SKCanvas> GenerateBitmapAsync(
public static async Task GenerateBitmapAsync(
string html,
Stream outputStream,
SKSize size,
SKEncodedImageFormat imageFormat,
int quality,
int width,
int? height = null,
int quality = 100,
CssData cssData = null,

Check warning on line 105 in Source/HtmlRenderer.SkiaSharp/ImageGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.

Check warning on line 105 in Source/HtmlRenderer.SkiaSharp/ImageGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.
EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null,

Check warning on line 106 in Source/HtmlRenderer.SkiaSharp/ImageGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.

Check warning on line 106 in Source/HtmlRenderer.SkiaSharp/ImageGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.
EventHandler<HtmlImageLoadEventArgs> imageLoad = null)

Check warning on line 107 in Source/HtmlRenderer.SkiaSharp/ImageGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.
{
using (var container = await CreateHtmlContainer(html, width, cssData, stylesheetLoad, imageLoad))
{
var bitmap = new SKBitmap(width, height ?? (int)container.ActualSize.Height);
var canvas = new SKCanvas(bitmap);
await DrawHtmlToCanvas(container, canvas);
bitmap.Encode(outputStream, imageFormat, quality);

var bitmap = new SKBitmap((int)size.Width, (int)size.Height);
var canvas = new SKCanvas(bitmap);

// add rendered image
await DrawSvgAsync(canvas, html, size, cssData, stylesheetLoad, imageLoad);
bitmap.Encode(outputStream, imageFormat, quality);

return canvas;
}
}

/// <summary>
/// Create image pages from given HTML and appends them to the provided image document.<br/>
/// Creates a html container for the suupplied content. Given a width, this will
/// determine the actual height.
/// </summary>
/// <param name="canvas">canvas to draw to</param>
/// <param name="html">HTML source to create image from</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 async Task DrawSvgAsync(
SKCanvas canvas,
string html,
SKSize size,
CssData cssData = null,
EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null,
EventHandler<HtmlImageLoadEventArgs> imageLoad = null)
private static async Task<HtmlContainer> CreateHtmlContainer(string html,
int width,
CssData? cssData = null,
EventHandler<HtmlStylesheetLoadEventArgs>? stylesheetLoad = null,
EventHandler<HtmlImageLoadEventArgs>? imageLoad = null)
{
using var container = new HtmlContainer();
var container = new HtmlContainer();

if (stylesheetLoad != null)
container.StylesheetLoad += stylesheetLoad;
if (imageLoad != null)
container.ImageLoad += imageLoad;

container.Location = new SKPoint(0, 0);
//container.MaxSize = size;
container.MaxSize = new SKSize(size.Width, 0);
container.PageSize = size;
container.MarginBottom = 0;
container.MarginLeft = 0;
container.MarginRight = 0;
container.MarginTop = 0;
container.ScrollOffset = new SKPoint(0, 0);
container.MaxSize = new SKSize(width, 0);
await container.SetHtml(html, cssData!);

// determine the actual height of the html we're rendering.
var docImageInfo = new SKImageInfo(width, width);
using (var s = SKSurface.Create(docImageInfo))
using (var g = s.Canvas)
{
await container.PerformLayout(g);
}

await container.SetHtml(html, cssData);
container.PageSize = container.ActualSize;
return container;
}

// layout the HTML with the page width restriction to know how many pages are required
private static async Task DrawHtmlToCanvas(HtmlContainer container, SKCanvas canvas)
{
await container.PerformLayout(canvas);
await container.PerformPaint(canvas);
}
Expand Down

0 comments on commit e2fd2d2

Please sign in to comment.