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
- Bonjour, PDF
- Styles d'API
- Texte & TextStyle
- Retour à la ligne du texte
- Formes
- Opacité
- Lignes & courbes
- Images
- Tableaux
- Liens & infobulles
- Polices TrueType
- Documents multi-pages
- Options d'enregistrement
- Métadonnées & version
- Conformité PDF/A
- Texte de droite à gauche
- Protection par mot de passe
- Signatures numériques
- Chiffrement à clé publique
- Fusion de PDF
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éthode | Description |
|---|---|
| .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ètre | Description |
|---|---|
| text | La chaîne à afficher. \n force un saut de ligne à cet endroit. |
| x, y | Coin supérieur gauche de la zone délimitée, en points PDF. |
| width, height | Dimensions de la zone. Le texte qui dépasserait y + height est omis. |
| style | TextStyle — la police, la taille, la couleur et l'alignement sont tous respectés. TextAlignment est relatif à la largeur de la zone. |
| returns int | Index 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éthode | Description |
|---|---|
| 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éthode | Description |
|---|---|
| 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éthode | Description |
|---|---|
| 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");
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");
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");
| Version | Notes |
|---|---|
| PdfVersion.Pdf14 | Par 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.Pdf20 | ISO 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
| Niveau | Basé sur | Notes |
|---|---|---|
| PdfConformance.PdfA1b | PDF 1.4 | Compatibilité maximale des visionneuses. Aucune transparence. Largement utilisé pour l'archivage. |
| PdfConformance.PdfA2b | PDF 1.7 | Autorise la transparence. Recommandé pour les nouvelles archives. |
| PdfConformance.PdfA3b | PDF 1.7 | Identique à PDF/A-2b avec en plus la prise en charge des pièces jointes intégrées. |
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
| Membre | Description |
|---|---|
| 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.Print | Autorise l'impression. |
| PdfPermissions.CopyText | Autorise 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
| Membre | Description |
|---|---|
| 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. |
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
| Membre | Description |
|---|---|
| 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). |
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éthode | Description |
|---|---|
| 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. |
PdfMerger est toujours en PDF 1.4, quelle que soit la version des documents sources.