Cette page peut contenir du texte traduit automatiquement.

Guide de démarrage rapide de la génération PDF C#

Découvrez comment générer des fichiers PDF tels que des rapports, des factures et des reçus dans vos projets .NET. À l'aide de C# ou de VB.NET, créez facilement des documents PDF en composant des éléments structurels. Les éléments incluent des en-têtes, des pieds de page, des conteneurs, des tableaux, des paragraphes, des images, etc. L'API divise automatiquement le contenu en pages.

Certaines autres méthodes de génération de fichiers PDF décrites dans l'article Créer des documents PDF en C# et VB.NET.

Présentation de la bibliothèque de génération PDF

Nous proposons l'API de mise en page en tant que module complémentaire gratuit pour la bibliothèque Docotic.Pdf. La bibliothèque et le module complémentaire Layout sont disponibles sur NuGet et sur notre site. Pour essayer la bibliothèque sans restrictions du mode d'évaluation, obtenez la clé de licence gratuite à durée limitée sur la page de la bibliothèque.

Bibliothèque Docotic.Pdf 9.4.17469-dev Module complémentaire de mise en page 9.4.17469-dev
Tests de régression 14,760 réussis Téléchargements totaux de NuGet 4,447,259

Installation

Installez le package BitMiracle.Docotic.Pdf.Layout à partir de NuGet. Il s’agit du moyen le plus simple et le plus pratique d’installer le module complémentaire Layout.

Comme alternative, vous pouvez télécharger le ZIP avec les binaires de la bibliothèque sur notre site. Pour utiliser l'API Layout, ajoutez des références aux DLL suivantes à partir du package ZIP :

  • BitMiracle.Docotic.Pdf.dll
  • Layout add-on/BitMiracle.Docotic.Pdf.Layout.dll

L'approche

Le point d'entrée est la classe PdfDocumentBuilder. Pour commencer à générer un PDF, vous appelez la méthode Generate de la classe. La méthode nécessite un délégué de type Action<Document> comme l'un de ses paramètres. La bibliothèque attend de vous que vous mettiez en page le contenu du document dans le délégué.

PdfDocumentBuilder.Create().Generate("output.pdf", (Document doc) =>
{
    // créer le contenu du document ici
});

Étant donné un objet Document, le délégué doit définir la mise en page. La disposition complète se compose de blocs de construction plus petits. Les pages, les en-têtes et pieds de page, les conteneurs, les blocs de texte sont des exemples de tels blocs.

De nombreux appels de méthode sont enchaînés. L'ordre des appels dans une chaîne est important. Voici un exemple qui montre comment configurer le contenu des pages en quelques appels enchaînés.

PdfDocumentBuilder.Create()
    .Generate("output.pdf", doc => doc.Pages(pages =>
    {
        pages.Content().Padding(24).AlignCenter().Text("Some text");
    }));

Intellisense vous aidera à découvrir l'API. Essayez l'API vous-même. J'espère que vous le trouverez facile à utiliser.

Bonjour le monde!

Développons une application simple qui montre les éléments de base courants en action. L'application utilisera l'approche mentionnée ci-dessus.

J'ai mis le code complet de l'application dans notre référentiel de codes d'exemple Docotic.Pdf. Le code de cette étape se trouve dans la classe HelloWorld de l'exemple d'application.

public void CreatePdf()
{
    PdfDocumentBuilder.Create().Generate("hello.pdf", doc => doc.Pages(page =>
    {
        page.Content().Text("Hello, world!");
    }));
}

Pas beaucoup de code, mais que se passe-t-il ici ?

Longue explication pour le short code

Le code crée une instance du générateur de documents et demande au constructeur de générer hello.pdf. Le constructeur délègue le travail de mise en page du contenu du document à mon code.

Dans le code du délégué, je demande au document de construire quelques pages. Maintenant, le document délègue le travail de présentation du contenu des pages à mon code.

Dans le délégué des pages, j'accède au conteneur de mise en page pour le contenu principal des pages. Je fais cela en appelant la méthode Content. L'appel chaîné à Text ajoute la fameuse étendue de texte au contenu des pages.

Il est maintenant temps pour le constructeur de générer le document avec quelques pages selon la mise en page fournie. Le générateur crée le nombre exact de pages requis pour contenir les données que j'ai ajoutées dans le conteneur de mise en page pour le contenu principal. Une page suffit dans ce cas ? D'accord.

Préparez-vous aux futures mises à jour

Je vais ajouter quelques fonctionnalités supplémentaires au code. Pour faciliter le développement ultérieur de l'application, j'ai modifié le code comme ceci :

public void CreatePdf()
{
    PdfDocumentBuilder.Create().Generate("hello.pdf", BuildDocument);
}

static void BuildDocument(Document doc)
{
    doc.Pages(BuildPages);
}

static void BuildPages(PageLayout pages)
{
    pages.Content().Text("Hello, world!");
}

Cela peut sembler inutile, mais diviser le code en méthodes le rend au moins plus lisible.

L'exemple de code pour cette étape se trouve dans la classe HelloWorld2 de l'exemple d'application.

Veuillez consulter les articles suivants pour plus d'informations sur les documents, les pages et les conteneurs.

Polices et couleurs

La police par défaut est bonne, mais je vais vous montrer comment en utiliser une autre. L'idée principale est de créer un style de texte à l'aide d'une police. Ensuite, si nécessaire, appliquez certaines propriétés facultatives au style et, enfin, utilisez le style sur une étendue de texte.

Vous pouvez utiliser une police de la collection de polices installée dans le système d'exploitation ou charger une police à partir d'un fichier ou d'un flux.

Je recommande de remplacer les styles prédéfinis en configurant la typographie du document. Mais ce n’est pas obligatoire et vous pouvez utiliser directement les styles de texte.

L'exemple de code pour cette étape se trouve dans la classe HelloWorld3 de l'application exemple. Vous trouverez ci-dessous les parties qui ont changé par rapport à l'étape précédente.

static void BuildDocument(Document doc)
{
    doc.Typography(t =>
    {
        t.Document = doc.TextStyleWithFont(SystemFont.Family("Calibri"));
    });
    doc.Pages(BuildPages);
}

static void BuildPages(PageLayout pages)
{
    pages.Size(PdfPaperSize.A6);
    pages.Margin(10);

    BuildTextContent(pages.Content());
}

static void BuildTextContent(LayoutContainer content)
{
    var colorAccented = new PdfRgbColor(56, 194, 10);
    var styleAccented = TextStyle.Parent.FontColor(colorAccented);

    content.Text(t =>
    {
        t.Span("Hello, ").Style(styleAccented);
        t.Span("world!").Style(styleAccented.Underline());
    });
}

Comme vous pouvez le voir, j'ai mis à jour le code de BuildDocument et BuildPages. J'ai également ajouté une nouvelle méthode nommée BuildTextContent.

Dans BuildDocument, je crée un style de texte à partir de la police système nommée "Calibri". Ensuite, j'ai défini ce style de texte comme style de texte par défaut pour le document.

La méthode BuildPages contient désormais du code pour définir la taille et la marge de toutes les pages. De plus, la méthode appelle BuildTextContent, en passant le conteneur du contenu principal des pages comme paramètre.

La façon dont je construis le contenu principal est différente maintenant. J'utilise deux étendues de texte et j'applique différents styles de texte à chaque étendue. En effet, les deux travées utilisent la couleur d'accentuation, mais la deuxième travée a également un soulignement.

Le code produit un PDF avec la police et la couleur du texte personnalisées. Si votre résultat contient un message d'avertissement d'essai, veuillez obtenir une licence gratuite à durée limitée sur la page de la bibliothèque Docotic.Pdf.

De nombreux documents PDF réels, comme les rapports ou les factures, contiennent un en-tête et un pied de page. Laissez-moi vous montrer comment ajouter un en-tête et un pied de page à un PDF.

L'exemple de code pour cette étape se trouve dans la classe HelloWorld4 de l'application exemple. Vous trouverez ci-dessous les parties qui ont changé par rapport à l'étape précédente.

static void BuildPages(PageLayout pages)
{
    pages.Size(PdfPaperSize.A6);
    pages.Margin(10);

    BuildPagesHeader(pages.Header());
    BuildPagesFooter(pages.Footer());

    BuildTextContent(pages.Content());
}

static void BuildPagesHeader(LayoutContainer header)
{
    header.TextStyle(TextStyle.Parent.FontSize(8))
        .AlignRight()
        .Text(t =>
        {
            t.Line($"Created by: {Environment.UserName}");
            t.Line($"Date: {DateTime.Now}");
        });
}

static void BuildPagesFooter(LayoutContainer footer)
{
    footer.Height(20)
        .Background(new PdfGrayColor(95))
        .AlignCenter()
        .Text(t => t.CurrentPageNumber());
}

J'ai modifié la méthode BuildPages pour appeler BuildPagesHeader avec le conteneur d'en-tête comme paramètre. La méthode appelle également BuildPagesFooter en lui transmettant le conteneur de pied de page.

Le PDF avec en-tête et pied de page résultant ressemble définitivement plus à un document PDF professionnel.

La méthode BuildPagesHeader définit une taille de police plus petite pour le texte. J'utilise deux lignes pour le contenu de l'en-tête : une avec le nom de l'utilisateur actuel et la seconde avec la date actuelle. Le texte est aligné à droite.

Veuillez noter que je ne spécifie aucune taille explicite pour l'en-tête. Il occupera toute la largeur de la page moins les marges gauche et droite. La hauteur dépendra de la hauteur des lignes de texte.

Le pied de page est similaire, sauf que sa hauteur est spécifiée explicitement. Et une couleur d’arrière-plan lui est appliquée. La partie intéressante est que pour mettre le numéro de page actuel dans le pied de page du PDF, je peux simplement utiliser la méthode CurrentPageNumber. Tous les calculs ont lieu à l'intérieur de la bibliothèque.

Images

Comme on dit, vous pouvez économiser beaucoup de mots en utilisant une seule image. Dans un devis ou un reçu, vous utiliserez probablement un logo de votre entreprise ou une autre image importante. Pour cet exemple de code, j'en utiliserai juste un joli.

Le fichier est sur notre site, pour que vous puissiez voir à quoi ressemble le PDF avec la belle image résultant.

Pour utiliser une image, vous devez d'abord l'ajouter au document. La bibliothèque peut lire l'image à partir d'un fichier ou d'un flux. J'ai modifié la méthode BuildDocument pour montrer comment ajouter une image au document.

L'exemple de code pour cette étape se trouve dans la classe HelloWorld5 de l'application exemple. Vous trouverez ci-dessous les parties qui ont changé par rapport à l'étape précédente.

static void BuildDocument(Document doc)
{
    doc.Typography(t =>
    {
        t.Document = doc.TextStyleWithFont(SystemFont.Family("Calibri"));
    });

    var imageFile = new FileInfo("red-flowers-at-butterfly-world.jpg");
    var image = doc.Image(imageFile);

    doc.Pages(pages => {
        BuildPages(pages);

        pages.Content().Column(c =>
        {
            BuildTextContent(c.Item());
            BuildImageContent(c.Item(), image);
        });
    });
}

static void BuildPages(PageLayout pages)
{
    pages.Size(PdfPaperSize.A6);
    pages.Margin(10);

    BuildPagesHeader(pages.Header());
    BuildPagesFooter(pages.Footer());
}

static void BuildImageContent(LayoutContainer content, Image image)
{
    content.AlignCenter()
        .PaddingVertical(20)
        .Image(image);
}

Comme vous pouvez le voir, il y a d'autres changements dans la méthode BuildDocument. Auparavant, le code utilisait la méthode Text pour définir du texte comme contenu principal des pages. Cela se produit toujours dans la méthode BuildTextContent. Mais maintenant, je veux aussi une image dans le contenu.

Pour avoir à la fois le texte et l'image dans le contenu principal des pages, j'ai besoin d'un conteneur. J'utilise le conteneur Column pour ajouter le texte et l'image verticalement l'un après l'autre. La méthode Item du conteneur de colonnes fournit un sous-conteneur. J'utilise un appel à la méthode Item pour obtenir un conteneur pour le texte et un autre appel pour obtenir un conteneur pour l'image.

Comme vous pouvez le voir, je n'ai pas du tout modifié BuildTextContent. Mais, bien sûr, j'ai dû supprimer un appel à BuildTextContent de la méthode BuildPages.

BuildImageContent fait un travail important en trois lignes. Il ajoute l'image avec un peu de remplissage en haut et en bas. Et cela centre également l’image sur la page.

Nous avons plus d'informations sur le conteneur Column et les images dans les articles suivants.

Listes

Qu'est-ce qu'une liste ? Pensons-y comme un groupe d'éléments numérotés écrits les uns en dessous des autres. Cette idée suggère une manière de mettre en œuvre une liste.

L'exemple de code pour cette étape se trouve dans la classe HelloWorld6 de l'application exemple. Vous trouverez ci-dessous les parties qui ont changé par rapport à l'étape précédente.

static void BuildDocument(Document doc)
{
    ....

    doc.Pages(pages => {
        BuildPages(pages);

        pages.Content().Column(c =>
        {
            BuildTextContent(c.Item());
            BuildImageContent(c.Item(), image);
            BuildListContent(c.Item());
        });
    });
}

static void BuildListContent(LayoutContainer content)
{
    var dayNames = DateTimeFormatInfo.InvariantInfo.DayNames;
    var dayNamesSpain = DateTimeFormatInfo.GetInstance(new CultureInfo("es-ES")).DayNames;

    content.Column(column =>
    {
        for (int i = 0; i < dayNames.Length; i++)
        {
            column.Item().Row(row =>
            {
                row.Spacing(5);
                row.AutoItem().Text($"{i + 1}.");
                row.RelativeItem().Text(t => {
                    t.Line(dayNames[i]);
                    t.Line($"In Spain they call it {dayNamesSpain[i]}");
                });
            });
        }
    });
}

Le seul changement dans BuildDocument est le nouvel appel de méthode. J'ai ajouté l'appel à BuildListContent après l'appel BuildImageContent.

BuildListContent crée la liste sous forme de colonne de lignes. Dans chaque ligne, il y a deux éléments. Le premier (à gauche) concerne le numéro d’article. Un autre (à droite) concerne le texte de l'élément. Le code définit explicitement l'espacement entre les éléments de la ligne.

Pour organiser les éléments, le conteneur Row doit connaître au préalable ou calculer la taille de chaque élément. J'utilise les méthodes AutoItem et RelativeItem dans cet exemple. En conséquence, le conteneur de lignes calculera la largeur requise pour contenir le premier élément. Ensuite, le conteneur utilisera la largeur disponible restante pour le deuxième élément.

Après avoir ajouté la liste, le contenu du PDF résultant ne tient plus sur une page. L'API Layout ajoute automatiquement la deuxième page et y place la liste. Vous pouvez voir que l'API a répété l'en-tête et le pied de page sur la nouvelle page du document PDF avec plusieurs pages.

Nous avons plus d'informations sur les listes dans l'article Conteneurs composés.

Les tables

De nombreux documents PDF contiennent des tableaux. Il n’y a pas de surprise ici car les tables améliorent la clarté et l’organisation des données. Laissez-moi vous montrer comment créer un table au format PDF à l'aide de l'API Layout.

L'exemple de code pour cette étape se trouve dans la classe HelloWorld7 de l'application exemple. Vous trouverez ci-dessous les parties qui ont changé par rapport à l'étape précédente.

static void BuildDocument(Document doc)
{
    ....

    doc.Pages(pages => {
        BuildPages(pages);

        pages.Content().Column(c =>
        {
            BuildTextContent(c.Item());
            BuildImageContent(c.Item(), image);
            BuildListContent(c.Item());
            BuildTableContent(c.Item());
        });
    });
}

static void BuildTableContent(LayoutContainer content)
{
    var color = new PdfGrayColor(75);

    content.PaddingTop(20).Table(t =>
    {
        t.Columns(c =>
        {
            c.RelativeColumn(4);
            c.RelativeColumn(1);
            c.RelativeColumn(4);
        });

        t.Header(h =>
        {
            h.Cell().Background(color).Text("Month in 2024");
            h.Cell().Background(color).Text("Days");
            h.Cell().Background(color).Text("First Day");
        });

        for (int i = 0; i < 12; i++)
        {
            var stats = GetMonthStats(2024, i);

            t.Cell().Text(stats.Item1);
            t.Cell().Text(stats.Item2);
            t.Cell().Text(stats.Item3);
        }
    });
}

static (string, string, string) GetMonthStats(int year, int monthIndex)
{
    return (
        DateTimeFormatInfo.InvariantInfo.MonthNames[monthIndex],
        DateTime.DaysInMonth(year, monthIndex + 1).ToString(),
        new DateTime(year, monthIndex + 1, 1).DayOfWeek.ToString()
    );
}

L'appel à BuildTableContent est le seul changement dans BuildDocument.

Dans BuildTableContent, je crée un tableau simple. Le tableau affiche des informations triviales sur les mois de l'année 2024. Pour commencer, je définis trois colonnes avec des largeurs relatives. Les colonnes les plus à gauche et à droite seront 4 fois plus larges que la colonne du milieu.

Le code définit également l'en-tête du tableau. Pour ce faire, il ajoute des cellules d'en-tête et spécifie la couleur du texte et de l'arrière-plan pour chaque cellule. Lorsque le tableau ne tient pas sur une seule page, l'en-tête est répété sur chaque page occupée par le tableau. Vous pouvez le voir dans le document PDF avec tableau résultant. Dans le document, le tableau commence à la deuxième page et se poursuit sur la troisième.

J'utilise la boucle simple pour constituer des lignes. Le code dans la boucle commence par récupérer les informations sur chaque mois. Ensuite, il ajoute trois cellules constituant une ligne d'informations.

L'article Conteneur Table explique plus en détail toutes les fonctionnalités du conteneur Table.

Exemple de code

Ci-dessus, j'ai présenté certaines des fonctionnalités les plus populaires de la génération de PDF en C#. Je vous propose de continuer la découverte de l'API en lisant l'article suivant. Essayez également l'exemple de code du référentiel Docotic.Pdf.Samples sur GitHub. L'exemple de code pour l'API Layout se trouve dans le dossier Layout du référentiel.

Vous pouvez utiliser l’exemple de code comme terrain de jeu de code. De cette façon, vous pouvez essayer quelques idées sans repartir de zéro à chaque fois.

Le même exemple de code se trouve dans le dossier Samples du package ZIP. Il existe deux fichiers de solution. SamplesCSharp est destiné aux exemples de projets qui utilisent le langage C#. Et SamplesVB.NET est destiné aux versions VB.NET.