HTML to PDF on ARM64 Linux (AWS Graviton) in C#
ARM64 servers such as AWS Graviton run .NET at a lower price per hour. SelectPdf.Universal has a native engine package for 64-bit ARM Linux: reference SelectPdf.Universal.Native.linux-arm64 instead of linux-x64, and the same code and the same Dockerfile run on ARM64.
Compiled and run: Linux ARM64 · Linux x64 · macOS ARM64 · Windows x64
Build it step by step.
-
1Install the NuGet packages
SelectPdf.Universalis the library. The native package carries the Chromium engine for one platform: add the one for the platform you run on.dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.win-x64
dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.linux-x64
dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.linux-arm64
dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.osx-arm64
-
2Create a console app
Any .NET 8 or .NET 10 project works. To follow along, create a console app, run the install commands above inside its folder, then replace
Program.cswith the code below.dotnet new console -n PdfSample cd PdfSample
-
3Import the namespaces
using System.Runtime.InteropServices; using SelectPdf.Universal;
System.Runtime.InteropServicesreports the architecture; the converter is inSelectPdf.Universal. The project referencesSelectPdf.Universal.Native.linux-arm64, the ARM64 engine, next toSelectPdf.Universal. -
4Check where it runs
// 1. Where the program runs: Arm64 on AWS Graviton and other ARM64 Linux hosts. Console.WriteLine($"{RuntimeInformation.OSDescription}, {RuntimeInformation.ProcessArchitecture}");RuntimeInformation.ProcessArchitectureprintsArm64on a Graviton instance, an ARM64 container or an ARM64 developer machine. It is only there to show the architecture; the conversion does not need it. -
5Prepare the HTML
// 2. The same code as on x64: only the engine package differs. string html = """ <html> <body style="font-family: sans-serif"> <h1>Shipping label #58213</h1> <p>Deliver to: Fabrikam Ltd, 12 King Street, London</p> <p>Rendered by SelectPdf.Universal on Linux.</p> </body> </html> """;A raw string literal holds the page. Any HTML works: a template with your data filled in, a Razor view rendered to a string, or a full page with CSS.
-
6Convert and save
HtmlToPdf converter = new HtmlToPdf(); PdfDocument doc = converter.ConvertHtmlString(html); doc.Save("label.pdf"); doc.Close();ConvertHtmlStringreturns aPdfDocument,Savewriteslabel.pdfandClosereleases it. This is the code that runs on x64; on ARM64 only the engine package differs. -
7Run it
dotnet run # or in a container on an ARM64 machine (writes label.pdf to ./out): docker build --platform linux/arm64 -t label-pdf . docker run --rm --platform linux/arm64 -v "$PWD/out:/out" -w /out label-pdf
The program writes
label.pdfto the working folder. Without a license key, every page carries a trial watermark; setGlobalProperties.LicenseKeybefore the first conversion to remove it.
The complete Program.cs.
This is the exact file our samples pipeline compiled and ran on Linux ARM64 and Linux x64 and macOS ARM64 and Windows x64 to produce the output on this page.
using System.Runtime.InteropServices;
using SelectPdf.Universal;
// 1. Where the program runs: Arm64 on AWS Graviton and other ARM64 Linux hosts.
Console.WriteLine($"{RuntimeInformation.OSDescription}, {RuntimeInformation.ProcessArchitecture}");
// 2. The same code as on x64: only the engine package differs.
string html = """
<html>
<body style="font-family: sans-serif">
<h1>Shipping label #58213</h1>
<p>Deliver to: Fabrikam Ltd, 12 King Street, London</p>
<p>Rendered by SelectPdf.Universal on Linux.</p>
</body>
</html>
""";
HtmlToPdf converter = new HtmlToPdf();
PdfDocument doc = converter.ConvertHtmlString(html);
doc.Save("label.pdf");
doc.Close();
Open the project on GitHub → this program and the variations below, ready to dotnet run
Supporting files.
Dockerfile
The same two stages as on x64. The .NET base images are multi-architecture, so on an ARM64 machine, or when building with --platform linux/arm64, they come in their ARM64 variants. There is no apt-get line: the ARM64 engine package carries everything the engine needs.
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /src COPY . . RUN dotnet publish -c Release -f net10.0 -o /out FROM mcr.microsoft.com/dotnet/runtime:10.0 # no apt-get: the Chromium closure ships in SelectPdf.Universal.Native.linux-arm64 WORKDIR /app COPY --from=build /out ./ ENTRYPOINT ["dotnet", "/app/PdfSample.dll"]
.dockerignore
Keeps the host's build output out of the image's build context, so the publish inside the container starts clean.
bin/ obj/ out/
The PDF it produces.
Download label.pdf ↓ the file this sample produced, unedited
Common problems and fixes.
The engine fails to start on ARM64
The image probably holds the x64 engine. Reference SelectPdf.Universal.Native.linux-arm64, not linux-x64, and reference only one engine package per build: they unpack into the same folder.
Building on an Apple Silicon Mac
Docker Desktop for Mac runs Linux containers, so the image needs SelectPdf.Universal.Native.linux-arm64. The osx-arm64 package is for applications that run natively on macOS.
Text in other scripts shows as boxes
The Linux base images have no fonts for CJK, Arabic and many other scripts. Reference SelectPdf.Universal.Fonts; it works the same on ARM64.
The engine does not start on an x64 machine running the ARM64 image
Docker can build an ARM64 image on an x64 machine with --platform linux/arm64, but under its emulation the Chromium engine stops with "GPU process isn't usable". Run ARM64 images on an ARM64 host: a Graviton instance, an ARM64 build agent or an Apple Silicon Mac with Docker Desktop.
Good to know.
- SelectPdf.Universal.Native.linux-arm64 holds the native engines for 64-bit Linux on ARM64 (aarch64). Source
- For ARM64 containers, reference SelectPdf.Universal.Native.linux-arm64 instead of linux-x64; everything else stays the same, and the multi-architecture .NET base images select the matching architecture. Source
- SelectPdf runs on Amazon Web Services on Linux x64 and arm64 (Graviton); on Linux, reference linux-arm64 for Graviton. Source
- On AWS Lambda, arm64 is cheaper per second and converts at a similar speed. Source
Questions, answered.
Short answers about this guide. The SelectPdf.Universal documentation covers every class and option.