iText page number in header within PDF/A

2019-01-28 12:25发布

I have trying to adjust the code to add page number in PDF to PDF/A.

I have added the font, color scheme and the PDF/A creation works if I leave out adding the addition of the PdfTemplate.

// PDF is created successfully when this part is removed
// Though without the page number in the header
PdfPCell cell = new PdfPCell(Image.getInstance(total));
cell.setBorder(Rectangle.BOTTOM);
table.addCell(cell);"

Though I would really like the header with page number to be in it too. I am out of clues how to add the font to the PdfPCell. With other fields I usually add a phrase or a paragraph to which I can provide my font.

The error thrown is: Exception in thread "main" com.itextpdf.text.DocumentException: com.itextpdf.text.pdf.PdfAConformanceException: All the fonts must be embedded. This one isn't: Helvetica at com.itextpdf.text.pdf.PdfDocument.add(PdfDocument.java:809)

public class MovieCountries1 {

/**
 * The resulting PDF file.
 */
public static final String RESULT
    = "d:/tmp/pdf/movie_countries1.pdf";

private static final String FONT_LOCATION = "./fonts/arial.ttf";

public static Font fontArial = FontFactory.getFont(FONT_LOCATION, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

/**
 * Inner class to add a table as header.
 */
class TableHeader extends PdfPageEventHelper {
/**
 * The header text.
 */
String header;
/**
 * The template with the total number of pages.
 */
PdfTemplate total;

/**
 * Allows us to change the content of the header.
 *
 * @param header The new header String
 */
public void setHeader(String header) {
    this.header = header;
}

/**
 * Creates the PdfTemplate that will hold the total number of pages.
 *
 * @see com.itextpdf.text.pdf.PdfPageEventHelper#onOpenDocument(
 *com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)
 */
public void onOpenDocument(PdfWriter writer, Document document) {
    total = writer.getDirectContent().createTemplate(30, 16);
}

/**
 * Adds a header to every page
 *
 * @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(
 *com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)
 */
public void onEndPage(PdfWriter writer, Document document) {
    PdfPTable table = new PdfPTable(3);
    try {
    table.setWidths(new int[]{24, 24, 2});
    table.setTotalWidth(527);
    table.setLockedWidth(true);
    table.getDefaultCell().setFixedHeight(20);
    table.getDefaultCell().setBorder(Rectangle.BOTTOM);
    table.addCell(header);
    table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
    table.addCell(String.format("Page %d of", writer.getPageNumber()));

    //PDF is created successfully when this part is removed
    //Though without the page number in the header
    PdfPCell cell = new PdfPCell(Image.getInstance(total));
    cell.setBorder(Rectangle.BOTTOM);
    table.addCell(cell);

    table.writeSelectedRows(0, -1, 34, 803, writer.getDirectContent());
    } catch (DocumentException de) {
    throw new ExceptionConverter(de);
    }
}

/**
 * Fills out the total number of pages before the document is closed.
 *
 * @see com.itextpdf.text.pdf.PdfPageEventHelper#onCloseDocument(
 *com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)
 */
public void onCloseDocument(PdfWriter writer, Document document) {
    ColumnText.showTextAligned(total, Element.ALIGN_LEFT,
        new Phrase(String.valueOf(writer.getPageNumber() - 1), fontArial),
        2, 2, 0);
}
}

/**
 * Creates a PDF document.
 *
 * @param filename the path to the new PDF document
 * @throws DocumentException
 * @throws IOException
 * @throws SQLException
 */
public void createPdf(String filename)
    throws IOException, DocumentException, SQLException {
// Create a database connection

// step 1
Document document = new Document(PageSize.A4, 36, 36, 54, 36);
// step 2
PdfAWriter writer = PdfAWriter.getInstance(document, new FileOutputStream(RESULT), PdfAConformanceLevel.PDF_A_1A);
//PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(RESULT));

document.addAuthor("Author");
document.addSubject("Subject");
document.addLanguage("nl-nl");
document.addCreationDate();
document.addCreator("Creator");
document.addTitle("Title");

writer.setPdfVersion(PdfName.VERSION);
writer.setTagged();
writer.createXmpMetadata();

TableHeader event = new TableHeader();
writer.setPageEvent(event);
// step 3
document.open();
// step 4
List<Movie> movies = composeMovies();
for (int i = 0; i < 10; i++) {
    for (Movie movie : movies) {
    document.add(new Paragraph(movie.getMovieTitle(), fontArial));
    if (movie.getOriginalTitle() != null)
        document.add(new Paragraph(movie.getOriginalTitle(), fontArial));
    final String format = String.format("Year: %s; run length: %s minutes",
        movie.getYear(), movie.getDuration());
    document.add(new Paragraph(format, fontArial));
    }
}

// step 4
final String colorProfile = "/color/sRGB_Color_Space_Profile.icm";
final InputStream resourceAsStream = this.getClass().getResourceAsStream(colorProfile);
ICC_Profile icc = ICC_Profile.getInstance(resourceAsStream);
writer.setOutputIntents("Custom", "", "http://www.color.org", "sRGB IEC61966-2.1", icc);
document.close();
}

private List<Movie> composeMovies() {
List<Movie> movies = new ArrayList<>();
final Movie movie1 = new Movie();
movie1.setYear("2012");
movie1.setMovieTitle("movieTitle1");
movie1.setOriginalTitle("originalTitle1");
movie1.setDuration("1h");
final Movie movie2 = new Movie();
movie2.setYear("2013");
movie2.setMovieTitle("movieTitle2");
movie2.setOriginalTitle("originalTitle2");
movie2.setDuration("2h");
movies.add(movie1);
movies.add(movie2);
return movies;
}

/**
 * Main method.
 *
 * @param args no arguments needed
 * @throws DocumentException
 * @throws IOException
 * @throws SQLException
 */
public static void main(String[] args)
    throws IOException, DocumentException, SQLException {
new MovieCountries1().createPdf(RESULT);
}

}

标签: image itext pdfa
1条回答
淡お忘
2楼-- · 2019-01-28 12:35

Please take a look at this line:

table.addCell(String.format("Page %d of", writer.getPageNumber()));

In this line, you add a String to the table directly. Internally, a PdfPCell is created, as well as a Phrase object. As no font is defined, the default font (Helvetica, unembedded) is used.

Please change the above line into:

table.addCell(new Phrase(String.format("Page %d of", writer.getPageNumber()), fontArial);

This will solve already one problem (unless I've overlooked other instances where the default font is introduced). There will be other exceptions if you want PDF/A Level A, though.

I've written an example that creates a PDF/A document based on a CSV file. I'm adding a footer to this document reusing your page event implementation: PdfA1A

The problem you are experiencing can be explained as follows: when you tell the PdfWriter that it needs to create Tagged PDF (using writer.setTagged();), iText will make sure that the appropriate tags are created when adding Element objects to the document. As long as you stick to using high-level objects, this will work.

However, the moment you introduce objects that are added at absolute positions, you take responsibility to correctly tag any content you add. In your case, you are adding a footer. Footers are not part of the "real content", hence they need to be marked as "artifacts".

In my example, I have adapted your page event implementation in a way that allows me to explain two different approaches:

In the first approach, I set the role at the level of the object:

Image total = Image.getInstance(t);
total.setRole(PdfName.ARTIFACT);

In the second approach, I mark content as an artifact at the lowest level:

PdfContentByte canvas = writer.getDirectContent();
canvas.beginMarkedContentSequence(PdfName.ARTIFACT);
table.writeSelectedRows(0, -1, 36, 30, canvas);
canvas.endMarkedContentSequence();

I use this second approach for PdfPTable because if I don't, I would have to tag all sub-elements of the table (every single row) as an artifact. If I didn't, iText would introduce TR elements inside an artifact (and that would be wrong).

See http://itextpdf.com/sandbox/pdfa/PdfA1A for the full source code.

查看更多
登录 后发表回答