DEV Community

Andriy Andruhovski for Aspose.PDF

Posted on • Edited on

8 3

Rendering HTML5 Canvas to PDF documents using Aspose.HTML

In many cases, HTML documents are used to create templates for various reports with subsequent conversion into PDF docs. The Canvas API is a powerful tool for creating images and it can also be used to place graphics in PDF documents. This API is used by writing JS-scripts that can access the canvas area through a full set of drawing functions, thus allowing for dynamically generated graphics.

Aspose.HTML supports two methods of accessing to canvas elements:

  • via JavaScript code - this is a traditional method and it is preferable when we use standard HTML docs;
  • via Aspose.HTML API - this method is more convenient for creating in-memory HTML docs;

Since the first method is very popular, we will consider only a small example of its usage.

private static void ConvertCanvastoPdf()
{
const string content =
"<!DOCTYPE html><html><head><title>A Simple Canvas Example</title><style>body{background: #aabbcc;}" +
"#canvas{margin: 10px;padding: 10px;background: #ffffff;border: 3px groove #aabbcc;}</style></head>" +
"<body>" +
"<canvas id='canvas' width='320' height='240'> Canvas not supported</canvas>" +
"<script>" +
"var canvas=document.getElementById('canvas');" +
"var context=canvas.getContext('2d');" +
"context.font='20pt Arial';context.fillStyle='navy';context.strokeStyle='blue';" +
"context.fillText('Hello Canvas', 30, 30);" +
"context.strokeText('Hello Canvas', 30, 30);" +
"</script>" +
"</body></html>";
var document = new Aspose.Html.HTMLDocument(content, string.Empty);
GeneratePdfDoc(document, OutputFile);
}
view raw Program.cs hosted with ❤ by GitHub

As has been said before, we will use the Aspose.HTML API in the second method. This method has some differences from the previous, mainly because of the features of the .NET platform, but the main concept is the same.
As an example, consider the following problem: suppose that we need to generate a report for one (or several) images on which we need to mark certain regions (faces, animals, etc) and add it with text. Thus, our solution will consist of the following steps:

  • Generate a template;
  • Get details about the image (from external service);
  • Generate report as HTML document;
  • Convert HTML document to PDF one.
private static void CanvasToPdfDemo()
{
var document = CreateHtmlTemplate();
var faces = MakeAnalysisRequest(ImageFilePath).Result;
GenerateReport(document, faces);
GeneratePdfDoc(document, OutputFile);
}
view raw Program.cs hosted with ❤ by GitHub

Step 1 is pretty straightforward:

private static HTMLDocument CreateHtmlTemplate()
{
var document = new Aspose.Html.HTMLDocument();
document.AppendChild(document.CreateDocumentType("html", "", "", ""));
document.DocumentElement.SetAttribute("lang", "en");
document.Title = "Face detection report";
var head = document.GetElementsByTagName("head")[0];
var metaCharSet = (HTMLMetaElement)document.CreateElement("meta");
metaCharSet.SetAttribute("charset", "utf-8");
var metaViewPort = (HTMLMetaElement)document.CreateElement("meta");
metaViewPort.Name = "viewport";
metaViewPort.Content = "width=device-width, initial-scale=1";
head.AppendChild(metaCharSet);
head.AppendChild(metaViewPort);
var header1 = (HTMLHeadingElement)document.CreateElement("h1");
header1.TextContent = "Detection report";
document.DocumentElement.LastElementChild.AppendChild(header1);
var canvas = (HTMLCanvasElement)document.CreateElement("canvas");
canvas.Style.CSSText = "border: 1px solid black";
document.DocumentElement.LastElementChild.AppendChild(canvas);
return document;
}
view raw Program.cs hosted with ❤ by GitHub

In step 2, we will use Microsoft Cognitive Services (Face API). You may learn more about this service on Microsoft Docs. In short, we call the REST API and get the result with a set of detected faces with additional info.

/// <summary>
/// Gets the analysis of the specified image by using the Face REST API.
/// </summary>
/// <param name="imageFilePath">The image file.</param>
private static async Task<Microsoft.ProjectOxford.Face.Contract.Face[]> MakeAnalysisRequest(string imageFilePath)
{
const string subscriptionKey = "*************";
const string uriBase = "https://westcentralus.api.cognitive.microsoft.com/face/v1.0";
var faceServiceClient = new FaceServiceClient(subscriptionKey, uriBase);
return await faceServiceClient.DetectAsync(imageFilePath, false, true,
new[] { FaceAttributeType.Gender, FaceAttributeType.Age });
}
}
}
view raw Program.cs hosted with ❤ by GitHub

Now we can add the data to report: modify canvas and add p element after the canvas. In order to modify canvas, we need to get the context of this element and make the drawing.

var imageObj = (HTMLImageElement)document.CreateElement("img");
imageObj.Src = ImageFilePath;
var canvas = (HTMLCanvasElement)document.GetElementsByTagName("canvas")[0];
canvas.Width = canvasWidth;
canvas.Height = canvasHeight;
var context = (ICanvasRenderingContext2D)canvas.GetContext("2d");
context.ClearRect(0, 0, canvasWidth, canvasHeight);
context.DrawImage(imageObj, 0, 0);
context.BeginPath();
context.LineWidth = 2.0;
view raw gistfile1.cs hosted with ❤ by GitHub

The resulting object from the previous step is an array, which contains rectangles, that describes face locations on the image. So, we run the loop and draw the rectangles in the manner as in JavaScript code. At the last, we add details as p elements below canvas.

private static void GenerateReport(HTMLDocument document, Face[] faces)
{
const int canvasWidth = 640;
const int canvasHeight = 480;
var colors = new[] {
"Red", "Cyan", "Orange", "Green", "Blue", "Purple", "Black", "Aqua", "Olive", "Navy", "Teal",
"Maroon", "Gray", "Beige", "MediumSlateBlue", "Aquamarine", "LightSalmon", "Gold", "LightSeaGreen",
"Violet", "Chartreuse", "LightSalmon", "MediumSlateBlue"
};
var imageObj = (HTMLImageElement)document.CreateElement("img");
{
imageObj.Src = ImageFilePath;
var canvas = (HTMLCanvasElement)document.GetElementsByTagName("canvas")[0];
canvas.Width = canvasWidth;
canvas.Height = canvasHeight;
var context = (ICanvasRenderingContext2D)canvas.GetContext("2d");
context.ClearRect(0, 0, canvasWidth, canvasHeight);
context.DrawImage(imageObj, 0, 0);
context.BeginPath();
context.LineWidth = 2.0;
for (var i = 0; i < faces.Length; i++)
{
context.StrokeStyle = colors[i % 24];
context.StrokeRect(
faces[i].FaceRectangle.Left,
faces[i].FaceRectangle.Top,
faces[i].FaceRectangle.Width,
faces[i].FaceRectangle.Height);
context.Stroke();
var paragraph = (HTMLParagraphElement)document.CreateElement("p");
paragraph.TextContent = $"{colors[i]} - {faces[i].FaceAttributes.Age}, {faces[i].FaceAttributes.Gender}";
document.DocumentElement.LastElementChild.AppendChild(paragraph);
}
}
}
view raw Program.cs hosted with ❤ by GitHub

Оbtained HTML document we can easily convert to PDF.

private static void GeneratePdfDoc(HTMLDocument document, string outputfile)
{
var options = new PdfRenderingOptions();
options.PageSetup.AnyPage.Margin.Top = Unit.FromMillimeters(20);
options.PageSetup.AnyPage.Margin.Bottom = Unit.FromMillimeters(20);
options.PageSetup.AnyPage.Margin.Left = Unit.FromMillimeters(20);
options.PageSetup.AnyPage.Margin.Right = Unit.FromMillimeters(20);
Console.WriteLine("Render PDF file started...");
var device = new PdfDevice(options, outputfile);
var renderer = new HtmlRenderer();
renderer.Render(device, document);
Console.WriteLine("Render PDF file finished.");
}
view raw Program.cs hosted with ❤ by GitHub

You can see full example here:

using System;
using System.Threading.Tasks;
using Aspose.Html;
using Aspose.Html.Dom.Canvas;
using Aspose.Html.Drawing;
using Aspose.Html.Rendering;
using Aspose.Html.Rendering.Pdf;
using Microsoft.ProjectOxford.Face;
using Microsoft.ProjectOxford.Face.Contract;
namespace Canvas
{
class Program
{
private const string ImageFilePath = "http://universe.bits-pilani.ac.in/Uploads/Pilani/pilanibiologicalScienceadmin/Gallery/2015-1-5--14-36-35-944_6.JPG";
private const string OutputFile = @"C:\aspose\pdf\output01.pdf";
private static void Main()
{
ConvertCanvastoPdf();
//ConvertCanvastoPdf2();
CanvasToPdfDemo();
}
private static void ConvertCanvastoPdf()
{
const string content = "<!DOCTYPE html><html><head><title>A Simple Canvas Example</title><style>body{background: #aabbcc;}" +
"#canvas{margin: 10px;padding: 10px;background: #ffffff;border: 3px groove #aabbcc;}</style></head>" +
"<body>" +
"<canvas id='canvas' width='320' height='240'> Canvas not supported</canvas>" +
"<script>" +
"var canvas=document.getElementById('canvas');" +
"var context=canvas.getContext('2d');" +
"context.font='20pt Arial';context.fillStyle='navy';context.strokeStyle='blue';" +
"context.fillText('Hello Canvas', 30, 30);" +
"context.strokeText('Hello Canvas', 30, 30);" +
"</script>" +
"</body></html>";
var document = new HTMLDocument(content, string.Empty);
GeneratePdfDoc(document, OutputFile);
}
private static void CanvasToPdfDemo()
{
var document = CreateHtmlTemplate();
var faces = MakeAnalysisRequest(ImageFilePath).Result;
GenerateReport(document, faces);
GeneratePdfDoc(document, OutputFile);
}
private static void GenerateReport(HTMLDocument document, Face[] faces)
{
const int canvasWidth = 640;
const int canvasHeight = 480;
var colors = new[] {
"Red", "Cyan", "Orange", "Green", "Blue", "Purple", "Black", "Aqua", "Olive", "Navy", "Teal",
"Maroon", "Gray", "Beige", "MediumSlateBlue", "Aquamarine", "LightSalmon", "Gold", "LightSeaGreen",
"Violet", "Chartreuse", "LightSalmon", "MediumSlateBlue"
};
var imageObj = (HTMLImageElement)document.CreateElement("img");
imageObj.Src = ImageFilePath;
var canvas = (HTMLCanvasElement)document.GetElementsByTagName("canvas")[0];
canvas.Width = canvasWidth;
canvas.Height = canvasHeight;
var context = (ICanvasRenderingContext2D)canvas.GetContext("2d");
context.ClearRect(0, 0, canvasWidth, canvasHeight);
context.DrawImage(imageObj, 0, 0);
context.BeginPath();
context.LineWidth = 2.0;
for (var i = 0; i < faces.Length; i++)
{
context.StrokeStyle = colors[i % 24];
context.StrokeRect(
faces[i].FaceRectangle.Left,
faces[i].FaceRectangle.Top,
faces[i].FaceRectangle.Width,
faces[i].FaceRectangle.Height);
context.Stroke();
var paragraph = (HTMLParagraphElement)document.CreateElement("p");
paragraph.TextContent = $"{colors[i]} - {faces[i].FaceAttributes.Age}, {faces[i].FaceAttributes.Gender}";
document.DocumentElement.LastElementChild.AppendChild(paragraph);
}
}
private static void GeneratePdfDoc(HTMLDocument document, string outputfile)
{
var options = new PdfRenderingOptions();
options.PageSetup.AnyPage.Margin.Top = Unit.FromMillimeters(20);
options.PageSetup.AnyPage.Margin.Bottom = Unit.FromMillimeters(20);
options.PageSetup.AnyPage.Margin.Left = Unit.FromMillimeters(20);
options.PageSetup.AnyPage.Margin.Right = Unit.FromMillimeters(20);
Console.WriteLine("Render PDF file started...");
var device = new PdfDevice(options, outputfile);
var renderer = new HtmlRenderer();
renderer.Render(device, document);
Console.WriteLine("Render PDF file finished.");
}
private static HTMLDocument CreateHtmlTemplate()
{
var document = new HTMLDocument();
document.AppendChild(document.CreateDocumentType("html", "", "", ""));
document.DocumentElement.SetAttribute("lang", "en");
document.Title = "Face detection report";
var head = document.GetElementsByTagName("head")[0];
var metaCharSet = (HTMLMetaElement)document.CreateElement("meta");
metaCharSet.SetAttribute("charset", "utf-8");
var metaViewPort = (HTMLMetaElement)document.CreateElement("meta");
metaViewPort.Name = "viewport";
metaViewPort.Content = "width=device-width, initial-scale=1";
head.AppendChild(metaCharSet);
head.AppendChild(metaViewPort);
var header1 = (HTMLHeadingElement)document.CreateElement("h1");
header1.TextContent = "Detection report";
document.DocumentElement.LastElementChild.AppendChild(header1);
var canvas = (HTMLCanvasElement)document.CreateElement("canvas");
canvas.Style.CSSText = "border: 1px solid black";
document.DocumentElement.LastElementChild.AppendChild(canvas);
return document;
}
/// <summary>
/// Gets the analysis of the specified image by using the Face REST API.
/// </summary>
/// <param name="imageFilePath">The image file.</param>
private static async Task<Face[]> MakeAnalysisRequest(string imageFilePath)
{
const string subscriptionKey = "<key>";
const string uriBase = "https://westcentralus.api.cognitive.microsoft.com/face/v1.0";
var faceServiceClient = new FaceServiceClient(subscriptionKey, uriBase);
return await faceServiceClient.DetectAsync(imageFilePath, false, true,
new[] { FaceAttributeType.Gender, FaceAttributeType.Age });
}
}
}
view raw CanvasDemo.cs hosted with ❤ by GitHub

Image of Docusign

Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

Top comments (1)

Collapse
 
pawan_singh_9cd584625b956 profile image
Pawan Singh • Edited

Pdf must be in form of vector not image