Questa pagina può contenere testo tradotto automaticamente.

Contenitori composti

I contenitori complessi svolgono un ruolo cruciale nella strutturazione e nell’organizzazione dei contenuti. Utilizzando un contenitore adeguato, puoi presentare facilmente testo e immagini in modo intuitivo.

È sicuramente possibile costruire un documento utilizzando solo semplici contenitori di testo e immagini. Tuttavia, esistono requisiti difficili o impossibili da implementare solo con contenitori semplici. I contenitori composti aiutano in questi casi. Inoltre, i contenitori complessi aiutano a raggiungere i tuoi obiettivi con meno codice.

Contenitori composti

Utilizza i metodi della classe LayoutContainer per aggiungere contenitori complessi come Row e Column alle pagine dei documenti. Utilizzando questi contenitori, puoi implementare altri contenitori come griglie ed elenchi. Esistono anche i metodi Inlined e Layers per casi meno comuni ma comunque importanti.

Questo articolo fa parte di una serie sull'API Layout per la generazione di PDF. Se sei nuovo all'API, leggi prima la parte Introduzione all'API Layout.

Libreria Docotic.Pdf 9.4.17467-dev Componente aggiuntivo di layout 9.4.17467-dev
Test di regressione Ne sono passati 14,760 Download totali di NuGet 4,415,970

Row

I contenitori Row offrono spazio per elementi disposti orizzontalmente su un'unica riga. Ogni elemento in una riga è un contenitore. Ciò significa che puoi inserire contenuti di diversi tipi in una riga. Puoi specificare la spaziatura tra gli elementi utilizzando il metodo Spacing.

Tutti gli elementi in fila hanno la stessa altezza. La libreria utilizza l'altezza dell'elemento più alto come altezza della riga. Esistono tre modi per specificare la larghezza di un elemento. Devi sceglierne uno quando crei l'oggetto. Una riga può contenere elementi creati in diversi modi.

Il metodo Row.AutoItem crea un elemento senza una larghezza specificata esplicitamente. Per tali elementi, la biblioteca calcola la dimensione intrinseca del loro contenuto. La larghezza del contenuto calcolata corrisponde alla larghezza dell'articolo. Tieni presente che gli elementi creati con AutoItem non vanno a capo nelle righe lunghe.

Utilizza il metodo ConstantItem per creare un elemento con larghezza pari a un numero esatto di punti.

Il RelativeItem è utile quando non conosci la larghezza esatta degli elementi nella riga e non vuoi utilizzare dimensioni intrinseche. Puoi invece specificare larghezze relative per gli elementi nella riga. Il metodo accetta il numero di parti che l'articolo dovrebbe occupare. Il numero totale di parti è la somma di tutti i numeri in tutte le chiamate RelativeItem in questa riga.

Ad esempio, se è presente una chiamata RelativeItem, il numero non è importante. L'articolo occuperà tutta la larghezza disponibile. Per due o più elementi, i numeri definiscono la proporzione.

row.RelativeItem(2)
row.RelativeItem(3)
row.RelativeItem(1)

Tutti gli elementi creati con il codice precedente richiedono 6 parti (2 + 3 + 1 = 6). I singoli elementi occupano rispettivamente 2 parti su 6, 3 su 6 e 1 su 6.

L'API Layout utilizza la seguente formula per calcolare la larghezza di una parte:

PartWidth = (RowWidth - AutoWidth - ConstantWidth) / TotalParts

Dove:
RowWidth = larghezza del contenitore di righe
AutoWidth = larghezza di tutti gli elementi creati con il metodo "AutoItem"
ConstantWidth = larghezza di tutti gli elementi creati con il metodo ConstantItem

Ecco un esempio che crea una riga con elementi di tutti e tre i tipi.

var monthNames = DateTimeFormatInfo.InvariantInfo.MonthNames;
var groups = new[]
{
    string.Join(", ", monthNames.Take(4)),
    string.Join(", ", monthNames.Skip(4).Take(4)),
    string.Join(", ", monthNames.Skip(8).Take(4)),
};

PdfDocumentBuilder.Create().Generate("compounds-row.pdf", doc => doc.Pages(page =>
{
    page.Content()
        .Padding(20)
        .MinimalBox()
        .Row(row =>
        {
            row.ConstantItem(100)
                .Background(new PdfRgbColor(187, 237, 237))
                .Text("100 points wide");

            for (int i = 0; i < groups.Length; i++)
            {
                row.AutoItem().LineVertical(0.1);

                var numberOfParts = groups.Length - i + 1;
                row.RelativeItem(numberOfParts)
                    .PaddingHorizontal(5)
                    .Text(t =>
                    {
                        t.Line($"{numberOfParts} parts wide");
                        t.Line();
                        t.Line(groups[i]);
                    });
            }
        });
}));

Puoi vedere il risultato del codice in compounds-row.pdf.

Column

Per disporre gli elementi verticalmente, uno dopo l'altro, utilizza un contenitore Column. Ogni elemento in una colonna è un contenitore. Per questo motivo, puoi inserire contenuti di diversi tipi in una colonna.

La larghezza di ogni elemento è uguale alla larghezza della colonna. L'altezza di ciascun articolo dipende dal contenuto e dalle proprietà dell'articolo. I contenitori Column supportano il paging, quindi il componente aggiuntivo Layout può eseguire il rendering degli elementi di una colonna su più di una pagina.

Per impostazione predefinita, un contenitore Column non ha contenuto di intestazione o piè di pagina. Utilizza i metodi Header e Footer per accedere e configurare i contenitori corrispondenti. Quando gli elementi di colonna occupano più di una pagina, la libreria ripete sia le intestazioni che i piè di pagina su ogni pagina.

Utilizza il metodo Spacing per aggiungere spazio verticale tra gli elementi della colonna. Tieni presente che la libreria non applica la spaziatura tra l'intestazione e il primo elemento. La libreria inoltre non aggiunge spazio prima del piè di pagina.

PdfDocumentBuilder.Create().Generate("compounds-column.pdf", doc => doc.Pages(page =>
{
    page.Size(PdfPaperSize.A6);

    page.Content()
        .Padding(20)
        .Column(column =>
        {
            column.Header()
                .Background(new PdfRgbColor(187, 237, 237))
                .Padding(5)
                .Text("Month names");

            for (int i = 0; i < 12; i++)
            {
                column.Item().Background(
                    new PdfGrayColor(i % 2 == 0 ? 90 : 100))
                    .Padding(5)
                    .Text(DateTimeFormatInfo.InvariantInfo.MonthNames[i]);
            }

            column.Footer().LineHorizontal(1);
        });
}));

Puoi vedere il risultato del codice in compounds-column.pdf.

Griglia

I layout a griglia organizzano gli elementi in colonne e righe. Sotto questo aspetto le griglie sono simili alle tabelle. L'API Layout non fornisce un tipo di contenitore speciale per le griglie. Puoi implementare un layout a griglia utilizzando i contenitori Column e Row.

È utile pensare a una griglia come a una colonna, in cui ciascuno dei suoi elementi è una riga. Sia i contenitori Column che quelli Row offrono la possibilità di impostare la spaziatura tra gli elementi. Puoi avere un'intestazione e un piè di pagina, se lo desideri.

Ogni riga può avere un layout indipendente. Può esserci un numero diverso di elementi in ciascuna riga. Gli articoli possono avere larghezza e altezza diverse. È possibile aggiungere spazio aggiuntivo prima, dopo o tra gli elementi di una riga. Usa oggetti senza contenuto e decorazioni per questo.

var blue = new PdfRgbColor(187, 237, 237);
var darkerBlue = blue.Darken(50);
PdfDocumentBuilder.Create().Generate("compounds-grid.pdf", doc => doc.Pages(page =>
{
    page.Size(300, 200);

    page.Content().Padding(15).Column(column =>
    {
        column.Spacing(10);

        column.Item().Row(row =>
        {
            row.Spacing(10);

            row.ConstantItem(100).Background(darkerBlue).Height(40);
            row.RelativeItem(4).Background(blue);
        });

        column.Item().Row(row =>
        {
            row.Spacing(10);

            row.RelativeItem(2).Background(blue).Height(60);
            row.RelativeItem(1);
            row.RelativeItem(2).Background(blue);
        });

        column.Item().Row(row =>
        {
            row.Spacing(10);

            row.RelativeItem(1).Background(blue).Height(50);
            row.RelativeItem(3).Background(blue);
            row.ConstantItem(50).Background(darkerBlue);
        });
    });
}));

Puoi vedere il risultato del codice in compounds-grid.pdf.

Elenchi

Gli elenchi migliorano la leggibilità suddividendo le informazioni in punti concisi. Gli elementi dell'elenco possono contenere numeri, punti elenco e altri simboli accanto al testo al loro interno. Puoi facilmente implementare un layout di elenco utilizzando i contenitori Column e Row. L'API Layout non fornisce un tipo di contenitore speciale per gli elenchi.

Controlla il codice di esempio che crea un elenco di mesi per stagione. Tieni presente che l'elenco ha un'intestazione. Se gli elementi contengono testo che può andare a capo nella riga successiva, utilizza il metodo RelativeItem o ConstantItem per la parte di testo dell'elemento.

var monthNames = DateTimeFormatInfo.InvariantInfo.MonthNames.ToList();
monthNames.Insert(0, monthNames[11]);

PdfDocumentBuilder.Create().Generate("compounds-list.pdf", doc => doc.Pages(page =>
{
    page.Size(150, 200);

    page.Content().Padding(5).Column(column =>
    {
        column.Header()
            .Text("Months by seasons:")
            .Style(TextStyle.Parent.Underline());

        for (int i = 0; i < 4; i++)
        {
            var season = string.Join(", ", monthNames.Skip(i * 3).Take(3));
            column.Item().Row(row =>
            {
                row.Spacing(2);

                row.AutoItem().Text("•");
                row.RelativeItem().Text(season);
            });
        }
    });
}));

Puoi vedere il risultato del codice in compounds-list.pdf.

Table

I layout di tabella organizzano gli elementi in colonne e righe. Il tipo di contenitore Table fornisce un ampio set di funzionalità e può aiutarti con i casi più sofisticati. Leggi tutte le funzionalità nell'articolo Contenitore Table.

InlineContainer

Puoi riempire un contenitore con una raccolta di altri contenitori. Inizia chiamando il metodo LayoutContainer.Inlined. Quindi chiama il metodo Item dell InlineContainer fornito per aggiungere contenitori secondari.

Il componente aggiuntivo Layout mette i contenitori in fila uno dopo l'altro. Se non c'è spazio per inserire un elemento, la libreria inizia una nuova riga. Utilizza i metodi Spacing/HorizontalSpacing/VerticalSpacing per aggiungere spazio tra gli elementi.

È possibile influenzare la posizione degli elementi nel contenitore utilizzando i metodi di allineamento. I metodi AlignTop/AlignMiddle/AlignBottom allineano gli elementi verticalmente. Per la direzione orizzontale, utilizzare i metodi AlignLeft/AlignCenter/AlignRight/AlignJustify.

C'è un caso speciale. Il metodo AlignSpaceAround che allinea gli elementi orizzontalmente. Aggiunge inoltre spaziatura extra prima del primo elemento e dopo l'ultimo elemento.

var orange = new PdfRgbColor(250, 123, 5);
var brown = orange.Darken(50);
var itemProps = new (int Width, PdfColor Color)[] {
    (20, orange), (30, orange), (50, brown), (50, orange), (50, orange),
    (30, orange), (20, brown), (30, orange), (50, brown), (10, brown)
};

PdfDocumentBuilder.Create().Generate("compounds-inlined.pdf", doc => doc.Pages(page =>
{
    page.Size(150, 120);

    page.Content().Inlined(c =>
    {
        c.Spacing(5);

        foreach (var (Width, Color) in itemProps)
            c.Item().Height(30).Width(Width).Background(Color);
    });
}));

Puoi vedere il risultato del codice in compounds-inlined.pdf.

LayerContainer

Potrebbe essere necessario inserire del contenuto sotto e/o sopra il contenuto della pagina principale. Il caso d'uso ovvio è aggiungere una filigrana sopra le pagine PDF.

Per prima cosa, ottieni un oggetto LayerContainer chiamando il metodo LayoutContainer.Layers. Dato l'oggetto, puoi iniziare ad aggiungere livelli. La chiamata al metodo Layer aggiunge un livello secondario. Chiama il metodo PrimaryLayer per aggiungere il livello di contenuto principale. È necessario aggiungere esattamente un livello primario.

L'API Layout comporrà i livelli nello stesso ordine in cui li crei. I livelli aggiunti prima del livello primario andranno in secondo piano. Tutti i livelli aggiunti dopo il livello primario andranno sopra il contenuto principale. Il contenitore ripete i livelli secondari su tutte le pagine occupate dal contenuto principale.

Ecco un codice di esempio su come aggiungere filigrane alle pagine PDF.

PdfDocumentBuilder.Create().Generate("compounds-layers.pdf", doc => doc.Pages(page =>
{
    var largeRedText = TextStyle.Parent.FontSize(48)
        .FontColor(new PdfRgbColor(235, 64, 52));

    page.Size(400, 250);

    page.Content()
        .Padding(25)
        .Layers(layers =>
        {
            layers.Layer()
                .AlignCenter()
                .Text(text => text.CurrentPageNumber().Style(largeRedText));

            layers.PrimaryLayer()
                .Background(new PdfGrayColor(85), 65)
                .Padding(25)
                .Text(new string('_', 790));

            layers.Layer()
                .AlignCenter()
                .AlignMiddle()
                .Text("Watermark")
                .Style(largeRedText);
        });
}));

Puoi vedere il risultato del codice in compounds-layers.pdf.

Filigrane

Uno dei requisiti comuni è aggiungere la filigrana al PDF. Il requisito può esistere per una serie di ragioni. È possibile aggiungere una filigrana al PDF per identificarne la proprietà o per evidenziare la riservatezza o la sensibilità delle informazioni nel PDF.

Un approccio per applicare la filigrana ai PDF consiste nell'utilizzare i livelli. Vedere l'esempio nella sezione precedente. Lascia che ti mostri un altro approccio.

Utilizzerò lo sfondo della pagina e i contenitori in primo piano per filigranare i PDF. Il componente aggiuntivo Layout ripete questi contenitori nelle pagine successive. Ogni pagina con contenuto del documento principale conterrà anche contenitori di sfondo e di primo piano. Questo li rende adatti al compito.

Inizio aggiungendo un'immagine al contenitore di sfondo. Puoi aggiungere il tuo logo al PDF allo stesso modo. L'immagine apparirà dietro il contenuto della pagina. Non importa quante pagine del tuo documento utilizzano l'immagine di sfondo. L'API aggiungerà solo una copia dei byte dell'immagine al PDF generato.

Il contenuto del documento principale può essere qualsiasi cosa. Per questo codice di esempio utilizzo il famoso testo Lorem Ipsum.

La filigrana del testo va nel contenitore in primo piano. Il testo stesso può essere qualsiasi cosa e puoi utilizzare qualsiasi colore o carattere. Ho utilizzato il testo ruotato disegnato con lettere rosse semitrasparenti di dimensione maggiore.

Il codice di esempio scarica in modo asincrono sia l'immagine che il testo dal nostro repository di codice di esempio. Naturalmente è possibile utilizzare un'immagine locale e/o leggere il testo da un file.

var urlPrefix =
    "https://raw.githubusercontent.com/BitMiracle/Docotic.Pdf.Samples/master/Samples/Sample%20Data/";

using var client = new HttpClient();
using var imageResponse = await client.GetAsync(urlPrefix + "watermark-background.png");
using var imageStream = await imageResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);

var loremIpsum = string.Empty;
using (var textResponse = await client.GetAsync(urlPrefix + "lorem-ipsum.txt"))
     loremIpsum = await textResponse.Content.ReadAsStringAsync().ConfigureAwait(false);

PdfDocumentBuilder.Create().Generate("compounds-watermarks.pdf", doc =>
{
    var image = doc.Image(imageStream);

    doc.Pages(page =>
    {
        page.Size(400, 250);

        page.Background()
            .AlignMiddle()
            .Image(image);

        page.Content()
            .Padding(25)
            .Text(loremIpsum);

        var largeRedText = TextStyle.Parent.FontSize(48)
            .FontColor(new PdfRgbColor(235, 64, 52), 50);
        page.Foreground()
            .Rotate(-30)
            .Translate(-50, 180)
            .Text("DO NOT COPY")
            .Style(largeRedText);
    });
});

Puoi vedere il risultato del codice in compounds-watermarks.pdf.

Codice d'esempio

Abbiamo alcune app di esempio che coprono le funzionalità sopra menzionate in modo più dettagliato. Per favore, dedica un po' di tempo a controllarli.