Skia
Skia is an open source 2D graphics library which provides common APIs that work across a variety of hardware and software platforms.
It's able to generate PDF files with version 1.4. Header and tail for a PDF file is usually %PDF-1.4 and %EOF.
SkiaSharp dotnetcore
Library wrapper to use Skia in a dotnet core environment,
1 dotnet add package SkiaSharp --version 1.57.1
2 dotnet add package Avalonia.Skia.Linux.Natives --version 1.57.1.4
3
4 # Install in docker container
5 apt-get install -y libfontconfig1
6
7 # begin page SkDocument
8 #end page SkDocument
9 # end page SkDocument
10 # close SkDocument
11 # flush SkFileWStream
12 # dispose SkFileWStream
13
Example controller to generate PDF
- dotnet new webapi --name test-webapi
- cd test-webapi
dotnet add package SkiaSharp --version 1.57.1
- dotnet add package Avalonia.Skia.Linux.Natives --version 1.57.1.4
- Install swagger to test invocation via GET
1 using System;
2 using System.IO;
3 using System.Threading.Tasks;
4 using Microsoft.AspNetCore.Mvc;
5 using Microsoft.Extensions.Logging;
6 using SkiaSharp;
7 using System.Net.Mime;
8
9 namespace test_webapi.Controllers
10 {
11 [ApiController]
12 [Route("[controller]")]
13 public class PdfController : ControllerBase
14 {
15 private readonly ILogger<PdfController> _logger;
16
17 public PdfController(ILogger<PdfController> logger)
18 {
19 _logger = logger;
20 }
21
22 [HttpGet]
23 [Route("[controller]/[action]/{title}")]
24 public async Task<FileResult> CreatePdf(string title)
25 {
26 /*
27 Adapted from https://github.com/mono/SkiaSharp/blob/master/samples/Gallery/Shared/Samples/CreatePdfSample.cs
28 */
29 var metadata = new SKDocumentPdfMetadata
30 {
31 Author = "Cool Developer",
32 Creation = DateTime.Now,
33 Creator = "Cool Developer Library",
34 Keywords = "SkiaSharp, Sample, PDF, Developer, Library",
35 Modified = DateTime.Now,
36 Producer = "SkiaSharp",
37 Subject = "SkiaSharp Sample PDF",
38 Title = title,
39 };
40 var millisSinceDawnTime = DateTime.Now.Ticks / 10000;
41 var filePath = $"{Path.GetTempPath()}{millisSinceDawnTime}_test.pdf";
42 using (var stream = new SKFileWStream(filePath))
43 using (var document = SKDocument.CreatePdf(stream, metadata))
44 using (var paint = new SKPaint())
45 {
46 paint.TextSize = 64.0f;
47 paint.IsAntialias = true;
48 paint.Color = (SKColor)0xFF9CAFB7;
49 paint.IsStroke = true;
50 paint.StrokeWidth = 3;
51 paint.TextAlign = SKTextAlign.Center;
52
53 // var width = 840;
54 // var height = 1188;
55 // Portrait a4 in pts units. 1 pt = 127/360mm
56 // https://en.wikipedia.org/wiki/Paper_size
57 // https://skia-doc.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkDocument.html
58 var width = 595;
59 var height = 842;
60
61 // draw page 1
62 using (var pdfCanvas = document.BeginPage(width, height))
63 {
64 // draw button
65 var nextPagePaint = new SKPaint
66 {
67 IsAntialias = true,
68 TextSize = 16,
69 Color = SKColors.OrangeRed
70 };
71 var nextText = "Next Page >>";
72 var btn = new SKRect(width - nextPagePaint.MeasureText(nextText) - 24, 0, width, nextPagePaint.TextSize + 24);
73 pdfCanvas.DrawText(nextText, btn.Left + 12, btn.Bottom - 12, nextPagePaint);
74 // make button link
75 pdfCanvas.DrawLinkDestinationAnnotation(btn, "next-page");
76
77 // draw contents
78 pdfCanvas.DrawText("...PDF 1/2...", width / 2, height / 4, paint);
79 document.EndPage();
80 }
81
82 // draw page 2
83 using (var pdfCanvas = document.BeginPage(width, height))
84 {
85 // draw link destintion
86 pdfCanvas.DrawNamedDestinationAnnotation(SKPoint.Empty, "next-page");
87
88 // draw contents
89 pdfCanvas.DrawText("...PDF 2/2...", width / 2, height / 4, paint);
90 document.EndPage();
91 }
92
93 // end the doc
94 document.Close();
95 }
96 //var mimeType = "application/pdf";
97 var mimeType = MediaTypeNames.Application.Pdf;
98
99 Task<byte[]> fileBytes = System.IO.File.ReadAllBytesAsync(filePath);
100 await fileBytes;
101 return File(fileBytes.Result, mimeType, $"{millisSinceDawnTime}_test.pdf");
102 }
103 }
104 }