Diese Seite kann automatisch übersetzten Text enthalten.
Zusammengesetzte Container
Komplexe Container spielen eine entscheidende Rolle bei der Strukturierung und Organisation von Inhalten. Mit einem geeigneten Container können Sie Text und Bilder ganz einfach benutzerfreundlich darstellen.
Es ist durchaus möglich, ein Dokument nur mit einfachen Text- und Bildcontainern zu erstellen. Es gibt jedoch Anforderungen, die sich nur schwer oder gar nicht mit einfachen Containern allein umsetzen lassen. Zusammengesetzte Container helfen in solchen Fällen. Außerdem helfen komplexe Container, Ihre Ziele mit weniger Code zu erreichen.

Verwenden Sie Methoden der LayoutContainer-Klasse, um komplexe Container wie Row und Column zu Dokumentseiten hinzuzufügen. Mit diesen Containern können Sie andere Container wie Raster und Listen implementieren. Für weniger häufige, aber dennoch wichtige Fälle gibt es außerdem die Methoden Inlined und Layers.
Dieser Artikel ist Teil einer Reihe über die Layout API zur PDF-Erzeugung. Wenn Sie die API noch nicht kennen, lesen Sie zuerst den Abschnitt Erste Schritte mit Layout API.
Row
Row-Container bieten Platz für Elemente, die horizontal in einer Zeile angeordnet sind. Jedes Element in einer Zeile ist ein Container. Das bedeutet, dass Sie Inhalte unterschiedlicher Typen in eine Zeile setzen können. Den Abstand zwischen den Elementen können Sie mit der Methode Spacing festlegen.
Alle Elemente in einer Zeile haben die gleiche Höhe. Die Bibliothek verwendet die Höhe des höchsten Elements als Höhe der Zeile. Es gibt drei Möglichkeiten, die Breite eines Elements anzugeben. Sie müssen beim Erstellen des Elements eine davon auswählen. Eine Zeile kann Elemente enthalten, die auf unterschiedliche Weise erstellt wurden.
Die Methode Row.AutoItem erstellt ein Element ohne explizit angegebene Breite. Für solche Elemente berechnet die Bibliothek die intrinsische Größe ihres Inhalts. Die berechnete Inhaltsbreite ist die Breite des Elements. Beachten Sie, dass mit AutoItem erstellte Elemente lange Zeilen nicht umbrechen.
Verwenden Sie die Methode ConstantItem, um ein Element mit einer Breite zu erstellen, die einer exakten Anzahl von Punkten entspricht.
RelativeItem ist praktisch, wenn Sie die exakten Breiten der Elemente in der Zeile nicht kennen und keine intrinsischen Größen verwenden möchten. Stattdessen können Sie relative Breiten für Elemente in der Zeile angeben. Die Methode akzeptiert die Anzahl der Teile, die das Element belegen soll. Die Gesamtzahl der Teile ist die Summe aller Zahlen in allen RelativeItem-Aufrufen in dieser Zeile.
Wenn es beispielsweise genau einen RelativeItem-Aufruf gibt, ist die Zahl nicht wichtig. Das Element belegt die gesamte verfügbare Breite. Bei zwei oder mehr Elementen legen die Zahlen das Verhältnis fest.
row.RelativeItem(2)
row.RelativeItem(3)
row.RelativeItem(1)
Alle mit dem obigen Code erstellten Elemente belegen 6 Teile (2 + 3 + 1 = 6). Die einzelnen Elemente belegen entsprechend 2 von 6, 3 von 6 und 1 von 6 Teilen.
Die Layout API verwendet die folgende Formel zur Berechnung der Breite eines Teils:
PartWidth = (RowWidth - AutoWidth - ConstantWidth) / TotalParts
wobei:
RowWidth = Breite des Zeilencontainers
AutoWidth = Breite aller mit der Methode AutoItem erstellten Elemente
ConstantWidth = Breite aller mit der Methode ConstantItem erstellten Elemente
Hier ist ein Beispiel, das eine Zeile mit Elementen aller drei Arten erstellt.
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]);
});
}
});
}));
Das Ergebnis des Codes sehen Sie in compounds-row.pdf.
Column
Um Elemente vertikal nacheinander anzuordnen, verwenden Sie einen Column-Container. Jedes Element in einer Spalte ist ein Container. Dadurch können Sie Inhalte unterschiedlicher Typen in eine Spalte setzen.
Die Breite jedes Elements entspricht der Spaltenbreite. Die Höhe jedes Elements hängt vom Inhalt und den Eigenschaften des Elements ab. Column-Container unterstützen das Paginieren, sodass das Layout-Add-on Elemente einer Spalte auf mehr als einer Seite rendern kann.
Standardmäßig hat ein Column-Container keinen Kopf- oder Fußzeileninhalt. Verwenden Sie die Methoden Header und Footer, um auf die entsprechenden Container zuzugreifen und sie einzurichten. Wenn Spaltenelemente mehr als eine Seite beanspruchen, wiederholt die Bibliothek Kopf- und Fußzeilen auf jeder Seite.
Verwenden Sie die Methode Spacing, um etwas vertikalen Abstand zwischen Spaltenelementen hinzuzufügen. Beachten Sie, dass die Bibliothek keinen Abstand zwischen der Kopfzeile und dem ersten Element einfügt. Ebenso fügt die Bibliothek keinen Abstand vor der Fußzeile hinzu.
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);
});
}));
Das Ergebnis des Codes sehen Sie in compounds-column.pdf.
Raster
Rasterlayouts organisieren Elemente in Spalten und Zeilen. In dieser Hinsicht ähneln Raster Tabellen. Die Layout API stellt keinen speziellen Containertyp für Raster bereit. Sie können ein Rasterlayout mit den Containern Column und Row implementieren.
Es hilft, ein Raster als Spalte zu betrachten, deren einzelne Elemente jeweils eine Zeile sind. Sowohl der Column- als auch der Row-Container bieten die Möglichkeit, den Abstand zwischen Elementen festzulegen. Sie können bei Bedarf eine Kopf- und Fußzeile hinzufügen.
Jede Zeile kann ein unabhängiges Layout haben. Es kann in jeder Zeile eine unterschiedliche Anzahl von Elementen geben. Elemente können unterschiedliche Breite und Höhe haben. Es ist möglich, vor, nach oder zwischen Elementen in einer Zeile zusätzlichen Platz hinzuzufügen. Verwenden Sie dafür Elemente ohne Inhalt und Dekoration.
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);
});
});
}));
Das Ergebnis des Codes sehen Sie in compounds-grid.pdf.
Listen
Listen verbessern die Lesbarkeit, indem sie Informationen in knappe Punkte aufteilen. Listenelemente können Zahlen, Aufzählungspunkte und andere Symbole neben dem Text enthalten. Sie können ein Listenlayout einfach mit den Containern Column und Row implementieren. Die Layout API stellt keinen speziellen Containertyp für Listen bereit.
Sehen Sie sich den Beispielcode an, der eine Liste von Monaten nach Jahreszeiten erstellt. Beachten Sie, dass die Liste eine Kopfzeile hat. Wenn Elemente Text enthalten, der in die nächste Zeile umbrochen werden kann, verwenden Sie für den Textteil des Elements entweder die Methode RelativeItem oder ConstantItem.
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);
});
}
});
}));
Das Ergebnis des Codes sehen Sie in compounds-list.pdf.
Table
Tabellenlayouts organisieren Elemente in Spalten und Zeilen. Der Containertyp Table bietet einen umfangreichen Funktionsumfang und kann Ihnen bei den anspruchsvollsten Fällen helfen. Lesen Sie im Artikel Tabellencontainer über alle Funktionen.
InlineContainer
Sie können einen Container mit einer Sammlung anderer Container füllen. Beginnen Sie mit dem Aufruf der Methode LayoutContainer.Inlined. Rufen Sie dann die Methode Item des bereitgestellten InlineContainer auf, um untergeordnete Container hinzuzufügen.
Das Layout-Add-on platziert Container nacheinander in einer Zeile. Wenn nicht genug Platz vorhanden ist, um ein Element unterzubringen, beginnt die Bibliothek eine neue Zeile. Verwenden Sie die Methoden Spacing/HorizontalSpacing/VerticalSpacing, um etwas Abstand zwischen den Elementen hinzuzufügen.
Sie können die Position von Elementen im Container mit Ausrichtungs-Methoden beeinflussen. Die Methoden AlignTop/AlignMiddle/AlignBottom richten Elemente vertikal aus. Für die horizontale Richtung verwenden Sie die Methoden AlignLeft/AlignCenter/AlignRight/AlignJustify.
Es gibt einen Sonderfall. Die Methode AlignSpaceAround richtet Elemente horizontal aus. Sie fügt außerdem zusätzlichen Abstand vor dem ersten und nach dem letzten Element hinzu.
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);
});
}));
Das Ergebnis des Codes sehen Sie in compounds-inlined.pdf.
LayerContainer
Möglicherweise müssen Sie Inhalte unter und/oder über dem Hauptinhalt der Seite platzieren. Der naheliegende Anwendungsfall ist das Hinzufügen eines Wasserzeichens über PDF-Seiten.
Rufen Sie zuerst mit der Methode LayoutContainer.Layers ein LayerContainer-Objekt auf. Mit diesem Objekt können Sie mit dem Hinzufügen von Ebenen beginnen. Der Aufruf der Methode Layer fügt eine sekundäre Ebene hinzu. Rufen Sie die Methode PrimaryLayer auf, um die Hauptebene des Inhalts hinzuzufügen. Sie müssen genau eine primäre Ebene hinzufügen.
Die Layout API setzt Ebenen in derselben Reihenfolge zusammen, in der Sie sie erstellen. Ebenen, die vor der primären Ebene hinzugefügt werden, landen im Hintergrund. Alle Ebenen, die nach der primären Ebene hinzugefügt werden, liegen über dem Hauptinhalt. Der Container wiederholt die sekundären Ebenen auf allen Seiten, die vom Hauptinhalt belegt werden.
Hier ist ein Beispielcode, der zeigt, wie Wasserzeichen zu PDF-Seiten hinzugefügt werden.
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);
});
}));
Das Ergebnis des Codes sehen Sie in compounds-layers.pdf.
Wasserzeichen
Eine der häufigsten Anforderungen ist das Hinzufügen eines Wasserzeichens zu PDF. Dafür kann es verschiedene Gründe geben. Sie können ein Wasserzeichen zu PDF hinzufügen, um Eigentum zu kennzeichnen oder um auf Vertraulichkeit beziehungsweise Sensibilität der Informationen im PDF hinzuweisen.
Ein Ansatz für Wasserzeichen in PDFs ist die Verwendung von Ebenen. Siehe das Beispiel im vorherigen Abschnitt. Ich zeige Ihnen einen anderen Ansatz.
Ich verwende Seitenhintergrund- und Vordergrundcontainer, um PDFs mit Wasserzeichen zu versehen. Das Layout-Add-on wiederholt diese Container auf den folgenden Seiten. Jede Seite mit primärem Dokumentinhalt enthält auch Hintergrund- und Vordergrundcontainer. Das macht sie für diese Aufgabe geeignet.
Ich beginne damit, ein Bild zum Hintergrundcontainer hinzuzufügen. Auf dieselbe Weise können Sie Ihr Logo zu PDF hinzufügen. Das Bild erscheint hinter dem Seiteninhalt. Es spielt keine Rolle, wie viele Seiten Ihres Dokuments das Hintergrundbild verwenden. Die API fügt nur eine Kopie der Bildbytes in das erzeugte PDF ein.
Der primäre Dokumentinhalt kann beliebig sein. Für diesen Beispielcode verwende ich den bekannten Lorem-Ipsum-Text.
Das Textwasserzeichen kommt in den Vordergrundcontainer. Der Text selbst kann beliebig sein, und Sie können jede Farbe oder Schriftart verwenden. Ich habe gedrehten Text mit halbtransparenten roten Buchstaben in größerer Schriftgröße verwendet.
Der Beispielcode lädt Bild und Text asynchron aus unserem Repository mit Beispielcode herunter. Natürlich können Sie ein lokales Bild verwenden und/oder den Text aus einer Datei lesen.
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);
});
});
Das Ergebnis des Codes sehen Sie in compounds-watermarks.pdf.
Beispielcode
Wir haben einige Beispiel-Apps, die die oben genannten Funktionen ausführlicher abdecken. Bitte nehmen Sie sich etwas Zeit, um sie anzusehen.