How do you style a substring in a PDF (in Adobe Acrobat)? - pdf

Editing a PDF (specifically a user-editable form) using Adobe Acrobat, and using the PDF JavaScript API, is it possible to style separate substrings within a field value? Is there a markup language used, for example?
A bit of pseudocode for what I’m talking about:
This word is <red>red</red>, this word is <bold>bold</bold>. I have spoken.

The answer is to:
a) Make sure the field type is rich text, and
b) Use Adobe's JavaScript methods to set spans within the field's richValue property with the formatting desired, for example:
var field = this.getField("MyRichTextField");
var spans = new Array();
spans[0] = new Object();
spans[0].text = "This word is ";
spans[1] = new Object();
spans[1].text = "red";
spans[1].textColor = color.red;
field.richValue = spans;
Further details and a list of span properties can be found in Acrobat JavaScript Scripting Reference (https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/Acro6JS.pdf)

Related

itextsharp - AcroForm field value disappears after signing PDF document

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...

Custom Property for PDF File

I would like to add total page count as a custom property like ms word does as follow.
Is it possible to similar things for pdf? I am also using aspose for file conversion. I converter many kind of file types to pdf but if we want to show also the document's pagen count as the custom property.
This is from the Aspose Newsgroup:
//open document
Aspose.Pdf.Document pdfDocument = new Aspose.Pdf.Document("Test.pdf");
//set properties
pdfDocument.Metadata["xmp:Nickname"] = "Nickname";
pdfDocument.Metadata["xmp:CreatorTool"] = "Test Value";
pdfDocument.Metadata["xmp:CustomProperty"] = "Custom Value";
//Convert to PDF/A compliant document
pdfDocument.Validate("log.xml", PdfFormat.PDF_A_1A);
pdfDocument.Convert("log.xml", PdfFormat.PDF_A_1A, ConvertErrorAction.Delete);
//save output document
pdfDocument.Save("output_XMP.pdf");
Is this what you are looking for?

PdfFormField simply does not hide when setting the visibility to HIDDEN

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.

How to clean existing properties and replace with metadata template on Photoshop (scripting)?

While creating a script that would automate all the different tasks I do when I start working on a new picture on Photoshop, I encountered the following problem.
Manually, I would Ctrl + Alt + Shift + I, click on the template I want and choose the option "Clear existing properties and replace with template properties".
I can't find the way to do precisely this. The best thing I managed to find is something like this :
app.activeDocument.info.author = "test";
app.activeDocument.info.caption = "";
app.activeDocument.info.captionWriter = "";
app.activeDocument.info.headline = "";
app.activeDocument.info.instructions = "";
app.activeDocument.info.keywords = "";
app.activeDocument.info.authorPosition = "";
app.activeDocument.info.credit = "";
app.activeDocument.info.source = "";
app.activeDocument.info.category = "";
app.activeDocument.info.supplementalCategories = "";
app.activeDocument.info.title = "";
// etc.
And it actually doesn't really work like the "Clear existing properties and replace with template properties".
I didn't find anything on the Photoshop scripting guide, nor on the internet. Any help would be greatly appreciated !
What I think is the problem is Photoshop separates file-metadata from its activeDocument-metadata. What you see in "File info..." (via Ctrl+Alt+Shift+I) is supposed to represent the file in the filesystem, which metadata is embedded in.
There are several scripting guides to Photoshop scripting. I think the one relevant for you would be "Javascript Tools Guide", specifically the chapter 10 "Scripting Access to XMP Metadata".
Is it important for you to set up the metadata already when creating a new picture? If not, you may want to look at a solution using a customized export script.
It customizes XMP-metadata upon exporting like
Create a basic metadata object:
var meta = new XMPMeta();
Provide a namespaceURI (see XMP specs) known to photoshop along with tag name, and value:
meta.setProperty(XMPConst.NS_XMP, "CreatorTool", app.version);
Save the image temporarily (using other script):
var imgFile = new File(fileName);
saveImage(fileName);
Finish saving by adding the metadata-object:
var metaFile = new XMPFile(imgFile.fsName, XMPConst.FILE_UNKNOWN, XMPConst.OPEN_FOR_UPDATE);
if (metaFile.canPutXMP(meta)) { metaFile.putXMP(meta); }
metaFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY);
Doing it this way also erases any existing or default metadata.

Dynamic XFA PDF Forms

I have a number of Dynamic XFA PDFs that were created with Livecycle Designer. These PDFs are used as templates for various individuals to complete. When a user requests a template we have to write a submit button with url pointing back to a .net application for processing and update some of the fields with information from the database into the PDF.
Can I use iText(Sharp) with .net to update the dynamic xfa pdf to write into it a submit button and update fields and then use iText(Sharp) to process the returning form.
We are doing this now with Acroforms but need to do the same for Dynamic XFA forms as well. I can’t find any confirmation information that this is possible. If it is possible does anyone have any code that they can share to show me how to do this?
You can also achieve that putting the pdf's content inside an XmlDocument and working as you were working with an XML.
This is the code I use to replace some placeholders written in textboxes.
PdfReader pdfReader = new PdfReader(path_pdf);
using (PdfStamper pdfStamp = new PdfStamper(pdfReader, new FileStream(temp_path, FileMode.Create), '\0', true))
{
pdfStamp.ViewerPreferences = PdfWriter.AllowModifyContents;
XmlDocument xmlDocument = pdfReader.AcroFields.Xfa.DomDocument;
string pdfContent = xmlDocument.InnerXml;
string newpdfContent = pdfContent
.Replace("$CONTENT_TO_REPLACE_1$", "some_content")
.Replace("$CONTENT_TO_REPLACE_2$", "some_other_content")
xmlDocument.InnerXml = newpdfContent;
Stream stream = GenerateStreamFromString(newpdfContent);
pdfStamp.AcroFields.Xfa.FillXfaForm(stream);
pdfStamp.AcroFields.Xfa.DomDocument = xmlDocument;
pdfStamp.Close();
}