itext
Seitenereignisse (iText 5) versus Ereignishandler und Renderer (iText 7)
Suche…
Bemerkungen
In iText 5 haben wir das Konzept der Seitenereignisse eingeführt, damit Entwickler beim Öffnen eines Dokuments, beim Öffnen einer neuen Seite, beim Beenden einer Seite und beim Schließen eines Dokuments ein bestimmtes Verhalten hinzufügen können.
In der Dokumentation haben wir deutlich gemacht, dass das Hinzufügen von Inhalten in der onStartPage()
-Methode verboten ist . Inhalt kann nur in der onEndPage()
-Methode hinzugefügt werden. Wir haben auch deutlich gemacht, dass das Document
Objekt, das an die Seitenereignismethoden übergeben wurde, nur zu schreibgeschützten Zwecken übergeben wurde. Es war verboten , document.add()
auch in der onEndPage()
-Methode zu verwenden.
Leider ignorieren viele Entwickler die Dokumentation vollständig. Dies führte zu Problemen wie:
- "'System.StackOverflowException" im "OnEndPage" -Ereignishandler
- Eine Stack Overflow-Ausnahme erhalten, die eine PDF generiert
- iTextSharp-Zeilentrennzeichen wird mit PdfPageEventHelper nicht mehr angezeigt
- Das iTextSharp-Fehlerdokument hat vor dem Öffnen keine Seite
- ...
Ich kann mich nicht erinnern, wie oft ich aufgeregt wurde, weil ein anderer Entwickler ein Duplikat dieser Fragen veröffentlicht hat. Die Leute fragen sich oft, warum sie eine scharfe Antwort bekommen, aber sie wissen nicht, dass ein Minimum an Anstrengung von ihrer Seite allen, einschließlich sich selbst, viel Zeit gespart hätte. Alle diese Fragen könnten beantwortet werden, indem Sie sagten: "Lesen Sie das (Sie wissen, was) Handbuch."
Eine weitere Option war eine vollständige Überarbeitung von iText, um diese Art von Problemen zu vermeiden.
Aufgrund des organischen Wachstums von iText wurde die Seitenereignisklasse auch um Funktionen erweitert, die sich nicht auf Seitenereignisse beziehen. Es enthielt generische Chunk- Funktionen, registrierte den Anfang und das Ende von Absätzen und so weiter.
Was wir in iText 7 behoben haben:
Wir haben die Seitenereignisfunktion entfernt.
Für alle Ereignisse in Bezug auf Seiten implementieren wir nun die IEventHandler
Schnittstelle und verwenden den addEventHandler
, um diesen Handler als PdfDocumentEvent
zum PdfDocument
. Im Beispiel verwenden wir ein END_PAGE
Ereignis, wir hätten aber auch ein START_PAGE
Ereignis verwenden können. Es spielt keine Rolle mehr, ob Sie am Anfang oder am Ende Inhalte hinzufügen. Weitere Informationen hierzu finden Sie unter Ereignisse behandeln. Festlegen von Viewer-Einstellungen und Schreiber-Eigenschaften. Dies ist Kapitel 7 des Tutorials zu iText 7: Building Blocks .
Wir haben die Bausteine dahingehend verbessert, dass wir sie hierarchischer gemacht haben (siehe Bevor wir beginnen: Überblick über die Klassen und Schnittstellen, das ist die Einführung des Tutorials iText 7: Bausteine ). Wir haben auch eine Reihe von Renderer-Klassen eingeführt, eine für jeden Baustein. Außerdem können Entwickler diese Renderer so anpassen, dass ein Baustein beim Rendern ein anderes Verhalten zeigt. Siehe zum Beispiel das Renderer-Beispiel in Hinzufügen von AbstractElement-Objekten (Teil 1), das sich in Kapitel 7 des Tutorials zu iText 7: Building Blocks befindet .
Diese Änderungen vereinfachen die Funktionalität für Entwickler, die sich mit PDF und iText nicht auskennen (wollen), und bieten gleichzeitig eine enorme Flexibilität für Entwickler, die keine Angst haben, tief in den iText - Code einzugreifen, um eine PDF genau so, wie sie es wollen.
Möchten Sie mehr wissen? Holen Sie sich das kostenlose E-Book!
Text2PdfPageEvents.java (iText 5)
Angenommen, wir haben die folgende Textdatei: jekyll_hyde.txt
Wie konvertieren wir es in ein PDF, das so aussieht:
Beachten Sie den blauen Rand, der den Titeln hinzugefügt wird, und die Seitennummer unten auf jeder Seite. In iText 5 werden diese Elemente mithilfe von Seitenereignissen hinzugefügt:
class MyPageEvents extends PdfPageEventHelper {
protected float startpos = -1;
protected boolean title = true;
public void setTitle(boolean title) {
this.title = title;
}
@Override
public void onEndPage(PdfWriter writer, Document document) {
Rectangle pagesize = document.getPageSize();
ColumnText.showTextAligned(
writer.getDirectContent(),
Element.ALIGN_CENTER,
new Phrase(String.valueOf(writer.getPageNumber())),
(pagesize.getLeft() + pagesize.getRight()) / 2,
pagesize.getBottom() + 15,
0);
if (startpos != -1)
onParagraphEnd(writer, document,
pagesize.getBottom(document.bottomMargin()));
startpos = pagesize.getTop(document.topMargin());
}
@Override
public void onParagraph(PdfWriter writer, Document document,
float paragraphPosition) {
startpos = paragraphPosition;
}
@Override
public void onParagraphEnd(PdfWriter writer, Document document,
float paragraphPosition) {
if (!title) return;
PdfContentByte canvas = writer.getDirectContentUnder();
Rectangle pagesize = document.getPageSize();
canvas.saveState();
canvas.setColorStroke(BaseColor.BLUE);
canvas.rectangle(
pagesize.getLeft(document.leftMargin()),
paragraphPosition - 3,
pagesize.getWidth() - document.leftMargin() - document.rightMargin(),
startpos - paragraphPosition);
canvas.stroke();
canvas.restoreState();
}
}
Wir können den Code zum Konvertieren einer Textdatei aus dem Beispiel Text2Pdf.java (iText 5) in eine PDF-Datei wiederverwenden und das Seitenereignis in den PdfWriter
:
public void createPdf(String dest)
throws DocumentException, IOException {
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
MyPageEvents events = new MyPageEvents();
writer.setPageEvent(events);
document.open();
BufferedReader br = new BufferedReader(new FileReader(TEXT));
String line;
Paragraph p;
Font normal = new Font(FontFamily.TIMES_ROMAN, 12);
Font bold = new Font(FontFamily.TIMES_ROMAN, 12, Font.BOLD);
boolean title = true;
while ((line = br.readLine()) != null) {
p = new Paragraph(line, title ? bold : normal);
p.setAlignment(Element.ALIGN_JUSTIFIED);
events.setTitle(title);
document.add(p);
title = line.isEmpty();
}
document.close();
}
Quelle: developer.itextpdf.com
Text2PdfPageEvents1.java (iText 7)
Angenommen, Sie haben die folgende Textdatei: jekyll_hyde.txt
Wie konvertieren wir es in ein PDF, das so aussieht:
Notieren Sie sich die Seitennummern unten auf jeder Seite. Diese werden mithilfe einer IEventHandler
Implementierung hinzugefügt:
protected class Footer implements IEventHandler {
@Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdf = docEvent.getDocument();
PdfPage page = docEvent.getPage();
Rectangle pageSize = page.getPageSize();
PdfCanvas pdfCanvas = new PdfCanvas(
page.getLastContentStream(), page.getResources(), pdf);
Canvas canvas = new Canvas(pdfCanvas, pdf, pageSize);
float x = (pageSize.getLeft() + pageSize.getRight()) / 2;
float y = pageSize.getBottom() + 15;
canvas.showTextAligned(
String.valueOf(pdf.getPageNumber(page)),
x, y, TextAlignment.CENTER);
}
}
Das Beispiel für Text2Pdf.java (iText 7) kann mit nur zwei geringfügigen Änderungen wiederverwendet werden:
public void createPdf(String dest) throws IOException {
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
pdf.addEventHandler(PdfDocumentEvent.END_PAGE, new Footer());
Document document = new Document(pdf)
.setTextAlignment(TextAlignment.JUSTIFIED);
BufferedReader br = new BufferedReader(new FileReader(TEXT));
String line;
PdfFont normal = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN);
PdfFont bold = PdfFontFactory.createFont(FontConstants.TIMES_BOLD);
boolean title = true;
Border border = new SolidBorder(Color.BLUE, 1);
while ((line = br.readLine()) != null) {
document.add(new Paragraph(line)
.setFont(title ? bold : normal)
.setBorder(title ? border : Border.NO_BORDER));
title = line.isEmpty();
}
document.close();
}
Wir fügen einen Ereignishandler hinzu, der die handleEvent()
Methode der Footer
Klasse jedes Mal auslöst, handleEvent()
eine Seite endet. Wir definieren auch einen Rahmen für die Paragraph
, die für einen Titel verwendet werden.
Quelle: developer.itextpdf.com und das Tutorial zu iText 7: Bausteine .
Text2PdfPageEvents2.java
Angenommen, Sie haben die folgende Textdatei: jekyll_hyde.txt
Wie konvertieren wir es in ein PDF, das so aussieht:
Beachten Sie, dass dies dem vorher sehr ähnlich ist, aber der Rand der Titel hat jetzt abgerundete Ecken. Wir haben einen benutzerdefinierten ParagraphRenderer
, um dies zu erreichen, und ein TitleParagraph
Objekt erstellt, das diesen Renderer verwendet:
public class TitleParagraph extends Paragraph {
public TitleParagraph(String line) {
super(line);
try {
setFont(PdfFontFactory.createFont(FontConstants.TIMES_BOLD));
}
catch (IOException ioe) {
}
}
@Override
protected IRenderer makeNewRenderer() {
return new ParagraphRenderer(this) {
@Override
public void drawBorder(DrawContext drawContext) {
Rectangle occupiedAreaBBox = getOccupiedAreaBBox();
float[] margins = getMargins();
Rectangle rectangle = applyMargins(occupiedAreaBBox, margins, false);
PdfCanvas canvas = drawContext.getCanvas();
canvas.roundRectangle(rectangle.getX() - 1, rectangle.getY() - 1,
rectangle.getWidth() + 2, rectangle.getHeight() + 2, 5).stroke();
}
};
}
}
Unser Code zum Konvertieren von Text in PDF ist jetzt sehr einfach. Wir müssen die Schriftart für die Titel nicht mehr fett setzen, und wir müssen keinen Rahmen mehr definieren:
public void createPdf(String dest) throws IOException {
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
pdf.addEventHandler(PdfDocumentEvent.END_PAGE, new Footer());
Document document = new Document(pdf)
.setTextAlignment(TextAlignment.JUSTIFIED);
BufferedReader br = new BufferedReader(new FileReader(TEXT));
String line;
PdfFont normal = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN);
boolean title = true;
Border border = new SolidBorder(Color.BLUE, 1);
while ((line = br.readLine()) != null) {
if (title)
document.add(new TitleParagraph(line));
else
document.add(new Paragraph(line).setFont(normal));
title = line.isEmpty();
}
document.close();
}
Quelle: developer.itextpdf.com und das Tutorial zu iText 7: Bausteine .