iText 7: Generated Stamp Breaks Upon Rotation - c#

I'm trying to create stamps using iTextsharp - as far as I'm concerned, the position and size of the resulting stamp is handled appropriately. However, once the user opens the document using the reader, attempting to rotate the stamp simply breaks it. The stamp turns into blank box with an "X" as shown below:
The code I am using is as follows:
Rectangle location = new Rectangle(crop.GetLeft(),crop.GetBottom(),iWidth/4,iHeight/4);
PdfStampAnnotation stamp = new PdfStampAnnotation(location).SetStampName(new PdfName("Logo"));
PdfFormXObject xObj = new PdfFormXObject(new Rectangle(iWidth, iHeight));
PdfCanvas canvas = new PdfCanvas(xObj, pdfDoc);
canvas.AddImage(img, 0, 0,iWidth, false);
stamp.SetNormalAppearance(xObj.GetPdfObject());
stamp.SetFlags(PdfAnnotation.PRINT);
pdfDoc.GetFirstPage().AddAnnotation(stamp);
pdfDoc.Close();
I am tempted to say that the image is not bound with the rectangle and ends up breaking apart upon rotation. However, assuming the stamp is created correctly, it seems confusing to me because this is a manipulation done via Acrobat. I would assume that the reader attempts rotation by first rotating and resizing the bounding rectangle before trying to rotate the image.
It is also worth noting that scaling and moving the stamp DOES work - is there an attribute I forgot to include in my construction of the stamp?

Up front a warning: The following is a result of trial and error using only Adobe Acrobat Reader DC on Windows. Results might differ on different platforms, for different versions, and most probably for different viewer products.
The specification
As far as the PDF specification is concerned, there is nothing wrong with your approach. All it says about stamp annotations is
12.5.6.12 Rubber Stamp Annotations
A rubber stamp annotation (PDF 1.3) displays text or graphics intended to look as if they were stamped on the page with a rubber stamp. When opened, it shall display a pop-up window containing the text of the associated note. Table 181 shows the annotation dictionary entries specific to this type of annotation.
Table 181 – Additional entries specific to a rubber stamp annotation
Subtype
name
(Required) The type of annotation that this dictionary describes; shall be Stamp for a rubber stamp annotation.
Name
name
(Optional) The name of an icon that shall be used in displaying the annotation. Conforming readers shall provide predefined icon appearances for at least the following standard names:
Approved, Experimental, NotApproved, AsIs, Expired , NotForPublicRelease, Confidential, Final, Sold, Departmental, ForComment, TopSecret, Draft, ForPublicRelease
Additional names may be supported as well. Default value: Draft.
The annotation dictionary’s AP entry, if present, shall take precedence over the Name entry; see Table 168 and 12.5.5, “Appearance Streams.”
Your chosen name Logo is not in that enumeration but you supply a custom appearance after all.
Adobe Reader
Thus, this issue has nothing to do with the PDF but with the way Adobe Reader implements Rubber Stamp annotation rotation changes.
I tested the behavior of Adobe Acrobat Reader DC in this regard and it turns out that upon rotation it always recreates the appearance of a rubber stamp annotation from the resources known to itself, using that X graphic whenever it does not know the annotation type. E.g. if you change the appearance of a standard annotation created by Adobe Reader and then rotate it, it regains its Adobe Reader look and feel.
So it always recreates the appearance of a rubber stamp annotation upon rotation unless it recognizes it as a custom, user defined stamp! And it recognizes user defined stamps by their name starting with a '#' character.
The fix
Thus, if you change
PdfStampAnnotation stamp = new PdfStampAnnotation(location).SetStampName(new PdfName("Logo"));
to
PdfStampAnnotation stamp = new PdfStampAnnotation(location).SetStampName(new PdfName("#Logo"));
the resulting PDF should behave as desired (at least it does so here).
Beware: As this behavior is not prescribed by the specification, it might change any time.
E.g. when I created a user defined stamp with Adobe Reader here, it got the name #zKzrX95V9NYDDQGyrLjmOA. There might be something like a checksum letter in this name, or it might be something like a hash of the appearance or whatever. In such a case Adobe might start in some later version to only recognize rubber stamp annotations which also fulfill this condition as user defined.
Violation of the specification?
You might wonder whether this is a violation of the specification as quoted above which does not define special names for "user defined annotations".
It is not.
The specification mostly defines how a specific PDF is to be displayed, it hardly specifies how it is to be edited.
In particular the prescription in the quote above
The annotation dictionary’s AP entry, if present, shall take precedence over the Name entry
only refers to displaying PDFs, not to editing them.

Related

PDF-A1a document not valid after signing with VisualRepresentation using IText

I digitally sign a PDF-A1a document using IText 7.15.0.
In addition to the digital signature, I also add a visual representation (image) to the document.
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance.SetPageNumber(1);
Rectangle pr = new Rectangle(10 + ImageOffset, 10 + ImageOffset, 100, 100 );
appearance.SetPageRect(pr);
byte[] image = System.IO.File.ReadAllBytes(VisualAppearance);
appearance.SetRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
ImageData imageData = ImageDataFactory.Create(image);
appearance.SetSignatureGraphic(imageData);
This code works and the signature is valid.
But if the document was a PDF-A1a, it is no longer a valid PDF-A1a. It only becomes invalid when I add the visual representation. If I just apply the signature without the visual representation, it remains a valid PDF-A1a.
Other PDF-A standards like A2a do remain valid when adding the visual representation.
When using foxit phantom to validate the PDF-A1a, it shows the following message:
A transparent soft mask is present. Beginning with PDF 1.4 transparency is supported. Some PDF-based ISO standards prohibit the use of transparency.
What do i need to do in order to keep a PDF-A1a valid while adding the visual representation?
As Foxit already informs, some standards prohibit the use of transparency within a conforming file, in particular ISO 19005-1 does for PDF/A-1 profiles by a number of provisions, among them:
If an SMask key appears in an ExtGState or XObject dictionary, its value shall be None.
(ISO 19005-1, section 6.4 Transparency)
But if iText adds an image with transparency information to a PDF, it translates the transparency information to a non-vanishing SMASK entry of the resulting image XObject.
To prevent this, simply use images without transparency.
In a comment to your parallel question you confirm
If i use jpeg instead of png, the PDF-A1a remains valid.
For non-rectangular image outlines consider using a clip path.

Fill pdf check field with iText7

I'm trying check a checkbox on my PDF with iText7.
But instead of checking only one field, it's checking all fields
What I need:
What I get:
PDF when editing:
I think the exported value has something to do with it.
But I don't kown what to do.
My code:
private static void CreatePdf(string output)
{
using var _pdfDoc = new PdfDocument(new PdfReader("CheckTest.pdf"), new PdfWriter(output));
var form = PdfAcroForm.GetAcroForm(_pdfDoc, true);
var check = form.GetField("Check");
check.SetValue("01");
}
PDF: Link
Someone know how to check it properly?
Thanks!
First of all, the PDF essentially mis-uses PDF AcroForm check box fields as radio buttons instead of using genuine PDF AcroForm radio button fields.
The PDF specification does not clearly specify what a PDF viewer should do in such a case (it's mis-use after all) but the developers of the PDF form generator in question probably have experimented and determined that in the most widely used PDF viewer, Adobe Acrobat Reader, this mis-use works just as they want.
As this use is beyond specification, though, other PDF processors processing such PDFs may produce completely different results without doing anything wrong.
That being said, there is a way to fill the form using iText and achieve results similar to those generated by Adobe Reader.
The problem at hand is that iText by default for all form field types except actual AcroForm radio button fields generates new appearances in a way appropriate for the field type when setting the field value. In your document there are three check box field objects with the same name. Thus, they are considered a single check box with three widgets representing the same value, and so the appearances are generated as you observe.
But you can tell iText to not generate new appearances, using another SetValue overload accepting an additional boolean value, simply replace
check.SetValue("01");
by
check.SetValue("01", false);
Now iText makes do with the existing appearances, so only the field becomes checked that has an appearance for that "01" value.
Beware, only prevent iText from generating appearances in cases like this. In case of text fields, for example, not updating the appearances would cause the old appearances with the former field content to continue to be displayed even though the internal field value changed.
A did it like this:
Dim MyPDFFormCheckBoxField As Fields.PdfFormField = myform.GetField("myCheckBox")
MyPDFFormCheckBoxField.SetCheckType(PdfFormField.TYPE_CHECK)
MyPDFFormCheckBoxField.SetValue("", If(myCheckBox.IsChecked = True, True, False))
Notice that it is the second parameter of SetValue that is setting the checkbox True or False.

Get document properties from PDF in iTextSharp

I'm trying to get some information out of a PDF file. I've tried using PdfSharp, and it has properties for the information I need, but it cannot open iref streams, so i've had to abandon it.
Instead i'm trying iTextSharp. so far i've managed to get some basic information out, like the title, aurhor and subject, from the Info array.
However, i'm now after a bit more information, but cannot find where it is exposed (if it is exposed) in iTextSharp.... The information I am after is highlighted in the image below:
I cannot figure out where this information is stored. Any and all help will be much appreciated.
For documents encrypted using standard password encryption you can retrieve the permissions after opening the file in a PdfReader pdfReader using
getPermissions() in case of iText/Java
int permissions = pdfReader.getPermissions()
Permissions in case of iTextSharp/.Net
int permissions = pdfReader.Permissions
The int value returned is the P value of the encryption dictionary which contains
A set of flags specifying which operations shall be permitted when the document is opened with user access (see Table 22).
[...]
The value of the P entry shall be interpreted as an unsigned 32-bit quantity containing a set of flags specifying which access permissions shall be granted when the document is opened with user access. Table 22 shows the meanings of these flags. Bit positions within the flag word shall be numbered from 1 (low-order) to 32 (high order). A 1 bit in any position shall enable the corresponding access permission.
[...]
Bit position Meaning
3 (Security handlers of revision 2) Print the document. (Security handlers of revision 3 or greater) Print the document (possibly not at the highest quality level, depending on whether bit 12 is also set).
4 Modify the contents of the document by operations other than those controlled by bits 6, 9, and 11.
5 (Security handlers of revision 2) Copy or otherwise extract text and graphics from the document, including extracting text and graphics (in support of accessibility to users with disabilities or for other purposes). (Security handlers of revision 3 or greater) Copy or otherwise extract text and graphics from the document by operations other than that controlled by bit 10.
6 Add or modify text annotations, fill in interactive form fields, and, if bit 4 is also set, create or modify interactive form fields (including signature fields).
9 (Security handlers of revision 3 or greater) Fill in existing interactive form fields (including signature fields), even if bit 6 is clear.
10 (Security handlers of revision 3 or greater) Extract text and graphics (in support of accessibility to users with disabilities or for other purposes).
11 (Security handlers of revision 3 or greater) Assemble the document (insert, rotate, or delete pages and create bookmarks or thumbnail images), even if bit 4 is clear.
12 (Security handlers of revision 3 or greater) Print the document to a representation from which a faithful digital copy of the PDF content could be generated. When this bit is clear (and bit 3 is set), printing is limited to a low-level representation of the appearance, possibly of degraded quality.
(Section 7.6.3.2 "Standard Encryption Dictionary" in the PDF specification ISO 32000-1)
You can use the PdfWriter.ALLOW_* constants in this context.
Concerning the dialog screenshot you made, though, be aware that the operations effectively allowed do not only depend on the PDF document but also on the PDF viewer! Otherwise you might be caught in the same trap as the OP of this question.
Thanks to mkl for your answer, it was part of the story, but here is the answer which you helped me find:
using (var pdf = new PdfReader(File))
{
Console.WriteLine(PdfEncryptor.IsModifyAnnotationsAllowed(pdf.Permissions));
}
The PdfEncryptor is what was missing, it converts the P value into a simple bool for yes or no. Other methods on there are:
IsAssemblyAllowed
IsCopyAllowed
IsDegradedPrintingAllowed
IsFillInAllowed
IsModifyAnnotationsAllowed
IsModifyContentsAllowed
IsPrintingAllowed
IsScreenReadersAllowed
As for the security method part, this is what i went with:
using (var pdf = new PdfReader(File))
{
Console.WriteLine(!pdf.IsOpenedWithFullPermissions == Expected);
}

Is it possible to modify spot color names in a PDF using iTextSharp in C#?

Is it possible to modify spot color names in a PDF using iTextSharp in C#, its just the Colour name that requires changing.
So you have an existing PDF that uses some spot colors, for instance a color named "ABC", and you want to manipulate that PDF so that the name is "XYZ".
This is possible, but it requires low-level PDF syntax manipulation.
You need to create a PdfReader instance, look for the dictionary that defines the spot color, change the name, then use PdfStamper to create a new file based on the altered PdfReader instance.
There is no "ready-made" example on how to answer your specific question (I doubt somebody else but the original developer of iText will answer a question like this), but you can get some inspiration by looking at the code samples from chapter 13 of the second edition of "iText in Action": http://itextpdf.com/book/chapter.php?id=13
See for instance the manipulatePdf() method in this example: http://itextpdf.com/examples/iia.php?id=239
In this example an URL is replaced by another one using the principle explained above.
You need to adapt this example so that you find the path to the place where the spot color name is stored, change that name, and persist the changes.
Hint: the Spot color name will be in an array of which the first element is a name (/Separation), the second entry will be the name you want to change (this is the one you want to replace with a new PdfName instance), and so on.
How to find this /Separation array? I would loop over the pages (the getPageN() method will give you the page dictionary), get the resources of every page (pageDict.getAsDict(PdfName.RESOURCES)), look for the existence of a /Colorspace dictionary, then look for all the /Separation colors in that dictionary. Replace the second element whenever you encounter a name you want to change.
The examples in chapter 13 in combination with ISO-32000-1 (can be downloaded from the Adobe.com site) will lead the way.

How do I force formatting and calculations in a PDF when filling other fields using iTextSharp?

I have a PDF form with a number of text fields. The values entered in these fields are used to calculate values in other fields (the calculated fields are read-only).
When I open the form in Adobe Reader and fill in a field, the calculated fields automatically re-calculate.
However, I am using iTextSharp to fill in the fields, flatten the resulting form, then stream the flattened form back to the user over the web.
That part works just fine except the calculated fields never calculate. I'm assuming that since no user triggered events (like keydowns or focus or blur) are firing, the calculations don't occur.
Obviously, I could remove the calculations from the fillable form and do them all on the server as I am filling the fields, but I'd like the fillable form to be usable by humans as well as the server.
Does anyone know how to force the calculations?
EDIT:
I ain't feeling too much iText/iTextSharp love here...
Here are a few more details. Setting stamper.AcroFields.GenerateAppearances to true doesn't help.
I think the answer lies somewhere in the page actions, but I don't know how to trigger it...
Paulo Soares (one of the main devs of iText and current maintainer of iTextSharp) says:
iText doesn't do any effort to fix
calculated fields because most of the
times that's impossible. PdfCopyFields
has some support for it that sometimes
works and sometimes don't.
I have updated all the calculated fields of my pdfs by calling the javascript method calculateNow on the Doc object.
According to the adobe javascript documentation this.calculateNow();
Forces computation of all calculation fields in the current document.
When a form contains many calculations, there can be a significant delay after the user inputs data into a field, even if it is not a calculation field. One strategy is to turn off calculations at some point and turn them back on later (see example).
To include the javascript call with iTextSharp :
using (PdfReader pdfReader = new PdfReader(pdfTemplate))
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(newFile, FileMode.Create)))
{
// fill f1 field and more...
AcroFields pdfFormFields = pdfStamper.AcroFields;
pdfFormFields.SetField("f1", "100");
//...
// add javascript on load event of the pdf
pdfStamper.JavaScript = "this.calculateNow();";
pdfStamper.Close();
}
I have figured out how to do this. Please see my answer for the stackoverflow question:
How to refresh Formatting on Non-Calculated field and refresh Calculated fields in Fillable PDF form
On the server side, see if there is an answer in the calculated fields. If not, calculate them.
As Greg Hurlman says, you should do the calculations yourself on the server. This is for more than just convenience, there's actually a good reason for it.
Any file that the customer has, they have the potential to screw with. I don't know what the PDF forms are for, but chances are it's connected to money somehow, so the potential exists for people to cheat by making the calculations show the wrong result. If you trust the calculations done on the client side, you have no way of detecting it.
When you recieve the PDF form from the client, you should redo all calculations so that you know they're correct. Then if you also have the client's versions to compare to, you should check whether they've been screwed with.
Don't think your clients are that untrustworthy? Good for you, but the evidence disagrees. One of my earliest introductions to programming was opening up the savegames for SimCity to give myself more money. If the opportunity exists to cheat in some way, then at some point people will try it.

Categories