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));
}
Related
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?
I have a requirement to do below items,
Read the existing PDF file
Search the specific keywords in the PDF
Highlight them in specific color or bold
Save the PDF
and i have to tried below code,
public static void main(String[] args) throws IOException, DocumentException
{
File file = new File(DEST); file.getParentFile().mkdirs();
new BrefingPackageHighlight_Main2().manipulatePdf(SRC, DEST);
}
public void manipulatePdf(String src, String dest) throws IOException, DocumentException
{
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); PdfContentByte canvas = stamper.getOverContent(2); canvas.saveState(); canvas.setColorFill(BaseColor.YELLOW);
canvas.rectangle(200, 786, 5, 5);
canvas.fill();
canvas.restoreState();
stamper.close();
reader.close();
}
the above code only highlights top of the second page. Please provide me samples to search one specific keyword and highlight them alone.
I have been tasked with creating a work order application where the
output is PDF for printing from a browser. The output has to be one PDF
document containing one or more "work orders". Due to variable content length each work order might be more than one printed page. Each work order must have its own "page" numbering. I am using Spring MVC and Itext 5.
So imagine we have three work orders. The first will fit on one printed
page, the second requires two printed pages, and the third requires one printed page. We have a total of four printed pages.
How do make so that:
Work order one would have a page number of "1"
Work order two would have page numbers "1, 2"
Work order three would page number "1"
So basically the PDF document would be a container for multiple inner
documents that are independent from each other.
I have tried to reset the page numbers and use the footer for output but that does not seem to work. I am wondering if there some way to set a custom page counter that I can control.
public class PDFBuilder extends AbstractITextPdfView
{
#Override
protected void buildPdfDocument(Map<String, Object> model, Document doc,
PdfWriter writer, HttpServletRequest request, HttpServletResponse response)
throws Exception
{
#SuppressWarnings("unchecked") // TODO replace this with some generic goodness
List<WorkOrderDto> workOrders = (List<WorkOrderDto>) model.get("workOrders");
Integer pageCounter = 1;
// define table header cell
PdfPCell cell = new PdfPCell();
cell.setBackgroundColor(BaseColor.BLUE);
cell.setPadding(5);
// define font for table header row
Font font = FontFactory.getFont(FontFactory.HELVETICA);
font.setColor(BaseColor.WHITE);
writer.setPageEvent(new Footer(pageCounter));
for (WorkOrderDto dto : workOrders)
{
PdfPTable woHeader = new PdfPTable(4);
woHeader.setWidthPercentage(100.0f);
woHeader.setSpacingBefore(10);
if (dto.getNumber() != null)
{
woHeader.addCell("Number: " + dto.getNumber());
}
else
{
woHeader.addCell("Number: ");
}
if (dto.getOwnerNumber() != null)
{
woHeader.addCell("Owner: " + dto.getOwnerNumber());
}
else
{
woHeader.addCell("Owner: ");
}
if (dto.getTypeNumber() != null)
{
woHeader.addCell("Type: " + dto.getTypeNumber());
}
else
{
woHeader.addCell("Type: ");
}
if (dto.getScheduleDate() != null)
{
woHeader.addCell("Open Date: " + dto.getScheduleDate().toString());
}
else
{
woHeader.addCell("Open Date: ");
}
doc.add(woHeader);
PdfPTable servicesTable = new PdfPTable(4);
for (ServiceDto serviceDto : dto.getCurrentServices())
{
servicesTable.addCell("Number: " + serviceDto.getNumber());
servicesTable.addCell("Name: " + serviceDto.getName());
servicesTable.addCell("Description: " + serviceDto.getDescription());
servicesTable.addCell("Status: " + serviceDto.getStatus());
}
doc.add(servicesTable);
doc.newPage();
pageCounter++;
}
}
}
public class Footer implements PdfPageEvent
{
Font ffont = new Font(Font.FontFamily.UNDEFINED, 10, Font.ITALIC);
Integer pageCounter;
public Footer(Integer pageCounter)
{
this.pageCounter = pageCounter;
}
#Override
public void onOpenDocument(PdfWriter writer, Document document)
{
}
#Override
public void onStartPage(PdfWriter writer, Document document)
{
}
#Override
public void onEndPage(PdfWriter writer, Document document)
{
PdfContentByte cb = writer.getDirectContent();
Phrase footer = new Phrase(pageCounter + "", ffont);
ColumnText.showTextAligned(cb, Element.ALIGN_CENTER,
footer,
(document.right() - document.left()) / 2 + document.leftMargin(),
document.bottom() - 10, 0);
}
#Override
public void onCloseDocument(PdfWriter writer, Document document)
{
}
#Override
public void onParagraph(PdfWriter writer, Document document, float paragraphPosition)
{
}
#Override
public void onParagraphEnd(PdfWriter writer, Document document, float paragraphPosition)
{
}
#Override
public void onChapter(PdfWriter writer, Document document, float paragraphPosition, Paragraph title)
{
}
#Override
public void onChapterEnd(PdfWriter writer, Document document, float paragraphPosition)
{
}
#Override
public void onSection(PdfWriter writer, Document document, float paragraphPosition, int depth, Paragraph title)
{
}
#Override
public void onSectionEnd(PdfWriter writer, Document document, float paragraphPosition)
{
}
#Override
public void onGenericTag(PdfWriter writer, Document document, Rectangle rect, String text)
{
}
}
I came up with my own solution which turned out to be very simple. I created a class called PageCounter with some properties to represent various counters. I pass that to the footer and then manipulate the properties while building out the pages.
public class PageCounter
{
private Integer currentPage = 1;
private Integer totalPages = 1;
public Integer getCurrentPage()
{
return currentPage;
}
public void setCurrentPage(Integer currentPage)
{
this.currentPage = currentPage;
}
public Integer getTotalPages()
{
return totalPages;
}
public void setTotalPages(Integer totalPages)
{
this.totalPages = totalPages;
}
public void increment()
{
this.currentPage++;
}
public void reset()
{
this.currentPage = 1;
}
}
public class PDFBuilder extends AbstractITextPdfView
{
#Override
protected void buildPdfDocument(Map<String, Object> model, Document doc,
PdfWriter writer, HttpServletRequest request, HttpServletResponse response)
throws Exception
{
#SuppressWarnings("unchecked") // TODO replace this with some generic goodness
List<WorkOrderDto> workOrders = (List<WorkOrderDto>) model.get("workOrders");
PageCounter pageCounter = new PageCounter();
// define table header cell
PdfPCell cell = new PdfPCell();
cell.setBackgroundColor(BaseColor.BLUE);
cell.setPadding(5);
// define font for table header row
Font font = FontFactory.getFont(FontFactory.HELVETICA);
font.setColor(BaseColor.WHITE);
writer.setPageEvent(new Footer(pageCounter));
for (WorkOrderDto dto : workOrders)
{
PdfPTable woHeader = new PdfPTable(4);
woHeader.setWidthPercentage(100.0f);
woHeader.setSpacingBefore(10);
if (dto.getNumber() != null)
{
woHeader.addCell("Number: " + dto.getNumber());
}
else
{
woHeader.addCell("Number: ");
}
if (dto.getOwnerNumber() != null)
{
woHeader.addCell("Owner: " + dto.getOwnerNumber());
}
else
{
woHeader.addCell("Owner: ");
}
if (dto.getTypeNumber() != null)
{
woHeader.addCell("Type: " + dto.getTypeNumber());
}
else
{
woHeader.addCell("Type: ");
}
if (dto.getScheduleDate() != null)
{
woHeader.addCell("Open Date: " + dto.getScheduleDate().toString());
}
else
{
woHeader.addCell("Open Date: ");
}
doc.add(woHeader);
PdfPTable servicesTable = new PdfPTable(4);
for (ServiceDto serviceDto : dto.getCurrentServices())
{
servicesTable.addCell("Number: " + serviceDto.getNumber());
servicesTable.addCell("Name: " + serviceDto.getName());
servicesTable.addCell("Description: " + serviceDto.getDescription());
servicesTable.addCell("Status: " + serviceDto.getStatus());
}
doc.add(servicesTable);
doc.newPage();
pageCounter.reset();
}
public class Footer implements PdfPageEvent
{
Font ffont = new Font(Font.FontFamily.UNDEFINED, 10, Font.ITALIC);
PageCounter pageCounter;
public Footer(PageCounter pageCounter)
{
this.pageCounter = pageCounter;
}
#Override
public void onOpenDocument(PdfWriter writer, Document document)
{
}
#Override
public void onStartPage(PdfWriter writer, Document document)
{
}
#Override
public void onEndPage(PdfWriter writer, Document document)
{
PdfContentByte cb = writer.getDirectContent();
Phrase footer = new Phrase(pageCounter.getCurrentPage() + "", ffont);
pageCounter.increment();
ColumnText.showTextAligned(cb, Element.ALIGN_CENTER,
footer,
(document.right() - document.left()) / 2 + document.leftMargin(),
document.bottom() - 10, 0);
}
#Override
public void onCloseDocument(PdfWriter writer, Document document)
{
}
#Override
public void onParagraph(PdfWriter writer, Document document, float paragraphPosition)
{
}
#Override
public void onParagraphEnd(PdfWriter writer, Document document, float paragraphPosition)
{
}
#Override
public void onChapter(PdfWriter writer, Document document, float paragraphPosition, Paragraph title)
{
}
#Override
public void onChapterEnd(PdfWriter writer, Document document, float paragraphPosition)
{
}
#Override
public void onSection(PdfWriter writer, Document document, float paragraphPosition, int depth, Paragraph title)
{
}
#Override
public void onSectionEnd(PdfWriter writer, Document document, float paragraphPosition)
{
}
#Override
public void onGenericTag(PdfWriter writer, Document document, Rectangle rect, String text)
{
}
}
I've been using XMLWorkerHelper to add formatted text, inputted on pages via a rich text editor, to PDFs. I've noticed that sometimes not all text was rendered in the PDF. Apparently XMLWorkerHelper drops text not between HTML tags.
Is this correct behavior?
I've written a JUnit test case that shows the problem:
public class XMLWorkerTest {
#Test
public void test() throws IOException, DocumentException {
Document document = new Document();
String fileName = "itext_test_" + System.currentTimeMillis() + ".pdf";
PdfWriter.getInstance(document, new FileOutputStream(fileName));
document.open();
Paragraph paragraph = new Paragraph();
String s1 = "not between tags<b>between tags</b>not between tags";
addHtml(paragraph, s1);
// NOT OK: 'not between tags' missing twice
paragraph.add(Chunk.NEWLINE);
String s2 ="<span>" + s1 + "</span>";
addHtml(paragraph, s2);
// OK
document.add(paragraph);
document.close();
}
private void addHtml(final Paragraph paragraph, String html) throws IOException {
XMLWorkerHelper.getInstance().parseXHtml(new ElementHandler() {
#Override
public void add(Writable writable) {
if (writable instanceof WritableElement) {
for (Element element : ((WritableElement) writable).elements()) {
paragraph.add(element);
}
}
}
}, new ByteArrayInputStream(html.getBytes()), Charset.defaultCharset());
}
}
We're using version 5.5.6.
That's the expected behavior. Your html should have a root tag otherwise it's not really html. Just because the text shows in a browser doesn't mean that is well formed.
Please find the below code.
public class MakingFieldReadOnly implements PdfPCellEvent {
/** The resulting PDF. */
public static final String RESULT1 = "text_fields.pdf";
/** The resulting PDF. */
public static final String RESULT2 = "text_filled.pdf";
/** The text field index of a TextField that needs to be added to a cell. */
protected int tf;
public static final String CONTENT = "Write any thing so that it exceeds the content limit of the textfield and scroll bar comes. asdadasdasdasdasdasdasdasdasddlfjklfjljdflkjasdfjasdfjsldfjlsdjflsjdfljdflkjsdfljsldfjlsdjflskdfjlskdfjlsdjflskdjflksdjflksdjflkjsdflkjsdfljsdfkljsdlfjlsdjkfasdadasdasdasdasdasdasdasdasddlfjklfjljdflkjasdfjasdfjsldfjlsdjflsjdfljdflkjsdfljsldfjlsdjflskdfjlskdfjlsdjflskdjflksdjflksdjflkjsdflkjsdfljsdfkljsdlfjlsdjkfasdadasdasdasdasdasdasdasdasddlfjklfjljdflkjasdfjasdfjsldfjlsdjflsjdfljdflkjsdfljsldfjlsdjflskdfjlskdfjlsdjflskdjflksdjflksdjflkjsdflkjsdfljsdfkljsdlfjljkf";
/**
* Creates a cell event that will add a text field to a cell.
* #param tf a text field index.
*/
public MakingFieldReadOnly(int tf) {
this.tf = tf;
}
/**
* Manipulates a PDF file src with the file dest as result
* #param src the original PDF
* #param dest the resulting PDF
* #throws IOException
* #throws DocumentException */
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
AcroFields form = stamper.getAcroFields();
form.setField("text1_1", CONTENT);
form.setField("text1_2", CONTENT);
form.setField("text1_3", CONTENT);
form.setField("text1_4", CONTENT);
form.setFieldProperty("text1_1","setfflags",TextField.READ_ONLY , null);
form.setFieldProperty("text1_2","setfflags",TextField.READ_ONLY , null);
form.setFieldProperty("text1_3","setfflags",TextField.READ_ONLY , null);
form.setFieldProperty("text1_4","setfflags",TextField.READ_ONLY , null);
stamper.close();
//reader.close();
}
/**
* Creates a PDF document.
* #param filename the path to the new PDF document
* #throws DocumentException
* #throws IOException
*/
public void createPdf(String filename) throws DocumentException, IOException {
// step 1
Document document = new Document();
// step 2
PdfWriter.getInstance(document, new FileOutputStream(filename));
// step 3
document.open();
// step 4
PdfPCell cell;
PdfPTable table = new PdfPTable(2);
table.setWidths(new int[]{ 1, 2 });
table.addCell("Name:");
cell = new PdfPCell();
cell.setCellEvent(new MakingFieldReadOnly(1));
cell.setFixedHeight(60);
table.addCell(cell);
table.addCell("Loginname:");
cell = new PdfPCell();
cell.setCellEvent(new MakingFieldReadOnly(2));
cell.setFixedHeight(60);
table.addCell(cell);
table.addCell("Password:");
cell = new PdfPCell();
cell.setCellEvent(new MakingFieldReadOnly(3));
cell.setFixedHeight(60);
table.addCell(cell);
table.addCell("Reason:");
cell = new PdfPCell();
cell.setCellEvent(new MakingFieldReadOnly(4));
cell.setFixedHeight(60);
table.addCell(cell);
document.add(table);
// step 5
document.close();
}
/**
* Creates and adds a text field that will be added to a cell.
* #see com.itextpdf.text.pdf.PdfPCellEvent#cellLayout(com.itextpdf.text.pdf.PdfPCell,
* com.itextpdf.text.Rectangle, com.itextpdf.text.pdf.PdfContentByte[])
*/
public void cellLayout(PdfPCell cell, Rectangle rectangle, PdfContentByte[] canvases) {
PdfWriter writer = canvases[0].getPdfWriter();
TextField text = new TextField(writer, rectangle, String.format("text1_%s",tf));
text.setBackgroundColor(new GrayColor(0.75f));
text.setOptions(TextField.MULTILINE | TextField.REQUIRED);
text.setBorderStyle(PdfBorderDictionary.STYLE_BEVELED);
text.setFontSize(8);
try {
PdfFormField field = text.getTextField();
writer.addAnnotation(field);
}
catch(IOException ioe) {
throw new ExceptionConverter(ioe);
}
catch(DocumentException de) {
throw new ExceptionConverter(de);
}
}
/**
* Main method
* #param args no arguments needed
* #throws IOException
* #throws DocumentException
*/
public static void main(String[] args) throws DocumentException, IOException {
MakingFieldReadOnly example = new MakingFieldReadOnly(0);
example.createPdf(RESULT1);
example.manipulatePdf(RESULT1, RESULT2);
}
}
Please run the above code and generate the document. I have used itext-1.3.jar but same behavior shown with itext-5.3.5.jar.
In the second file named as "text_filled.pdf", I have four pdf cells(fields) in the table. My code is making these editable fields read only but I want scroll bar also(when content exceeds the field limit) as like it is coming for 4th one only, so that user can be able to view whole content without having edit permission.
Could I get read only mode with scroll bar(if content is more than limit of the text field) for each cell of the the table.
I have tried the below code also for making the fields read only.
form.setFieldProperty("text1_1","setfflags",PdfFormField.FF_READ_ONLY , null);
form.setFieldProperty("text1_2","setfflags",PdfFormField.FF_READ_ONLY , null);
form.setFieldProperty("text1_3","setfflags",PdfFormField.FF_READ_ONLY, null);
form.setFieldProperty("text1_4","setfflags",PdfFormField.FF_READ_ONLY , null);
If from these codes can't be done then any other possible solution.
I have tried your example, and I have discovered that the behavior you experience is caused by a bug in Adobe Acrobat / Reader. The bug occurs when the borders of the widget annotations of different text fields overlap.
Once I made sure that there was no overlap between the different fields, the scroll bars appeared.
How did I make sure that there was no overlap? Simply by changing the way the TextField instance created in your cellLayout() method:
Rectangle rect = new Rectangle(
rectangle.getLeft(), rectangle.getTop() - 1,
rectangle.getRight(), rectangle.getBottom() + 1);
TextField text = new TextField(writer, rect, String.format("text1_%s",tf));
Now the rectangles that define the text field no longer overlap, and you no longer experience the Adobe Acrobat / Reader bug.