I'm setting the visibility of a PdfFormField to HIDDEN using the setVisibility() method with parameter PdfFormField.HIDDEN. Still, on flattening it, the field does not hide. Below is the code to do so.
File file = new File("path to PDF file");
baos = new ByteArrayOutputStream();
pdfDoc = new PdfDocument(new PdfReader(file.getAbsolutePath()), new PdfWriter("path to flattened PDF file"));
//This function removes all the permissions.
removePdfPermissions();
form = PdfAcroForm.getAcroForm(pdfDoc, true);
fields = form.getFormFields();
fields.get("HumanSubjectsText").setVisibility(PdfFormField.HIDDEN);
fields.get("HumanSubjects").setVisibility(PdfFormField.HIDDEN);
form.flattenFields();
pdfDoc.close();
Setting the values of the fields to empty string "" is a workaround, but not the proper way.
The fields "HumanSubjects" and "HumanSubjectsText" correspond to a checkbox and its correspond text on page 2. (Human Subjects)
Link to PDF file
The fields could not be hidden using iText library. In contrast to Bruno's comment, one of the methods from iText library worked well, the setValue(). I'm not quite sure why the setVisibility() fails.
However, I was able to hide the field using Master PDF editor tool. I've attached a screenshot of this tool, where you can change the visibility for a form field from the General tab.
An observation: In the com.itextpdf.forms.fields.PdfFormField some of the constants defined are as follows:
public static final int HIDDEN = 1;
public static final int VISIBLE_BUT_DOES_NOT_PRINT = 2;
public static final int HIDDEN_BUT_PRINTABLE = 3;
public static final int VISIBLE = 4;
The Master PDF editor also has similar options to hide a field. Please refer to the attached screenshot.
NOTE: My requirement was just to simply hide the field. It could be achieved programmatically by using a library like iText or with some PDF editor tool.
Related
I'm using iText 7 to construct reusable PDF components that I reuse across multiple pages within a document. I'm using iText-dotnet for this task (v7), using F# as the language. (This shouldn't be hard to follow for non-F# people as it's just iText calls :D)
I know how to add annotations to a Page, that isn't the issue. Adding the annotation to the page is as simple as page.AddAnnotation(newAnnotation).
Where I'm having difficulty, is that there is no "Page" associated with a Canvas when you are using a PdfFormXObject() to render a Pdf fragment.
let template = new PdfFormXObject(rect)
let templateCanvas = PdfCanvas(template, pageContext.Canvas.GetPdfDocument())
let newCanvas = new Canvas(templateCanvas, rect)
Once I have the new Canvas, I try to write to the Canvas and add the Annotation via Page.AddAnnotation(). The problem is that there is no Page attached to the PdfFormXObject!
// Create the destination and annotation (destPage is the pageNumber)
let dest = PdfExplicitDestination.CreateFitB(destPage)
let action = PdfAction.CreateGoTo(dest)
let annotation = PdfLinkAnnotation(rect)
let border = iText.Kernel.Pdf.PdfAnnotationBorder(0f, 0f, 0f)
// set up the Annotation with action and display information
annotation
.SetHighlightMode(PdfAnnotation.HIGHLIGHT_PUSH)
.SetAction(action)
.SetBorder(border)
|> ignore
// Try adding the annotation to the page BOOM! (There is *NO* page (null) associated with newCanvas)
newCanvas.GetPage().AddAnnotation(annotation) |> ignore // HELP HERE: Is there another way to do this?
The issue is that I do not know of a different way to set the Annotation on the canvas. Is there a way to render the annotation and just add the annotation directly to the canvas as raw PDF instructions?
Alternatively, is there a way create a different reusable PDF fragment in iText so I can also reuse the GoTo annotation.
N.B. I could split off the annotations and then apply them every time I use the PdfFormXObject() on a new page, but that sort of defeats the purpose of reusing Pdf fragments (template) in my final PDF to reduce it's size.
If you can point me in the right direction, that would be great.
Again, this is not how to add an annotation to a Page(), that's easy. It's how to add an annotation to a PdfFormXObject (or similar mechanism that I'm unaware of for constructing rusable Pdf fragments).
-- As per John's comments below:
I cannot seem to find any reference to single use annotations.
I'm aware of the following example link, so I modified it to look like this:
private static void Main(string[] args)
{
try
{
PdfDocument pdfDocument = new PdfDocument(new PdfWriter("TestMultiLink.pdf"));
Document document = new Document(pdfDocument);
string destinationName = "MyForwardDestination";
// Create a PdfStringDestination to use more than once.
var stringDestination = new PdfStringDestination(destinationName);
for (int page = 1; page <= 50; page++)
{
document.Add(new Paragraph().SetFontSize(100).Add($"{page}"));
switch (page)
{
case 1: // First use of PdfStringDestination
document.Add(new Paragraph(new Link("Click here for a forward jump", stringDestination).SetFontSize(20)));
break;
case 3: // Re-use the stringDestination
document.Add(new Paragraph(new Link("Click here for a forward jump", stringDestination).SetFontSize(10)));
break;
case 42:
pdfDocument.AddNamedDestination(destinationName, PdfExplicitDestination.CreateFit(pdfDocument.GetLastPage()).GetPdfObject());
break;
}
if (page < 50)
document.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
}
document.Close();
}
catch (Exception e)
{
Console.WriteLine($"Ouch: {e.Message}");
}
}
If you dig into the iText source for iText.Layout.Link, you'll see that the String Destination is added as an Annotation. Therefore, I'm not sure if John's answer is true anymore.
Does anyone know how I can convert the Annotation to a Dictionary and how I would go about adding the PdfDictionary (raw) info into the PftFormXObject?
Thanks
#johnwhitington is correct.
Per PDF specification, annotations can only be added to a page, they cannot be added to a form XObject. It is not a limitation of iText or any other PDF library.
Annotations cannot be reused, each annotation is a distinct object.
the following szenario is given: party 1 signs pdf, party 2 fills out AcroForm field and then also signs the pdf.The problem is, after the second signature, the form field value only appears if I click in the field. Both the form filling process and the signature process happen in append mode.signing pdf code:
using (PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0', tempFolder, true))
{
// Creating the signature
SigPadSignature sig = new SigPadSignature(sigInfo, DigestAlgorithms.SHA256);
// Creating the appearance
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.Reason = sigInfo.Reason;
appearance.Location = sigInfo.Location;
appearance.Contact = sigInfo.ContactInfo;
appearance.Certificate = chain[0];
appearance.SignatureCreator = sigInfo.SignatureCreator;
appearance.SetVisibleSignature(area.CreateRectangle(), area.PageNumber, fieldName);
appearance.Layer2Text = string.Format("\n{0}\n{1}, {2:g}", sigInfo.SignerName, sigInfo.Location, DateTime.Now);
appearance.Layer2Font = new Font(Font.FontFamily.COURIER, 7.0f);
appearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION;
appearance.SignatureGraphic = Image.GetInstance(sigInfo.SignatureImage, System.Drawing.Imaging.ImageFormat.Bmp);
appearance.SignatureEvent = sig;
MakeSignature.SignDetached(appearance, sig, chain, /*crlList*/null, /*ocspClient*/null, /*tsaClient*/null, estimatedSize, CryptoStandard.CMS);
}
fill form field code:
using (PdfStamper stamper = new PdfStamper(reader, outStrm, '\0', true))
{
stamper.AcroFields.SetField("fieldname", "test1234");
}
Here is a example PDF. If you open it in AdobeReader you can see the szenario described. The form field value only appears when clicking the field.
What am I doing wrong? Any suggestions?
Greetings
In short
You actually discovered a bug in iTextSharp v5.x (also in iText v5.x and OpenPdf). When working in append mode in this library, one must mark each indirect object from the original file one manipulated as 'used' but iText(Sharp) forgets to do so for one object in the context of changing the field appearance.
This object needs not be indirect, actually it more often is direct or absent than indirect; thus, this bug does not have a visible effect very often.
You can work around this by removing that object in its previous form before setting setting the field value:
using (PdfStamper stamper = new PdfStamper(reader, outStrm, '\0', true))
{
stamper.AcroFields.GetFieldItem("AcroFormField_0").GetWidget(0).Remove(PdfName.AP);
stamper.AcroFields.SetField("AcroFormField_0", "test1234");
}
(Actually some null checks wouldn't hurt here either...)
In detail
When setting the field value, eventually AcroFields.SetField(String name, String value, String display, bool saveAppearance) is called. In case of a text field, the new appearance of that field is updated in that method by this code:
PdfAppearance app = GetAppearance(merged, display, name);
...
PdfDictionary appDic = widget.GetAsDict(PdfName.AP);
if (appDic == null) {
appDic = new PdfDictionary();
widget.Put(PdfName.AP, appDic);
merged.Put(PdfName.AP, appDic);
}
appDic.Put(PdfName.N, app.IndirectReference);
writer.ReleaseTemplate(app);
If there was no appearance dictionary before, a new one is created as direct object and everything works as desired. If there was an appearance dictionary as direct object, it's just the same as the widget is marked used further down. But if there was an appearance dictionary appDict as indirect object, this dictionary is not marked used and, therefore, the change (appDic.Put(PdfName.N, app.IndirectReference)) is not eventually saved, i.e. the new appearance is not associated with the field widget.
A fix would be to mark a previously existing appearance dictionary as used, e.g. like this:
if (appDic == null) {
...
} else {
MarkUsed(appDic);
}
By removing it first as proposed above one makes iText create a new appearance dictionary as direct object, so the bug is circumvented.
And what about the signatures...?
It looks like Adobe Reader recognizes that the previous processor forgot to update the appearance and so does that itself under the hood in case of the PDF in which as last action the field value was set.
After adding another signature to that PDF, though, Adobe Reader apparently does not want to do this under the hood anymore. This would after all change what the signer had seen when signing, and Adobe tries to prevent such situations in which its software could be blamed for changing previously signed data...
I have to fill PDF form with some data. This form contains a few tables with "Add" button which adds new row with inputs to this table, for example to "FOREIGN PATENT DOCUMENTS".
I need to "click" this button in my code using iText a few times, add necessary rows, get input names there and fill them. How can I do this with iText? Could anybody provide me a code example?
My PDF file with form https://drive.google.com/open?id=0BwtWU1543EbTQ3A3b2dZcW9qYk0
This file is predefined and I can't regenerate it.
You don't "click" a button programmatically. You just provide the data that is necessary, and the form will adapt.
See the FillXFA example. We have a purchase_order.pdf that looks like this:
This document has an "Add item" button to add more line items (which results in creating more pages if necessary). That button only makes sense if there's a GUI, but when you fill out the form programmatically, there aren't any buttons to push. You just provide the XML with the data (e.g. data.xml), like this:
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();
XfaForm xfa = form.getXfa();
xfa.fillXfaForm(new FileInputStream(XML));
stamper.close();
reader.close();
}
The result looks like this: purchase_order_filled.pdf
As you can see, multiple lines were added, without pushing any button.
Important: I see that you have a hybrid document. I think you should make it a pure XFA form. This code won't work if you keep the AcroForm fields.
I'm working to refactor a PDF form web application that is using the Active PDF Toolkit and the FDFToolkit from Adobe. My goal is to use iTextSharp to:
Pre-populate the form fields with data from the database
Allow the user to attach a signature and/or barcode image via FDF
Item #1 is not the problem. Item #2 is the biggest challenge. Let me provide some background:
This is a web application which renders the PDF form once. After the initial load, there are 2 key buttons on the form which submit the PDF form to a URL with an action parameter in the query string. These buttons are called "Save" and "Sign". The Save button takes the FDF field dictionary and saves it to the database. The Sign button looks up the signature for the logged-in user and attaches the signature image to the FDF and writes the FDF to the HTTP Response.
The FDFToolkit supports attaching an image to a field using this method:
FDFSetAP(string bstrFieldName, short whichFace, string bstrFileName, short pageNum)
iTextSharp does not offer a comparable method in the FdfWriter class. I've considered subclassing the FdfWriter class and adding my own method to attach an image, but wanted to reach out here to see if anyone has had the same problem.
I have been able to overlay an image on top of a field using this method, but this is in the underlying PDF and not the FDF.
AcroFields.FieldPosition pos = _Stamper.AcroFields.GetFieldPositions("SIGNATUREFIELD").First();
Image signature = Image.GetInstance("Signature.gif");
image.SetAbsolutePosition(pos.position.Left, pos.position.Bottom);
image.ScaleToFit(pos.position.Width, pos.position.Height);
PdfContentByte pcb = _Stamper.GetOverContent(pos.page);
pcb.AddImage(image);
Thanks!
I've put images on forms by using the PdfStamper and making Pushbutton fields. You can replace your existing field with a Pushbutton field and set the Pushbutton to READ_ONLY so that it can't be pressed and it will look like a static image. This will keep the image you're trying to add as a field annotation instead of adding it to the page content.
using (PdfStamper stamper = new PdfStamper(new PdfReader(inputFile), File.Create(outputFile)))
{
AcroFields.FieldPosition fieldPosition = stamper.AcroFields.GetFieldPositions(fieldName)[0];
PushbuttonField imageField = new PushbuttonField(stamper.Writer, fieldPosition.position, fieldName);
imageField.Layout = PushbuttonField.LAYOUT_ICON_ONLY;
imageField.Image = iTextSharp.text.Image.GetInstance(imageFile);
imageField.ScaleIcon = PushbuttonField.SCALE_ICON_ALWAYS;
imageField.ProportionalIcon = false;
imageField.Options = BaseField.READ_ONLY;
stamper.AcroFields.RemoveField(fieldName);
stamper.AddAnnotation(imageField.Field, fieldPosition.page);
}
Our company using iText to stamp some watermark text (not image) on some pdf forms. I noticed 95% forms shows watermark correctly, about 5% does not. I tested, copy 2 original pdf files, one was marked ok, other one does not ok, then tested in via a small program, same result: one got marked, the other does not. I then tried the latest version of iText jar file (version 5.0.6), same thing. I checked pdf file properties, security settings etc, seems nothing shows any hint. The result file does changed size and markd "changed by iText version...." after executed program.
Here is the sample watermark code (using itext jar version 2.1.7), note topText, mainText, bottonText parameters passed in, make 3 lines of watermarks show in the pdf as watermark.
Any help appreciated !!
public class WatermarkGenerator {
private static int TEXT_TILT_ANGLE = 25;
private static Color MEDIUM_GRAY = new Color(160, 160, 160);
private static int SUPPORT_FONT_SIZE = 42;
private static int PRIMARY_FONT_SIZE = 54;
public static void addWaterMark(InputStream pdfInputStream,
OutputStream outputStream, String topText,
String mainText, String bottomText) throws Exception {
PdfReader reader = new PdfReader(pdfInputStream);
int numPages = reader.getNumberOfPages();
// Create a stamper that will copy the document to the output
// stream.
PdfStamper stamp = new PdfStamper(reader, outputStream);
int page=1;
BaseFont baseFont =
BaseFont.createFont(BaseFont.HELVETICA_BOLDOBLIQUE,
BaseFont.WINANSI, BaseFont.EMBEDDED);
float width;
float height;
while (page <= numPages) {
PdfContentByte cb = stamp.getOverContent(page);
height = reader.getPageSizeWithRotation(page).getHeight() / 2;
width = reader.getPageSizeWithRotation(page).getWidth() / 2;
cb = stamp.getUnderContent(page);
cb.saveState();
cb.setColorFill(MEDIUM_GRAY);
// Top Text
cb.beginText();
cb.setFontAndSize(baseFont, SUPPORT_FONT_SIZE);
cb.showTextAligned(Element.ALIGN_CENTER, topText, width,
height+PRIMARY_FONT_SIZE+16, TEXT_TILT_ANGLE);
cb.endText();
// Primary Text
cb.beginText();
cb.setFontAndSize(baseFont, PRIMARY_FONT_SIZE);
cb.showTextAligned(Element.ALIGN_CENTER, mainText, width,
height, TEXT_TILT_ANGLE);
cb.endText();
// Bottom Text
cb.beginText();
cb.setFontAndSize(baseFont, SUPPORT_FONT_SIZE);
cb.showTextAligned(Element.ALIGN_CENTER, bottomText, width,
height-PRIMARY_FONT_SIZE-6, TEXT_TILT_ANGLE);
cb.endText();
cb.restoreState();
page++;
}
stamp.close();
}
}
We solved problem by change Adobe LifecycleSave file option. File->Save->properties->Save as, then look at Save as type, default is Acrobat 7.0.5 Dynamic PDF Form File, we changed to use 7.0.5 Static PDF Form File (actually any static one will work). File saved in static one do not have this watermark disappear problem. Thanks Mark for pointing to the right direction.
You're using the underContent rather than the overContent. Don't do that. It leaves you at the mercy of big, white-filled rectangles that some folks insist on drawing first thing. It's a hold over from less-than-good PostScript interpreters and hasn't been necessary for Many Years.
Okay, having viewed your PDF, I can see the problem is that this is an XFA-based form (from LiveCycle Designer). Acrobat can (and often does) rebuild the entire file based on the XFA (a type of xml) it contains. That's how your changes are lost. When Acrobat rebuilds the PDF from the XFA, all the existing PDF information is pitched, including your watermark.
The only way to get this to work would be to define the watermark as part of the XFA file contained in the PDF.
Detecting these forms isn't all that hard:
PdfReader reader = new PdfReader(...);
AcroFields acFields = reader.getAcroFields();
XfaForm xfaForm = acFields.getXfaForm();
if (xfaForm != null && xfaForm.isXfaPresent()) {
// Ohs nose.
throw new ItsATrapException("We can't repel XML of that magnitude!");
}
Modifying them on the other hand could be Quite Challenging, but here's the specs.
Once you've figured out what needs to be changed, it's a simple matter of XML manipulation... but that "figure it out" part could be interesting.
Good hunting.