PDF / A中标题中的iText页码 [英] iText page number in header within PDF/A

查看:125
本文介绍了PDF / A中标题中的iText页码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试调整代码以将PDF中的页码添加到PDF / A.

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

如果我省去添加 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);"

虽然我真的很喜欢页面标题我也没有线索如何将字体添加到 PdfPCell 。对于其他字段,我通常会添加一个短语或段落,我可以提供我的字体。

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.

抛出的错误是:线程main中的异常com.itextpdf.text.DocumentException:com.itextpdf.text.pdf .PdfAConformanceException:所有字体都必须嵌入。这个不是: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);
}

}

推荐答案

请看一下这一行:

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

在此行中,添加字符串直接到。在内部,创建 PdfPCell ,以及 Phrase 对象。由于没有定义字体,因此使用默认字体(Helvetica,未嵌入)。

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.

请将以上行更改为:

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

这将解决一个问题(除非我忽略了引入默认字体的其他情况)。如果你想要的话还会有其他例外但是,PDF / A A级。

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.

我写了一个基于CSV文件创建PDF / A文档的例子。我在这里添加了一个页脚文档重用您的页面事件实现: PdfA1A

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

您遇到的问题可以解释如下:当您告诉 PdfWriter 它需要创建标记PDF时(使用 writer.setTagged( ); ),iText将确保在添加元素时创建相应的标签对象到文档。只要您坚持使用高级对象,这将有效。

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();

我对 PdfPTable 使用第二种方法,因为如果我不这样做,我将必须将表的所有子元素(每一行)标记为工件。如果我没有,iText会在工件中引入 TR 元素(这是错误的)。

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).

有关完整的源代码,请参见 http://itextpdf.com/sandbox/pdfa/PdfA1A

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

这篇关于PDF / A中标题中的iText页码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆