← Accueil
Démarrage rapide

Votre premier PDF en deux minutes

Majorsilence.Pdf est une bibliothèque PDF autonome et sans dépendance pour .NET 8 et 10. Un seul package, aucun binaire natif — créez des documents, dessinez du texte, des formes et des images, intégrez des polices TrueType, et enregistrez dans un fichier ou un flux.


Installation

Un seul package NuGet — aucune bibliothèque compagne requise :

# .NET CLI
dotnet add package Majorsilence.Pdf

# Package Manager Console
Install-Package Majorsilence.Pdf

Bonjour, PDF

Créez un document avec PdfDocument.Create(), ajoutez une page, dessinez sur le canevas, puis enregistrez. Les coordonnées sont exprimées en points PDF (1 pt = 1/72 pouce), l'origine étant le coin supérieur gauche — Y augmente vers le bas.

using Majorsilence.Pdf;

PdfDocument.Create()
    .AddPage(PageSizes.A4, canvas =>
    {
        canvas.DrawText("Hello, PDF!", 72, 72,
            TextStyle.Default.WithSize(24).WithBold());
        canvas.DrawLine(72, 96, 520, 96);
    })
    .Save("hello.pdf");

Styles d'API — callback vs incrémental

Choisissez celui qui convient le mieux à la structure de votre code :

Style callback (chaîne fluide)

Passez un lambda de dessin à AddPage. Le document est retourné pour pouvoir continuer à chaîner. Idéal pour des documents courts construits en une seule passe.

PdfDocument.Create()
    .WithTitle("My Report")
    .AddPage(PageSizes.A4, canvas =>
    {
        canvas.DrawText("Chapter 1", 72, 72,
            TextStyle.Default.WithSize(18).WithBold());
    })
    .AddPage(PageSizes.A4, canvas =>
    {
        canvas.DrawText("Chapter 2", 72, 72,
            TextStyle.Default.WithSize(18).WithBold());
    })
    .Save("report.pdf");

Style incrémental

AddPage sans callback retourne directement le PdfCanvas. Utile pour construire du contenu de façon impérative, par exemple dans une boucle.

var doc = PdfDocument.Create().WithTitle("My Report");

foreach (var chapter in chapters)
{
    var canvas = doc.AddPage(PageSizes.A4);
    canvas.DrawText(chapter.Title, 72, 72,
        TextStyle.Default.WithSize(18).WithBold());
    // ... draw body ...
}

doc.Save("report.pdf");

Texte & TextStyle

TextStyle est immuable. Chaque méthode With* retourne une nouvelle instance — l'original reste inchangé. Construisez un style de base une fois, puis dérivez-en des variantes.

var heading = TextStyle.Default
    .WithFamily("Helvetica")
    .WithSize(22)
    .WithBold()
    .WithColor(PdfColor.FromHex("#1A56A0"));

var body = TextStyle.Default
    .WithFamily("Times-Roman")
    .WithSize(11);

var mono = TextStyle.Default
    .WithFamily("Courier")
    .WithSize(10);

canvas.DrawText("Invoice #1024", 72, 72, heading);
canvas.DrawText("Due: July 17, 2026", 72, 106, body);

// Alignment
canvas.DrawText("Right-aligned", 540, 72,
    body.WithAlignment(TextAlignment.Right));

// Decorations
canvas.DrawText("underlined",     72, 140, body.WithUnderline());
canvas.DrawText("strikethrough",  72, 160, body.WithStrikethrough());
canvas.DrawText("overline",       72, 180, body.WithOverline());

Référence TextStyle

MéthodeDescription
.WithFamily(name)Police standard par nom. Intégrées : Helvetica, Times-Roman, Courier, Symbol, ZapfDingbats. Accepte aussi toute famille enregistrée dans FontRegistry.
.WithFontFile(path)Intègre une police TrueType / OpenType via un chemin de fichier absolu. Prend le pas sur WithFamily.
.WithSize(pts)Taille de police en points PDF. Par défaut : 12.
.WithColor(color)Couleur de premier plan du texte. Par défaut : PdfColor.Black.
.WithBold()Graisse grasse.
.WithItalic()Style italique.
.WithAlignment(a)TextAlignment.Left (par défaut), Center, Right. X est le point de référence.
.WithUnderline()Décoration soulignée.
.WithStrikethrough()Décoration barrée.
.WithOverline()Décoration surlignée.
.WithVertical()Fait pivoter le texte de 90° dans le sens antihoraire.
.WithRightToLeft()Inverse l'ordre des points de code pour un rendu RTL visuel (hébreu, arabe). À utiliser avec TextAlignment.Right pour que X soit l'ancrage droit.

PdfColor

// Named colours
PdfColor.Black    PdfColor.White    PdfColor.Red
PdfColor.Green    PdfColor.Blue     PdfColor.Yellow
PdfColor.Orange   PdfColor.Gray     PdfColor.LightGray   PdfColor.DarkGray

// From CSS hex string
PdfColor.FromHex("#1A56A0")

// From RGB bytes (0–255)
PdfColor.FromRgb(26, 86, 160)

// Constructor form — same as FromRgb
new PdfColor(26, 86, 160)

Mesurer la largeur du texte

Utilisez MeasureTextWidth pour positionner des libellés par rapport à un autre contenu :

float w = canvas.MeasureTextWidth("Hello", body);
canvas.DrawText("World", 72 + w + 4, 72, body);

Retour à la ligne multi-lignes

DrawTextBox ajuste automatiquement le texte dans une zone délimitée. Les retours à la ligne explicites (\n) forcent un saut de ligne ; les mots ne sont jamais coupés en leur milieu. La méthode retourne l'index dans la chaîne où le texte a dépassé la zone, afin que vous puissiez poursuivre le paragraphe dans une seconde zone ou sur la page suivante.

var body = TextStyle.Default.WithFamily("LiberationSans").WithSize(11);

string text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
              "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n\n" +
              "Second paragraph starts here.";

// Render into a 400 × 120 pt box; returns index of first character that did not fit
int overflow = canvas.DrawTextBox(text, x: 72, y: 72,
    width: 400, height: 120, body);

if (overflow < text.Length)
{
    // Continue overflowed text in a second box below
    canvas.DrawTextBox(text.Substring(overflow), x: 72, y: 210,
        width: 400, height: 120, body);
}

// Centre- and right-aligned boxes
canvas.DrawTextBox("Centred text\nSecond line", 72, 350, 300, 80,
    body.WithAlignment(TextAlignment.Center));

canvas.DrawTextBox("Right-aligned\nAll lines snap right", 72, 450, 300, 80,
    body.WithAlignment(TextAlignment.Right));

Référence DrawTextBox

ParamètreDescription
textLa chaîne à afficher. \n force un saut de ligne à cet endroit.
x, yCoin supérieur gauche de la zone délimitée, en points PDF.
width, heightDimensions de la zone. Le texte qui dépasserait y + height est omis.
styleTextStyle — la police, la taille, la couleur et l'alignement sont tous respectés. TextAlignment est relatif à la largeur de la zone.
returns intIndex du premier caractère qui n'a pas tenu dans la zone. Égal à text.Length si tout le texte a tenu.

Formes

ShapeStyle contrôle le remplissage et le contour indépendamment. Toutes les méthodes de forme acceptent un ShapeStyle optionnel ; la valeur par défaut est un contour noir de 1 pt sans remplissage.

// Rectangles
canvas.DrawRectangle(50, 50, 200, 80,
    ShapeStyle.Filled(PdfColor.LightGray));

canvas.DrawRectangle(50, 150, 200, 80,
    ShapeStyle.Stroked(PdfColor.Black, width: 2));

canvas.DrawRectangle(50, 250, 200, 80,
    ShapeStyle.Filled(PdfColor.FromHex("#E8F4FF"))
              .WithStroke(PdfColor.Blue, width: 1));

canvas.DrawRectangle(50, 350, 200, 80,
    ShapeStyle.Stroked(PdfColor.DarkGray).Dashed());

// Ellipses (same ShapeStyle options)
canvas.DrawEllipse(300, 50, 150, 80,
    ShapeStyle.Filled(PdfColor.Blue));

// Polygons
var triangle = new List<(float x, float y)>
{
    (300, 200), (400, 350), (200, 350)
};
canvas.DrawPolygon(triangle,
    ShapeStyle.Filled(PdfColor.Orange)
              .WithStroke(PdfColor.DarkGray));

Référence ShapeStyle

Fabrique / méthodeDescription
ShapeStyle.Filled(color)Remplissage plein, sans contour.
ShapeStyle.Stroked(color, width)Contour seul, sans remplissage. Largeur par défaut : 1.
.WithFill(color)Ajoute ou remplace la couleur de remplissage.
.WithStroke(color, width)Ajoute ou remplace la couleur et la largeur du contour.
.WithNoFill()Supprime le remplissage.
.WithNoStroke()Supprime le contour.
.Dashed()Style de trait en tirets pour le contour.
.Dotted()Style de trait en pointillés pour le contour.
.WithFillOpacity(alpha)Transparence du remplissage. 1.0 = opaque (par défaut) ; 0.0 = entièrement transparent. Voir Opacité.
.WithStrokeOpacity(alpha)Transparence du contour. Même échelle que WithFillOpacity.

Opacité & transparence

Réglez la transparence du remplissage et du contour indépendamment sur les formes, ou définissez l'opacité globale d'une ligne via StrokeStyle. Toutes les valeurs d'opacité vont de 0.0 (entièrement transparent) à 1.0 (entièrement opaque, la valeur par défaut).

// Fill opacity ramp — five blue squares from opaque to 20 % opacity
for (int i = 0; i < 5; i++)
    canvas.DrawRectangle(72 + i * 50, 100, 40, 40,
        ShapeStyle.Filled(PdfColor.Blue).WithFillOpacity(1f - i * 0.2f));

// Stroke opacity
canvas.DrawRectangle(72, 170, 200, 40,
    ShapeStyle.Stroked(PdfColor.Red, 3f).WithStrokeOpacity(0.4f));

// Overlapping semi-transparent shapes — backgrounds show through
canvas.DrawRectangle(80, 240, 150, 100, ShapeStyle.Filled(PdfColor.Red));
canvas.DrawRectangle(155, 265, 150, 100,
    ShapeStyle.Filled(PdfColor.Blue).WithFillOpacity(0.5f));
canvas.DrawEllipse(115, 300, 150, 80,
    ShapeStyle.Filled(PdfColor.Green).WithFillOpacity(0.4f));

// Line opacity via StrokeStyle
canvas.DrawLine(72, 400, 450, 400,
    StrokeStyle.Default.WithWidth(4).WithColor(PdfColor.DarkGray).WithOpacity(0.5f));

Résumé de l'API d'opacité

MéthodeDescription
ShapeStyle.WithFillOpacity(alpha)Transparence du remplissage pour les rectangles, ellipses et polygones.
ShapeStyle.WithStrokeOpacity(alpha)Transparence du contour pour les mêmes types de formes.
StrokeStyle.WithOpacity(alpha)Opacité pour les lignes tracées avec DrawLine et DrawCurve.

Lignes & courbes

StrokeStyle est à la ligne ce que ShapeStyle est aux formes remplies.

// Straight lines
canvas.DrawLine(72, 100, 520, 100);  // 1 pt solid black

canvas.DrawLine(72, 130, 520, 130,
    StrokeStyle.Default.WithWidth(2).WithColor(PdfColor.Blue));

canvas.DrawLine(72, 160, 520, 160,
    StrokeStyle.Default.WithWidth(1).Dashed());

// Smooth curve through control points (Catmull-Rom spline)
var pts = new List<(float, float)>
{
    (72, 300), (150, 260), (250, 320),
    (350, 270), (450, 310), (520, 280)
};
canvas.DrawCurve(pts,
    StrokeStyle.Default.WithWidth(2).WithColor(PdfColor.Red));

Images

DrawImage accepte soit des octets JPEG bruts, soit des octets RGB24 bruts (3 octets par pixel, ligne par ligne). L'image est placée avec son coin supérieur gauche en (x, y) et mise à l'échelle aux dimensions spécifiées.

// JPEG from disk
byte[] jpeg = File.ReadAllBytes("logo.jpg");
canvas.DrawImage(jpeg, pixelWidth: 400, pixelHeight: 200,
    isJpeg: true, x: 72, y: 72, width: 200, height: 100);

// Raw RGB24 (e.g. a gradient generated in code)
const int W = 200, H = 150;
var rgb = new byte[W * H * 3];
for (int row = 0; row < H; row++)
    for (int col = 0; col < W; col++)
    {
        int i = (row * W + col) * 3;
        rgb[i]     = (byte)(col * 255 / W);   // R
        rgb[i + 1] = (byte)(row * 255 / H);   // G
        rgb[i + 2] = 128;                     // B
    }
canvas.DrawImage(rgb, W, H, isJpeg: false,
    x: 72, y: 72, width: 200, height: 150);

Tableaux

PdfTable met en page une grille avec une ligne d'en-tête, un fond de ligne alterné optionnel, un retour à la ligne automatique du texte des cellules, et des bordures configurables. Passez-le à canvas.DrawTable() pour le dessiner à une position donnée.

// Column widths in PDF points
var table = new PdfTable(new float[] { 180, 80, 90, 90 })
    .WithHeaderBackground(new PdfColor(26, 86, 160))
    .WithAlternateRowBackground(new PdfColor(240, 245, 252))
    .WithBorder(new PdfColor(200, 200, 200), 0.5f)
    .WithCellPadding(5f)
    .WithCellTextStyle(TextStyle.Default.WithFamily("LiberationSans").WithSize(10))
    .WithHeaderTextStyle(
        TextStyle.Default.WithFamily("LiberationSans").WithSize(10)
                         .WithBold().WithColor(PdfColor.White));

// First AddRow call becomes the header row
table.AddRow("Product",         "Qty", "Unit Price", "Total");
table.AddRow("PDF Library Pro",  "3",   "$400.00",    "$1 200.00");
table.AddRow("Report Designer",  "1",   "$250.00",    "$250.00");
table.AddRow("Support (12 mo.)", "1",   "$500.00",    "$500.00");

// tableBottom receives the Y coordinate just below the last rendered row
canvas.DrawTable(table, x: 72, y: 72, out float tableBottom);

// Border-less "report" style
var report = new PdfTable(new float[] { 200, 100, 100 })
    .WithNoBorder()
    .WithHeaderBackground(new PdfColor(245, 245, 245))
    .WithCellPadding(4f)
    .WithCellTextStyle(TextStyle.Default.WithFamily("LiberationSans").WithSize(10))
    .WithHeaderTextStyle(
        TextStyle.Default.WithFamily("LiberationSans").WithSize(10).WithBold());

report.AddRow("Category",      "Revenue", "Growth");
report.AddRow("North America",  "$1.24M",  "+12%");
report.AddRow("Europe",         "$0.89M",  "+8%");

canvas.DrawTable(report, 72, 72 + tableBottom + 20);

Référence PdfTable

MéthodeDescription
new PdfTable(widths)Largeurs des colonnes en points PDF. Le nombre d'éléments définit le nombre de colonnes.
.WithHeaderBackground(color)Couleur de fond pour la première ligne (en-tête).
.WithAlternateRowBackground(color)Couleur de fond pour chaque ligne de données paire.
.WithBorder(color, width)Couleur et largeur des lignes de grille.
.WithNoBorder()Supprime toutes les lignes de grille.
.WithCellPadding(pts)Marge intérieure (tous les côtés) appliquée à chaque cellule.
.WithCellTextStyle(style)TextStyle par défaut pour les cellules de données.
.WithHeaderTextStyle(style)TextStyle pour la ligne d'en-tête.
.AddRow(col1, col2, …)Ajoute une ligne. Passez une chaîne par colonne. Le premier appel produit la ligne d'en-tête ; les appels suivants produisent des lignes de données. Le texte long des cellules s'ajuste automatiquement.
canvas.DrawTable(table, x, y)Dessine le tableau à la position donnée.
canvas.DrawTable(table, x, y, out float bottom)Identique, mais retourne également la coordonnée Y juste sous la dernière ligne — utile pour placer du contenu sous le tableau.

Liens & infobulles

Ajoutez des hyperliens cliquables ou des infobulles au survol sur n'importe quelle zone rectangulaire. La zone est définie par le coin supérieur gauche (x, y) plus width et height.

var linkStyle = TextStyle.Default
    .WithColor(PdfColor.Blue).WithUnderline();

canvas.DrawText("Visit majorsilence.com", 72, 110, linkStyle);
canvas.AddLink(72, 96, width: 220, height: 18,
    uri: "https://majorsilence.com");

// Tooltip (shows in supporting PDF viewers on hover)
canvas.DrawRectangle(72, 140, 200, 40,
    ShapeStyle.Filled(PdfColor.LightGray).WithStroke(PdfColor.Gray));
canvas.DrawText("Hover for info", 82, 165, TextStyle.Default);
canvas.AddTooltip(72, 140, 200, 40,
    tooltip: "This text appears on hover.");

Polices TrueType

Les cinq polices standard intégrées (Helvetica, Times-Roman, Courier, Symbol, ZapfDingbats) couvrent l'ASCII + le Latin-1. Pour le texte Unicode, les emoji ou le CJK, intégrez une police TrueType.

Intégration par chemin de fichier

L'option la plus simple : pointez directement TextStyle vers un fichier .ttf ou .otf. La police est lue une seule fois par document et mise en cache.

var custom = TextStyle.Default
    .WithFontFile("/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf")
    .WithSize(14);

canvas.DrawText("café résumé naïve", 72, 72, custom);
canvas.DrawText("Bold variant",      72, 96, custom.WithBold());

FontRegistry — familles nommées + chaîne de secours

Enregistrez une ou plusieurs familles sous des noms logiques, définissez la chaîne de secours (utilisée quand la police principale n'a pas de glyphe), et attachez le registre au document. Le canevas segmente alors automatiquement le texte, en acheminant chaque caractère vers la première police capable de le rendre.

var fonts = new FontRegistry()
    // Register individual variants
    .AddFamily("LiberationSans",
        regular:    "Fonts/LiberationSans-Regular.ttf",
        bold:       "Fonts/LiberationSans-Bold.ttf",
        italic:     "Fonts/LiberationSans-Italic.ttf",
        boldItalic: "Fonts/LiberationSans-BoldItalic.ttf")
    // Or scan a directory — detects variants from filenames
    .AddDirectory("Fonts/")
    // NotoSans fills in any glyph LiberationSans is missing
    .AddFallback("NotoSans");

PdfDocument.Create()
    .WithFontRegistry(fonts)
    .AddPage(PageSizes.A4, canvas =>
    {
        var style = TextStyle.Default
            .WithFamily("LiberationSans").WithSize(14);

        canvas.DrawText("Hello κόσμε мир", 72, 72, style);
        canvas.DrawText("Bold text",  72, 96, style.WithBold());
        canvas.DrawText("Italic text", 72, 118, style.WithItalic());
    })
    .Save("output.pdf");
AddDirectory attend des noms de fichiers suivant le modèle FamilyName-Regular.ttf, FamilyName-Bold.ttf, etc. Les caractères qu'aucune police enregistrée ne peut rendre sont affichés sous forme de boîtes .notdef — aucune exception n'est levée. Utilisez registry.Contains("FamilyName") pour vérifier qu'une famille a bien été chargée avant de l'utiliser.

Documents multi-pages

Appelez AddPage autant de fois que nécessaire. Les pages sont écrites dans l'ordre d'ajout.

var doc = PdfDocument.Create()
    .WithTitle("Report")
    .WithAuthor("Majorsilence")
    .WithFontRegistry(fonts);

string[] chapters = { "Introduction", "Methods", "Results" };
var title  = TextStyle.Default.WithSize(24).WithBold();
var footer = TextStyle.Default.WithSize(9).WithColor(PdfColor.Gray);

for (int i = 0; i < chapters.Length; i++)
{
    int pageNum = i + 1;
    doc.AddPage(PageSizes.A4, canvas =>
    {
        canvas.DrawText(chapters[i], 72, 72, title);
        canvas.DrawText(
            $"Page {pageNum} of {chapters.Length}",
            PageSizes.A4.Width / 2, PageSizes.A4.Height - 30,
            footer.WithAlignment(TextAlignment.Center));
    });
}

doc.Save("report.pdf");
Pages en paysage — appelez PageSizes.Letter.Landscape() (ou n'importe quelle taille) pour permuter la largeur et la hauteur. Mélangez librement les orientations entre les pages d'un même document.

Options d'enregistrement

// Write to a file
doc.Save("report.pdf");

// Write to any Stream (e.g. an ASP.NET response body)
doc.Save(Response.Body);

// Get bytes — useful for returning from an API endpoint
byte[] bytes = doc.ToBytes();
return File(bytes, "application/pdf", "report.pdf");
Les trois surcharges sont synchrones. Enveloppez-les dans un Task.Run si vous devez les appeler depuis du code asynchrone sans bloquer le pool de threads.

Métadonnées & version PDF

Les métadonnées apparaissent dans les propriétés du document de la visionneuse. La version PDF contrôle l'en-tête du fichier et le format de la table de références croisées.

PdfDocument.Create()
    .WithTitle("Invoice #INV-2026-0042")
    .WithAuthor("Majorsilence Corp")
    .WithSubject("Sales invoice")
    .WithCreator("MyApp 1.0")
    // PDF 1.4 (default) — broadest reader compatibility
    .WithVersion(PdfVersion.Pdf14)
    // PDF 2.0 — adds XMP metadata stream + compressed xref
    // .WithVersion(PdfVersion.Pdf20)
    .AddPage(PageSizes.Letter, canvas => { /* ... */ })
    .Save("invoice.pdf");
VersionNotes
PdfVersion.Pdf14Par défaut. En-tête %PDF-1.4. Table de références croisées traditionnelle. Prise en charge par pratiquement toutes les visionneuses PDF.
PdfVersion.Pdf20ISO 32000-2. En-tête %PDF-2.0. Flux de métadonnées XMP attaché au catalogue du document. Flux de références croisées compressé au lieu d'une table xref simple.

Conformité PDF/A

WithConformance marque un document comme PDF/A — un sous-ensemble ISO du PDF conçu pour l'archivage à long terme. La bibliothèque insère automatiquement le flux de métadonnées XMP requis et un intent de sortie ICC sRGB intégré. Toutes les polices doivent être intégrées via FontRegistry ; les polices Type 1 standard, le chiffrement et la transparence (pour le niveau A-1b) ne sont pas autorisés.

var fonts = new FontRegistry().AddDirectory("Fonts/").AddFallback("NotoSans");

PdfDocument.Create()
    .WithConformance(PdfConformance.PdfA2b)   // sets PDF 1.7 header automatically
    .WithFontRegistry(fonts)                   // embedded fonts are required
    .WithTitle("Archived Document")
    .WithAuthor("Majorsilence")
    .WithSubject("Archival demonstration")
    .AddPage(PageSizes.A4, canvas =>
    {
        canvas.DrawText("Archival content", 72, 72,
            TextStyle.Default.WithFamily("LiberationSans").WithSize(14));
    })
    .Save("archive.pdf");

Niveaux PdfConformance

NiveauBasé surNotes
PdfConformance.PdfA1bPDF 1.4Compatibilité maximale des visionneuses. Aucune transparence. Largement utilisé pour l'archivage.
PdfConformance.PdfA2bPDF 1.7Autorise la transparence. Recommandé pour les nouvelles archives.
PdfConformance.PdfA3bPDF 1.7Identique à PDF/A-2b avec en plus la prise en charge des pièces jointes intégrées.
Niveau B (reproductibilité visuelle) nécessite des polices intégrées, des métadonnées XMP, et un intent de sortie ICC — le tout inséré automatiquement par WithConformance. Utilisez un validateur PDF/A tel que veraPDF pour confirmer la conformité complète de votre sortie. Le PDF/A ne peut pas être combiné avec la protection par mot de passe ou le chiffrement à clé publique.

Texte de droite à gauche

Appelez .WithRightToLeft() sur un TextStyle pour inverser l'ordre des points de code afin d'obtenir un rendu RTL visuel. Associez-le à TextAlignment.Right pour que la coordonnée X soit l'ancrage droit. L'hébreu s'affiche correctement sans moteur de façonnage ; l'arabe présente une inversion visuelle (des ligatures correctes nécessitent un façonneur externe comme HarfBuzz).

using Majorsilence.Pdf;

// Build a registry with Hebrew and Arabic script fonts
var reg = new FontRegistry()
    .AddDirectory("Fonts/")          // picks up NotoSansHebrew, NotoSansArabic, etc.
    .AddFallback("NotoSans")
    .AddFallback("NotoSansHebrew")
    .AddFallback("NotoSansArabic");

// Check whether the optional script font actually loaded
string hebrewFamily = reg.Contains("NotoSansHebrew") ? "NotoSansHebrew" : "NotoSans";

float pageW      = PageSizes.A4.Width;
float rightEdge  = pageW - 72;  // right margin anchor

var rtl = TextStyle.Default
    .WithFamily(hebrewFamily)
    .WithSize(16)
    .WithRightToLeft()
    .WithAlignment(TextAlignment.Right);

PdfDocument.Create()
    .WithFontRegistry(reg)
    .AddPage(PageSizes.A4, canvas =>
    {
        canvas.DrawText("שלום עולם", rightEdge, 72, rtl.WithSize(24).WithBold());
        canvas.DrawText("ספר, ישראל, שלום, אהבה", rightEdge, 110, rtl);

        // Mix LTR and RTL on the same line
        var ltr = TextStyle.Default.WithFamily("LiberationSans").WithSize(14);
        canvas.DrawText("Hello, World!", 72, 160, ltr);
        canvas.DrawText("!שלום, עולם", rightEdge, 160, rtl.WithSize(14));
    })
    .Save("rtl.pdf");
NotoSansHebrew et NotoSansArabic sont inclus dans les polices Majorsilence.Drawing.Common fournies et sont détectés automatiquement par AddDirectory. Les caractères qu'aucune police enregistrée ne peut rendre apparaissent sous forme de boîtes .notdef.

Protection par mot de passe

Chiffrez un document afin que les lecteurs doivent fournir un mot de passe pour l'ouvrir. Vous pouvez aussi restreindre ce que le lecteur est autorisé à faire avec le document (imprimer, copier le texte, etc.).

Le chiffrement utilise le Standard Security Handler Rev 4, AES-128-CBC — l'algorithme défini dans PDF 1.5–1.7 et pris en charge par toutes les principales visionneuses.

using Majorsilence.Pdf;
using Majorsilence.Pdf.Security;

var security = PdfSecurity
    .Protect(userPassword: "open123", ownerPassword: "owner456")
    .WithPermissions(PdfPermissions.Print | PdfPermissions.CopyText);

PdfDocument.Create()
    .WithSecurity(security)
    .WithTitle("Confidential Report")
    .AddPage(PageSizes.A4, canvas =>
    {
        canvas.DrawText("Confidential document", 72, 72,
            TextStyle.Default.WithSize(18).WithBold());
    })
    .Save("protected.pdf");

Référence PdfSecurity & PdfPermissions

MembreDescription
PdfSecurity.Protect(user, owner)Crée un descripteur de sécurité. user est le mot de passe nécessaire pour ouvrir le fichier ; owner déverrouille toutes les restrictions.
.WithPermissions(flags)Champ de bits d'indicateurs PdfPermissions à accorder. Par défaut : aucune permission (lecture seule).
PdfPermissions.PrintAutorise l'impression.
PdfPermissions.CopyTextAutorise la sélection et la copie de texte.
doc.WithSecurity(security)Attache le descripteur de sécurité au document avant l'enregistrement.

Signatures numériques

Intégrez une signature numérique détachée PKCS#7 (adbe.pkcs7.detached, SHA-256) à l'aide d'un X509Certificate2 contenant une clé privée. En production, chargez le certificat depuis un X509Store ou un fichier .pfx délivré par une autorité de certification de confiance.

using Majorsilence.Pdf;
using Majorsilence.Pdf.Security;
using System.Security.Cryptography.X509Certificates;

// Load a certificate with a private key (from file, store, HSM, etc.)
X509Certificate2 cert = X509CertificateLoader.LoadPkcs12(
    File.ReadAllBytes("signer.pfx"), password: "pfxpassword",
    X509KeyStorageFlags.Exportable);

var sigOpts = new PdfSignatureOptions(cert)
    .WithReason("Document approval")
    .WithSignerName("Jane Smith")
    .WithLocation("Toronto, ON");

PdfDocument.Create()
    .WithSignature(sigOpts)
    .WithTitle("Signed Report")
    .AddPage(PageSizes.A4, canvas =>
    {
        canvas.DrawText("Digitally signed document", 72, 72,
            TextStyle.Default.WithSize(18).WithBold());
    })
    .Save("signed.pdf");

Référence PdfSignatureOptions

MembreDescription
new PdfSignatureOptions(cert)Crée des options de signature à partir d'un X509Certificate2 avec une clé privée exportable.
.WithReason(text)Raison de la signature inscrite dans le dictionnaire de signature (apparaît dans le panneau de signature de la visionneuse).
.WithSignerName(name)Nom du signataire lisible par l'humain.
.WithLocation(location)Emplacement physique ou logique de la signature.
doc.WithSignature(opts)Attache les options de signature au document. La signature est calculée et intégrée au moment de l'enregistrement.
La signature utilise SHA-256 et AES-128 (Rev 4), largement pris en charge. Ouvrez le fichier de sortie dans Adobe Acrobat ou une visionneuse compatible pour vérifier le panneau de signature. Un certificat auto-signé s'affichera comme non fiable à moins d'être ajouté au magasin de confiance de la visionneuse.

Apparence de signature visible

Appelez .WithAppearance() pour afficher une zone de signature visible sur la page — utile pour les documents nécessitant un champ « signé ici » visible. La zone affiche une bordure, « Digitally Signed », et le nom du signataire. Sans cela, la signature est cryptographiquement présente mais invisible.

var sigOpts = new PdfSignatureOptions(cert)
    .WithReason("Document approved")
    .WithSignerName("Jane Smith")
    .WithLocation("Toronto, ON")
    .WithAppearance(x: 72, y: 690, width: 220, height: 60);

PdfDocument.Create()
    .WithSignature(sigOpts)
    .AddPage(PageSizes.A4, canvas => { /* ... content ... */ })
    .Save("signed.pdf");

Chiffrement basé sur certificat

Chiffrez un PDF de sorte que seuls les détenteurs de la clé privée d'un certificat X.509 spécifique puissent l'ouvrir — aucun mot de passe partagé n'est nécessaire. Utilise /Filter /Adobe.PubSec, V=4, AES-128. Plusieurs certificats destinataires sont pris en charge ; n'importe lequel des détenteurs peut ouvrir le document.

using Majorsilence.Pdf;
using Majorsilence.Pdf.Security;
using System.Security.Cryptography.X509Certificates;

// Load the recipient's public certificate (no private key needed at encryption time)
X509Certificate2 cert = new X509Certificate2("recipient.cer");

var security = PdfPublicKeySecurity.ForRecipients(cert)
    .WithPermissions(PdfPermissions.Print | PdfPermissions.CopyText);

PdfDocument.Create()
    .WithPublicKeySecurity(security)
    .WithTitle("Confidential Report")
    .AddPage(PageSizes.A4, canvas =>
    {
        canvas.DrawText("Only the certificate holder can open this.", 72, 72,
            TextStyle.Default.WithSize(14));
    })
    .Save("encrypted.pdf");

// Multiple recipients — any one of them can open the document
var multi = PdfPublicKeySecurity.ForRecipients(cert1, cert2, cert3);

Référence PdfPublicKeySecurity

MembreDescription
PdfPublicKeySecurity.ForRecipients(cert, …)Crée un descripteur de sécurité à clé publique pour un ou plusieurs certificats destinataires. La clé publique de chaque destinataire chiffre une copie de la clé du document via CMS EnvelopedData (RSA).
.WithPermissions(flags)Champ de bits d'indicateurs PdfPermissions à accorder (mêmes indicateurs que la protection par mot de passe).
doc.WithPublicKeySecurity(security)Attache le descripteur au document. Mutuellement exclusif avec WithSecurity (mot de passe) et WithConformance (PDF/A).
En production, fournissez de vrais certificats provenant d'une autorité de certification de confiance. Pour les tests, vous pouvez générer un certificat auto-signé à l'exécution avec System.Security.Cryptography.X509Certificates.CertificateRequest — voir l'exemple 23 dans le projet d'exemples pour le modèle à suivre.

Fusion de PDF

PdfMerger concatène un nombre quelconque de tableaux d'octets PDF produits indépendamment en un seul document. Chaque PDF source peut avoir des tailles de page, des orientations et des polices intégrées différentes — elles sont toutes préservées dans la sortie.

using Majorsilence.Pdf;

// Produce two source documents as byte arrays
byte[] coverPage = PdfDocument.Create()
    .WithTitle("Quarterly Report")
    .AddPage(PageSizes.A4, canvas =>
    {
        canvas.DrawRectangle(0, 0, PageSizes.A4.Width, PageSizes.A4.Height,
            ShapeStyle.Filled(new PdfColor(30, 80, 160)));
        canvas.DrawText("Quarterly Report — Q2 2026", 72, 280,
            TextStyle.Default.WithSize(36).WithBold().WithColor(PdfColor.White));
    })
    .ToBytes();

byte[] contentPages = PdfDocument.Create()
    .AddPage(PageSizes.A4, canvas =>
    {
        canvas.DrawText("Financial Summary", 72, 72,
            TextStyle.Default.WithSize(22).WithBold());
        canvas.DrawText("Net Income: $1,500,000", 72, 120,
            TextStyle.Default.WithSize(12));
    })
    .ToBytes();

// Merge into a single document
byte[] merged = new PdfMerger()
    .Add(coverPage)
    .Add(contentPages)
    .WithTitle("Quarterly Report Q2 2026")
    .WithAuthor("Example Corp")
    .WithSubject("Financial Summary")
    .WithCreator("MyApp 2.0")
    .Merge();

File.WriteAllBytes("merged.pdf", merged);

Référence PdfMerger

MéthodeDescription
new PdfMerger()Crée un nouveau fusionneur. Aucun argument requis.
.Add(pdfBytes)Ajoute les pages d'un PDF (sous forme de byte[]) à la file de fusion. À appeler autant de fois que nécessaire ; les pages sont produites dans l'ordre.
.WithTitle(text)Titre pour les métadonnées du document fusionné.
.WithAuthor(text)Auteur pour les métadonnées du document fusionné.
.WithSubject(text)Sujet pour les métadonnées du document fusionné.
.WithCreator(text)Chaîne d'application créatrice pour les métadonnées du document fusionné.
.Merge()Exécute la fusion et retourne le PDF combiné sous forme de byte[]. La sortie est toujours en PDF 1.4.
La sortie de PdfMerger est toujours en PDF 1.4, quelle que soit la version des documents sources.