我尝试调整代码以将PDF中的页码添加到PDF / A.
如果我不添加PdfTemplate
的添加,我添加了字体,配色方案和PDF / A创作。
// 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
。对于其他字段,我通常会添加一个短语或段落,我可以提供我的字体。
抛出的错误是: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);
}
}
答案 0 :(得分:3)
请看一下这一行:
table.addCell(String.format("Page %d of", writer.getPageNumber()));
在此行中,您可以直接向String
添加table
。在内部,创建了PdfPCell
,以及Phrase
对象。由于没有定义字体,因此使用默认字体(Helvetica,unmbedded)。
请将以上一行改为:
table.addCell(new Phrase(String.format("Page %d of", writer.getPageNumber()), fontArial);
这将解决一个问题(除非我忽略了引入默认字体的其他实例)。如果你想要PDF / A A级,还会有其他例外。
我编写了一个基于CSV文件创建PDF / A文档的示例。我在本文档中添加了一个页脚重用您的页面事件实现:PdfA1A
您遇到的问题可以解释如下:当您告诉PdfWriter
需要创建标记PDF(使用writer.setTagged();
)时,iText将确保在创建时创建相应的标记将Element
个对象添加到document
。只要你坚持使用高级对象,这就行了。
但是,当您引入在绝对位置添加的对象时,您有责任正确标记您添加的任何内容。在您的情况下,您正在添加页脚。页脚不属于&#34;真实内容&#34;,因此需要将其标记为&#34;工件&#34;。
在我的示例中,我以一种允许我解释两种不同方法的方式调整了您的页面事件实现:
在第一种方法中,我将角色设置在对象的级别:
Image total = Image.getInstance(t);
total.setRole(PdfName.ARTIFACT);
在第二种方法中,我将内容标记为最低级别的工件:
PdfContentByte canvas = writer.getDirectContent();
canvas.beginMarkedContentSequence(PdfName.ARTIFACT);
table.writeSelectedRows(0, -1, 36, 30, canvas);
canvas.endMarkedContentSequence();
我对PdfPTable
使用第二种方法,因为如果我不这样做,我必须将表的所有子元素(每一行)标记为工件。如果我没有,iText会在工件中引入TR
个元素(这是错误的)。
有关完整的源代码,请参阅http://itextpdf.com/sandbox/pdfa/PdfA1A。