I need to add the total page count to a PDF/A-2 document created using iText in Java. The following code is being used:
public class HeaderFooterPageEvent extends PdfPageEventHelper {
Font fontHEADER = null;
/** The template with the total number of pages. */
PdfTemplate total;
public HeaderFooterPageEvent() {
try {
fontHEADER = new Font(BaseFont.createFont("OpenSans-Regular.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED), 8, Font.BOLD);
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onOpenDocument(PdfWriter writer, Document document) {
total = writer.getDirectContent().createTemplate(30, 16);
super.onOpenDocument(writer, document);
}
#Override
public void onCloseDocument(PdfWriter writer, Document document) {
PdfContentByte cb = writer.getDirectContent();
ColumnText.showTextAligned(total, Element.ALIGN_RIGHT,
new Phrase(String.valueOf(writer.getPageNumber() - 1)),fontHEADER),
document.right() - document.rightMargin()+5,
document.bottom() - 10, 0);
super.onCloseDocument(writer, document);
}
}
And when creating the PDF the following code is called:
Document document = new Document(PageSize.A4, 15, 15, 30, 20);
PdfAWriter writer = PdfAWriter.getInstance(document, new FileOutputStream(dest), PdfAConformanceLevel.PDF_A_2A);
writer.createXmpMetadata();
writer.setTagged();
// add header and footer
HeaderFooterPageEvent event = new HeaderFooterPageEvent();
writer.setPageEvent(event);
document.open();
document.addLanguage("en-us");
File file = new File("sRGB_CS_profile.icm");
ICC_Profile icc = ICC_Profile
.getInstance(new FileInputStream(file));
writer.setOutputIntents("Custom", "", "http://www.color.org", "sRGB IEC61966-2.1", icc);
Paragraph p=new Paragraph("Page 1 content",fontEmbedded); //setting an embedded font
p.setSpacingBefore(30f);
document.add(p);
document.newPage();
document.add(new Paragraph("Content of next page goes here",fontEmbedded));
document.close();
Now when we add content on 2 pages and use document.newPage() to add the new page, runtime exception is generated The page 3 was requested but the document has only 2 pages. What is a solution to this problem?
Related
I'm using ItextPdf 5.
I have an SVG file with specifical font (integrated in svg).
When I print my SVG (using batik 1.8) the graphic is print on my document, but fonts are blocked, so, can't select them.
see below my java code :
public class ItextPdfSmallTests {
#Test
public void svgFontsTest() throws IOException, DocumentException, URISyntaxException {
String RESULT = "C:\\test\\svgFontsTest.pdf";
Document document = new Document(PageSize.A4, 36, 36, 54, 36);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
document.open();
document.add(new Paragraph("SVG Example"));
int width = 250;
int height = 250;
PdfContentByte cb = writer.getDirectContent();
PdfTemplate template = cb.createTemplate(width, height);
PdfPrinterGraphics2D g2 = new PdfPrinterGraphics2D(cb, width, height, new MyFontMapper(), PrinterJob.getPrinterJob());
PrintTranscoder prm = new PrintTranscoder();
URI svgFileURI = getClass().getResource("myfont.svg").toURI();
TranscoderInput ti = new TranscoderInput(svgFileURI.toString());
prm.transcode(ti, null);
PageFormat pg = new PageFormat();
Paper pp = new Paper();
pp.setSize(width, height);
pp.setImageableArea(0, 0, width, height);
pg.setPaper(pp);
prm.print(g2, pg, 0);
g2.dispose();
ImgTemplate img = new ImgTemplate(template);
document.add(img);
document.close();
}
class MyFontMapper extends DefaultFontMapper {
#Override
public BaseFont awtToPdf(java.awt.Font font) {
try {
return BaseFont.createFont("AmaticSC-Regular.ttf", BaseFont.WINANSI, false);
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
}
is it possible make it editable ?
thanks for your helps
My problem is when I try to add the content in the pdf, my table appears from the beginning and not below the header, my table with content has an incorrect height
The code is something long and I can not upload images, but I have a header and footer with pagination
It looks like it's just adding a space to my table with content but I do not know how to do it, I think my problem is in the summary method
private void addHeader(PdfWriter writer) {
PdfPTable tableHeader = new PdfPTable(2);
try {
// set default
tableHeader.setWidths(new int[] { 2, 24 });
tableHeader.setTotalWidth(527);
tableHeader.setLockedWidth(true);
tableHeader.getDefaultCell().setFixedHeight(40);
tableHeader.getDefaultCell().setBorder(Rectangle.BOTTOM);
tableHeader.getDefaultCell().setBorderColor(BaseColor.LIGHT_GRAY);
// addImage
Image img = Image.getInstance(getClass().getClassLoader().getResource("imgPDF/logo.png"));
tableHeader.addCell(img);
// addText
PdfPCell text = new PdfPCell();
text.setPaddingBottom(15);
text.setPaddingLeft(10);
text.setBorder(Rectangle.BOTTOM);
text.setBorderColor(BaseColor.LIGHT_GRAY);
text.addElement(new Phrase(cve.getId(), new Font(Font.FontFamily.HELVETICA, 13)));
text.addElement(new Phrase("https://myapp.com", new Font(Font.FontFamily.HELVETICA, 10)));
tableHeader.addCell(text);
// write content
tableHeader.writeSelectedRows(0, -1, 34, 803, writer.getDirectContent());
} catch (DocumentException e) {
throw new ExceptionConverter(e);
} catch (MalformedURLException e) {
throw new ExceptionConverter(e);
} catch (IOException e) {
throw new ExceptionConverter(e);
}
private void summary() throws IOException, DocumentException {
PdfPTable table = new PdfPTable(2);
table.setHeaderRows(0);
table.setWidthPercentage(100);
table.setSpacingBefore(15);
table.setTotalWidth(100);
// Add headers
table.addCell(createHeaderCellWithColor("Summary"));
table.addCell(createHeaderCellWithColor("ACCESS"));
table.addCell(createCell("row 1"));
table.addCell(createCell("row 2"));
table.addCell(createCell("row 3"));
PdfPTable table3 = new PdfPTable(3);
PdfPCell cell = new PdfPCell(new Phrase("aaa"));
cell.setColspan(3);
table3.addCell(cell);
table.addCell(createHeaderCellWithColor("IMPACT"));
document.add(table);
With this I largely resolve,
document = new Document (PageSize.A4, 36, 36, 90, 36);
Although I would like to download more content, and that is not so close to the header
Previously had this method with a parameter equal to 15, making the content below the header, this more separate ,,, simply equals the fill
solved with
text.setPaddingBottom(8);
here is the endofpage event code
public override void OnEndPage(PdfWriter writer, Document document)
{
iTextSharp.text.pdf.draw.LineSeparator line1 = new iTextSharp.text.pdf.draw.LineSeparator(1f, 100f, BaseColor.CYAN, Element.ALIGN_LEFT, 1);
document.Add(new Chunk(line1));
}
We use the nice library iText for one of my customer's project to generate a pdf from a string representing a html page. The iText version is 5.5.10.
The following piece of code works well on the development environments and servers running on Windows, but it is not working on the customer's server running on iSeries.
public class GeneratePDFCmdImpl extends ControllerCommandImpl implements
GeneratePDFCmd {
private String charsetStr = null;
private Charset charset = null;
private BaseFont bf = null;
private String destFile = null;
private String destFilename = null;
private String srcContent = null;
private String docName = null;
public void setDocName(String docname) {
this.docName = docname;
}
public void setSrcContent(String srcContent) {
this.srcContent = srcContent;
}
private void prepareDefaultsAndSettings() {
/* srcContent may be more complex html but even this simple one is not working */
srcContent = "<html><head></head><body>This is just a test</body></html>";
docName = "mypdf";
charsetStr = "UTF-8";
destFilename = docName+".pdf";
Date timestamp = new Date();
/* destFile = "/" is just for the sample. In my real project, the value is a folder where my app has full rights
*/
destFile = "/" + destFilename;
charset = Charset.forName(charsetStr);
FontFactory.register("/fonts/arial.ttf","Arial");
bf = FontFactory.getFont("Arial").getBaseFont();
}
#Override
public void performExecute() throws ECException {
super.performExecute();
Document document = null;
OutputStream os = null;
prepareDefaultsAndSettings();
try {
InputStream srcInputStream;
srcInputStream = new ByteArrayInputStream(srcContent.getBytes(charset));
document = new Document(PageSize.A4, 20, 20, 75, 80);
FileOutputStream destOutput = new FileOutputStream(destFile);
PdfWriter writer = PdfWriter.getInstance(document,destOutput);
writer.setPageEvent( new HeaderFooterPageEvent(bf));
document.open();
XMLWorkerHelper.getInstance().parseXHtml(writer, document, srcInputStream, charset);
document.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} finally {
if(document != null) {
document.close();
}
document = null;
try {
if (os != null) {
os.close();
}
} catch(IOException e) {
e.printStackTrace();
}
os = null;
}
}
private class HeaderFooterPageEvent extends PdfPageEventHelper {
PdfContentByte cb;
PdfTemplate template;
BaseFont bf;
Font f;
float fs;
public HeaderFooterPageEvent(BaseFont _bf) {
super();
bf = _bf;
f = new Font(bf);
}
#Override
public void onOpenDocument(PdfWriter writer, Document document) {
cb = writer.getDirectContent();
template = cb.createTemplate(50, 50);
}
#Override
public void onEndPage(PdfWriter writer, Document document) {
Date dat = new Date();
ColumnText ct = new ColumnText(writer.getDirectContent());
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm");
ct.showTextAligned(writer.getDirectContent(), Element.ALIGN_CENTER, new Phrase(sdf.format(dat) ), 100, 30, 0);
String text = "Page " +writer.getPageNumber() + " to ";
float len = bf.getWidthPoint(text, 12);
cb.beginText();
cb.setFontAndSize(bf, 12);
cb.setTextMatrix(450, 30);
cb.showText(text);
cb.endText();
cb.addTemplate(template, 450 + len, 30);
}
#Override
public void onCloseDocument(PdfWriter writer, Document document) {
template.beginText();
template.setFontAndSize(bf, 12);
template.showText(String.valueOf(writer.getPageNumber()));
template.endText();
}
}
}
When executed on the iSeries, we have the error message
com.ibm.commerce.command.ECCommandTarget executeCommand CMN0420E: The following command exception has occurred during processing: "ExceptionConverter: java.io.IOException: The document has no pages.". ExceptionConverter: java.io.IOException: The document has no pages.
at com.itextpdf.text.pdf.PdfPages.writePageTree(PdfPages.java:112)
at com.itextpdf.text.pdf.PdfWriter.close(PdfWriter.java:1256)
at com.itextpdf.text.pdf.PdfDocument.close(PdfDocument.java:900)
at com.itextpdf.text.Document.close(Document.java:415)
at be.ourcustomer.package.GeneratePDFCmdImpl.performExecute(GeneratePDFCmdImpl.java:107)
I don't have much idea about what we do wrong. Any help would be greatly appreciated
I would like to know how to create class that generates a pdf using Itext and send it over to a web browser using JAX-RS using the #GET and #Produces annotation.
Below is my solution, simplified to fit here. I'm using JDK 8 lambdas in the generate method, if you can't, just return an anonymous inner class implementing StreamOutput.
#Path("pdf")
#Produces(ContractResource.APPLICATION_PDF)
public class PdfResource {
public static final String APPLICATION_PDF = "application/pdf";
#GET
#Path("generate")
public StreamingOutput generate() {
return output -> {
try {
generate(output);
} catch (DocumentException e) {
throw new IOException("error generating PDF", e);
}
};
}
private void generate(OutputStream outputStream) throws IOException, DocumentException {
Document document = new Document();
PdfWriter.getInstance(document, outputStream);
document.open();
document.add(new Paragraph("Test"));
document.close();
}
}
Mock solution that serves PDF file on browser without storing a file on the server side with JAX-RS and IText 5 Legacy.
#Path("download/pdf")
public class MockPdfService{
#GET
#Path("/mockFile")
public Response downloadMockFile() {
try {
// mock document creation
com.itextpdf.text.Document document = new Document();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
com.itextpdf.text.pdf.PdfWriter.getInstance(document, byteArrayOutputStream);
document.open();
document.add(new Chunk("Sample text"));
document.close();
// mock response
return Response.ok(byteArrayOutputStream.toByteArray(), MediaType.APPLICATION_OCTET_STREAM)
.header("content-disposition", "attachment; filename = mockFile.pdf")
.build();
} catch (DocumentException ignored) {
return Response.serverError().build();
}
}
}