iText 7 - Regenerate BarCode field created with Adobe - java

I come to you because I've a question !
I created a barCode with Adobe Acrobat in a acroform PDF. I can set the new value to the barCode field but I can't generate the new "appearance" with the new value. How can I do that ?
This is how I do for now with no success ... :
PdfFormField field = fields.get("QRCODE");
field.setValue(this.generateXMLDataMatrix(),false);
form = form.setNeedAppearances(true);
form.flattenFields();
pdf.close();
So for now, I still have the default appearance created in Adobe Acrobat :(
Thank you for you help ! :)

You will have to generate the field appearance manually. Here is an example of how to do it for a QR code one:
PdfFormField field = fields.get("QRCODE");
// Get the annotation. If you might have multiple representations of the same field across the document the just iterate over all widgets
PdfWidgetAnnotation annotation = field.getWidgets().get(0);
// This class will help us draw the barcode
BarcodeQRCode qrCode = new BarcodeQRCode(this.generateXMLDataMatrix());
// Get the number of rectangles constituting the barcode
Rectangle size = qrCode.getBarcodeSize();
// Creating a new FormXObject that will become our apperance. Set the dimension(bbox) of the current appearance
PdfFormXObject newAppearance = new PdfFormXObject(annotation.getAppearanceObject(PdfName.N).getAsRectangle(PdfName.BBox));
// Helper class to draw on FormXObject
PdfCanvas barcodeCanvas = new PdfCanvas(newAppearance, pdfDocument);
// Calculating the side of the smaller rectangle in the barcode
float side = Math.min(annotation.getRectangle().toRectangle().getHeight() / size.getHeight(),
annotation.getRectangle().toRectangle().getWidth() / size.getWidth());
// Draw the barcode on the XObject
qrCode.placeBarcode(barcodeCanvas, ColorConstants.BLACK, side);
// Set appearance to the newly generated one
annotation.setAppearance(PdfName.N, newAppearance.getPdfObject());

SOLVED! This how i finally did it :
//Generate BarCodedataMatrix
BarcodeDataMatrix dataMatrix = new BarcodeDataMatrix();
//Add code to the BarCodedataMatrix
dataMatrix.setCode(generateXMLDataMatrix());
dataMatrix.setOptions(BarcodeDataMatrix.DM_AUTO);
//Add dataMatrix to PDF
//Create a canvas for the first page
PdfCanvas canvas = new PdfCanvas(pdf.getFirstPage());
//Create the PdfFormXObject based on the dataMatrix
PdfFormXObject object = dataMatrix.createFormXObject(pdf);
//Add the pdfFormXObject to the canvas at X,Y position
canvas.addXObject(object,50,660);

Related

iText fails to render paragraph with overlength text

I want to add a variable string to a fixed drawing rectangle using iText 7 - this is a sample code:
try (PdfWriter writer = new PdfWriter("test.pdf");
PdfDocument pdf = new PdfDocument(writer)) {
// Create a page
PdfPage currentPage = pdf.addNewPage(PageSize.A4);
// Create the position rectangle
Rectangle rect = new Rectangle(
75f,
currentPage.getPageSize().getHeight() - 315f - 22f,
75f,
22f
);
// Create the font
PdfFont currentFont = PdfFontFactory.createFont(
"Helvetica",
"Cp1252"
);
// Create the paragraph
Paragraph p = (new Paragraph("Some longer value"))
.setFont(currentFont)
.setFontSize(12f)
.setWidth(75f)
.setHeight(22f)
.setTextAlignment(TextAlignment.LEFT);
// Add the paragraph
(new Canvas(new PdfCanvas(currentPage), pdf, rect))
.add((BlockElement)p);
}
When I run this code, I'll get this exception when the last line is being executed:
Exception in thread "main" java.lang.IllegalArgumentException: fromIndex(0) > toIndex(-1)
at java.base/java.util.AbstractList.subListRangeCheck(AbstractList.java:509)
at java.base/java.util.ArrayList.subList(ArrayList.java:1138)
at com.itextpdf.layout.renderer.ParagraphRenderer.layout(ParagraphRenderer.java:235)
at com.itextpdf.layout.renderer.RootRenderer.addChild(RootRenderer.java:84)
at com.itextpdf.layout.renderer.CanvasRenderer.addChild(CanvasRenderer.java:86)
at com.itextpdf.layout.RootElement.add(RootElement.java:98)
at itext.bug.reproduce.ITextBugReproduce.main(ITextBugReproduce.java:50)
When I replace Some longer value with test, everything works. So it seems adding an overlength string to a small drawing area fails.
The problem is: In real know only the destination drawing area, but I don't know the string which is going to be processed. This leads to my question: How can I draw even an overlength string to the PDF without pre-measuring etc.?
Update: When I expand the paragraph dimensions, I still have the same exception, so I assume its not a problem with the paragraph, but with the canvas which I use to restrict drawing to the destination rectangle (for not overwriting any contents outside of the rectangle).
With a newer iText 7 version (I used 7.0.1 before) and a slightly different code it's working now:
BasicConfigurator.configure();// Satisfy the logger
try (PdfWriter writer = new PdfWriter("test.pdf");
PdfDocument pdf = new PdfDocument(writer)) {
// Create a page
PdfPage currentPage = pdf.addNewPage(PageSize.A4);
// Create the position rectangle
Rectangle rect = new Rectangle(
75f,
currentPage.getPageSize().getHeight() - 315f - 22f,
75f,
22f
);
// Create the font
PdfFont currentFont = PdfFontFactory.createFont(
"Helvetica",
"Cp1252"
);
// Create the paragraph
Paragraph p = (new Paragraph("Some longer value"))
.setFont(currentFont)
.setFontSize(12f)
.setWidth(75f)
.setHeight(22f)
.setTextAlignment(TextAlignment.LEFT);
// Override the renderer
p.setNextRenderer(new ParagraphRenderer(p){
#Override
public List initElementAreas(LayoutArea area) {
List list = new ArrayList();
list.add(rect);
return list;
}
});
// Add the paragraph
(new Canvas(new PdfCanvas(currentPage), rect))
.add((BlockElement)p);

Can java use pdfbox to turn the red stamp into black

I tried to use the following code to convert the stamp color, but it didn't work
PDFDocumentSignature signature = signatures.get(i);
PDPageContentStream contents2 = new PDPageContentStream(pdDocument, pages,PDPageContentStream.AppendMode.APPEND, false, false);
PDExtendedGraphicsState r01 = new PDExtendedGraphicsState();
r01.setBlendMode(BlendMode.SATURATION);
contents2.setGraphicsStateParameters(r01);
contents2.setNonStrokingColor(Color.DARK_GRAY);
contents2.addRect(signature.getX(), signature.getY(), signature.getHeight(), signature.getHeight());
contents2.fill();
contents2.close();`
As it turned out in the comments to the question, the red stamp in question is a signature form field widget.
This explains why the OP's code could not de-saturate the stamp: That code de-saturates a portion of the static page content. Widgets (and annotations in general), though, are not part of the static page content but are rendered on top of it.
Thus, we have to manipulate the content stream of the widget annotation in question or another annotation over it.
You can manipulate the signature appearance like this:
PDDocument pdf = ...;
PDAcroForm acroForm = pdf.getDocumentCatalog().getAcroForm();
PDTerminalField acroField = (PDTerminalField) acroForm.getField("Signature1");
PDAnnotationWidget widget = acroField.getWidgets().get(0);
PDAppearanceStream appearance = widget.getAppearance().getNormalAppearance().getAppearanceStream();
byte[] originalBytes;
try ( InputStream oldContent = appearance.getContents() ) {
originalBytes = IOUtils.toByteArray(oldContent);
}
try ( PDPageContentStream canvas = new PDPageContentStream(pdf, appearance) ) {
canvas.appendRawCommands(originalBytes);
PDExtendedGraphicsState r01 = new PDExtendedGraphicsState();
r01.setBlendMode(BlendMode.SATURATION);
canvas.setGraphicsStateParameters(r01);
canvas.setNonStrokingColor(Color.DARK_GRAY);
PDRectangle bbox = appearance.getBBox();
canvas.addRect(bbox.getLowerLeftX(), bbox.getLowerLeftY(), bbox.getWidth(), bbox.getHeight());
canvas.fill();
}
pdf.save(RESULT);
(ChangeAppearance test testRemoveAppearanceSaturation)
before
after

IText 7 How To Add Div or Paragraph in Header Without Overlapping Page Content?

I am facing the following problem for which i haven't found any solution yet. I am implementing a platform for a medical laboratory. They want for every incident to write the report to the system and then generate and print it from the system. I am using itext 7 to accomplish this. However i am facing the following problem.
They have a very strange template. On the first page in the beginning they want to print a specific table, while in the beginning of every other page they want to print something else. So i need to know when pages change in order to print in the beginning of the page the corresponding table.
After reading various sources i ended up creating the first page normally and then adding a header event handler that checks the page number and gets executed always except page 1.
public class VariableHeaderEventHandler implements IEventHandler {
#Override
public void handleEvent(Event event) {
System.out.println("THIS IS ME: HEADER EVENT HANDLER STARTED.....");
PdfDocumentEvent documentEvent = (PdfDocumentEvent) event;
PdfDocument pdfDoc = documentEvent.getDocument();
PdfPage page = documentEvent.getPage();
Rectangle pageSize = page.getPageSize();
int pageNumber = pdfDoc.getPageNumber(page);
if (pageNumber == 1) return; //Do nothing in the first page...
System.out.println("Page size: " + pageSize.getHeight());
Rectangle rectangle = new Rectangle(pageSize.getLeft() + 30, pageSize.getHeight()-234, pageSize.getWidth() - 60, 200);
PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);
pdfCanvas.rectangle(rectangle);
pdfCanvas.setFontAndSize(FontsAndStyles.getRegularFont(), 10);
Canvas canvas = new Canvas(pdfCanvas, pdfDoc, rectangle);
Div header = new Div();
Paragraph paragraph = new Paragraph();
Text text = new Text("Διαγνωστικό Εργαστήριο Ιστοπαθολογίας και Μοριακής Παθολογοανατομικής").addStyle(FontsAndStyles.getBoldStyle());
paragraph.add(text);
paragraph.add(new Text("\n"));
text = new Text("Μοριακή Διάγνωση σε Συνεργασία με").addStyle(FontsAndStyles.getBoldStyle());
paragraph.add(text);
paragraph.add(new Text("\n"));
text = new Text("Γκούρβας Βίκτωρας, M.D., Ph.D.").addStyle(FontsAndStyles.getBoldStyle());
paragraph.add(text);
paragraph.add(new Text("\n"));
text = new Text("Τσιμισκή 33, Τ.Κ. 54624, ΘΕΣΣΑΛΟΝΙΚΗ").addStyle(FontsAndStyles.getNormalStyle());
paragraph.add(text);
paragraph.add(new Text("\n"));
text = new Text("Τήλ/Φάξ: 2311292924 Κιν.: 6932104909 e-mail: vgourvas#gmail.com").addStyle(FontsAndStyles.getNormalStyle());
paragraph.add(text);
header.add(paragraph);
// =============Horizontal Line BOLD============
SolidLine solidLine = new SolidLine((float) 1.5);
header.add(new LineSeparator(solidLine));
// ========Horizontal Line BOLD End==========
text = new Text("ΠΑΘΟΛΟΓΟΑΝΑΤΟΜΙΚΗ ΕΞΕΤΑΣΗ").addStyle(FontsAndStyles.getBoldStyle());
paragraph = new Paragraph().add(text);
header.add(paragraph);
header.setTextAlignment(TextAlignment.CENTER);
canvas.add(header);
canvas.close();
}
However the problem i am facing now is that header overlaps content and i can't figure out how to set different margins per page. For example form page 2 and beyond i would like different topMargin.
Has anyone faced these problems before and have found a working solution? Am I implementing correct? Is there a better way of accomplishing the same result?
Thanks in advance,
Toutoudakis Michail
You should create your own custom document renderer and decrease the area which would be used to place content for each page except for the first one.
Please look at the snippet below and updateCurrentArea method in particular.
class CustomDocumentRenderer extends DocumentRenderer {
public CustomDocumentRenderer(Document document) {
super(document);
}
#Override
public IRenderer getNextRenderer() {
return new CustomDocumentRenderer(this.document);
}
#Override
protected LayoutArea updateCurrentArea(LayoutResult overflowResult) {
LayoutArea area = super.updateCurrentArea(overflowResult);
if (currentPageNumber > 1) {
area.setBBox(area.getBBox().decreaseHeight(200));
}
return area;
}
}
Then just set the renderer on your document:
Document doc = new Document(pdfDoc);
doc.setRenderer(new CustomDocumentRenderer(doc));
The resultant pdf which I get for your document looks as follows:
There is another solution however. Once you've added at least one element to your document, you can change the default document's margins. The change will be applied on all pages created afterwards (and in your case these are pages 2, 3, ...)
doc.add(new Paragraph("At least one element should be added. Otherwise the first page wouldn't be created and changing of the default margins would affect it."));
doc.setMargins(200, 36, 36, 36);
// now you can be sure that all the next pages would have new margins

Read tick boxes given as images in PDF using iText

I have a PDF form where there are check boxes given as images in the PDF. I am using itext to read the PDF, I also want to get the value of the checkbox as ticked or unticked.
iText does not return anything for the images, below is the iText code:
PdfReader reader = new PdfReader(path);
Rectangle mediaboxKeys=reader.getPageSize(i);
mediaboxKeys.setRight((float) 100.00);
RenderFilter[] filterKeys = {new RegionTextRenderFilter(mediaboxKeys)};
FilteredTextRenderListener strategyKeys = new FilteredTextRenderListener(new LocationTextExtractionStrategy(), filterKeys);
String[] keysFromPage = PdfTextExtractor.getTextFromPage(reader, i, strategyKeys).split("\\r?\\n");
Attached is the pdf : https://drive.google.com/file/d/1D9TNnHZe5kqwv6LKIVO94Am1nl8AnrB1/view

iText Rectangle how to set color using setBorderColorxxx | how to add text to Rectangle [duplicate]

This question already has an answer here:
How to add overlay text with link annotations to existing pdf?
(1 answer)
Closed 7 years ago.
Two questions,
How to hide or set color white to Rectangle box border
How to add text to Rectangle
public void addLinkedtoTOC(String src, String dest,String IMG,int linkedPageNumber,int linkDisplayTOCPageNumber) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
Rectangle linkLocation = new Rectangle(320, 695, 560, 741);
linkLocation.setBorderColorLeft(BaseColor.WHITE);
linkLocation.setBorderColorRight(BaseColor.RED);
linkLocation.setBorderColorTop(BaseColor.RED);
PdfDestination destination = new PdfDestination(PdfDestination.FIT);
PdfAnnotation link = PdfAnnotation.createLink(stamper.getWriter(), linkLocation, PdfAnnotation.HIGHLIGHT_INVERT,linkedPageNumber, destination);
stamper.addAnnotation(link, linkDisplayTOCPageNumber);
stamper.close();
reader.close();
}
Your first question is easy. It's a duplicate of iText - How to stamp image on existing PDF and create an anchor
When you create a PdfAnnotation object that represents a link annotation, a border is defined by default. You can remove this border using the setBorder() method at the level of the annotation as is done in the AddImageLink example:
link.setBorder(new PdfBorderArray(0, 0, 0));
Your second question has also been answered before. See for instance:
How to add text at an absolute position on the top of the first page?
How to add text inside a rectangle?
How to truncate text within a bounding box?
How to fit a String inside a rectangle?
I have combined both in the AddLinkAnnotation5 example:
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
// Here we define the location:
Rectangle linkLocation = new Rectangle(320, 695, 560, 741);
// here we add the actual content at this location:
ColumnText ct = new ColumnText(stamper.getOverContent(1));
ct.setSimpleColumn(linkLocation);
ct.addElement(new Paragraph("This is a link. Click it and you'll be forwarded to another page in this document."));
ct.go();
// now we create the link that will jump to a specific destination:
PdfDestination destination = new PdfDestination(PdfDestination.FIT);
PdfAnnotation link = PdfAnnotation.createLink(stamper.getWriter(),
linkLocation, PdfAnnotation.HIGHLIGHT_INVERT,
3, destination);
// If you don't want a border, here's where you remove it:
link.setBorder(new PdfBorderArray(0, 0, 0));
// We add the link (that is the clickable area, not the text!)
stamper.addAnnotation(link, 1);
stamper.close();
reader.close();
}
However, there's also another way to add the text and the link annotation at the same time. That's explained in my answer to the duplicate question: How to add overlay text with link annotations to existing pdf?
In this answer, I refer to the AddLinkAnnotation2 example, where we add the content using ColumnText as described above, but we introduce a clickable Chunk:
Chunk chunk = new Chunk("The Best iText Questions on StackOverflow", bold);
chunk.setAnchor("http://developers.itextpdf.com/frequently-asked-developer-questions");
Wrap the chunk object inside a Paragraph, add the Paragraph using ColumnText and you have your borderless link.

Categories

Resources