I need to insert an image based on a generated barcode file.
The problem I'm having is when using the iTextSharp library I can normally fill in text such as
PdfReader pdfReader = new PdfReader(oldFile);
PdfStamper pdfStamper = new PdfStamper(pdfReader, outFile);
AcroFields fields = pdfStamper.AcroFields;
fields.SetField("topmostSubform[0].Page1[0].BARCODE[0]", "X974005-1");
though there's one field where in pdf if I click onto it it prompts me for an image to insert into field, but I can't seem to programmatically accomplish this. Based on some google searches and stumbling upon a stackoverflow page, I inserted the following code expecting it to work as desired:
string fieldName = "topmostSubform[0].Page1[0].BARCODE[0]";
string imageFile = "test-barcode.jpg";
AcroFields.FieldPosition fieldPosition = pdfStamper.AcroFields.GetFieldPositions(fieldName)[0];
PushbuttonField imageField = new PushbuttonField(pdfStamper.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;
pdfStamper.AcroFields.RemoveField(fieldName);
pdfStamper.AddAnnotation(imageField.Field, fieldPosition.page);
The problem I am having is while it removes the existing field as intended, when I open the newly created PDF file I don't see this new push button field with the intended image file but rather as a blank but when I perform this through debug mode I can see that it's at least picking up the correct dimensions of the image file, so I don't know what I'm doing wrong here.
Please advise, thanks.
If you read the official documentation (that is: my book), you'll find this example: ReplaceIcon.cs
You're removing the field using pdfStamper.AcroFields.RemoveField(fieldName); and subsequently you try adding the new field using pdfStamper.AddAnnotation(imageField.Field, fieldPosition.page);
That's wrong. You should replace the field using pdfStamper.AcroFields.ReplacePushbuttonField(fieldname, imageField.Field);
The ReplacePushbuttonField() method copies plenty of settings behind the scenes.
Related
I'm making a simple program with .NET and iText7
Inserting a signature image in a PDF document is one of the functions under production.
It has been implemented until the image is inserted into the PDF and newly saved, but I don't know if the image goes behind the text.
The Canvas function seems to be possible, but no matter how many times I look at the example, I can't see any parameters related to the placement.
It would be nice to present a keyword that can implement the function.
The sample results are attached to help understanding. In the figure, the left is the capture of the PDF in which I inserted my signature using a word processor, and the right is the capture of the PDF generated through IText.
My iText version is .Net 7.2.1.
I attached the code below just in case it was necessary.
Thank you.
public void PDF_SIGN(FileInfo old_fi)
{
string currentPath = System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
String imageFile = currentPath + "\\sign.jpg";
ImageData data = ImageDataFactory.Create(imageFile);
string source = old_fi.FullName;
string sourceFileName = System.IO.Path.GetFileNameWithoutExtension(source);
string sourceFileExtenstion = System.IO.Path.GetExtension(source);
string dest = old_fi.DirectoryName + "\\" + sourceFileName + "(signed)" + sourceFileExtenstion;
PdfDocument pdfDoc = new PdfDocument(new PdfReader(source), new PdfWriter(dest));
Document document = new Document(pdfDoc);
iText.Layout.Element.Image image = new iText.Layout.Element.Image(data);
image.ScaleAbsolute(Xsize, Ysize);
image.SetFixedPosition(1, Xaxis, Yaxis);
document.Add(image);
document.Close();
pdfDoc.Close();
}
Sample Result (Left: Gaol, Right: Current result):
You can organize content you add using iText in the same pass before or behind each other simply by the order of adding, and layout elements may have background images or colors.
The previously existing content of the source document, consequentially, usually serves as a mere background of everything new. Except, that is, if you draw to a page in a content stream that precedes earlier content.
Unfortunately you cannot use the Document class for this as its renderer automatically works in the foreground. But you can use the Canvas class here; this class only works on a single object (e.g. a single page) but it can be initialized in a far more flexible way.
In your case, therefore, replace
Document document = new Document(pdfDoc);
iText.Layout.Element.Image image = new iText.Layout.Element.Image(data);
image.ScaleAbsolute(Xsize, Ysize);
image.SetFixedPosition(1, Xaxis, Yaxis);
document.Add(image);
document.Close();
by
iText.Layout.Element.Image image = new iText.Layout.Element.Image(data);
image.ScaleAbsolute(Xsize, Ysize);
image.SetFixedPosition(1, Xaxis, Yaxis);
PdfPage pdfPage = pdfDoc.GetFirstPage();
PdfCanvas pdfCanvas = new PdfCanvas(pdfPage.NewContentStreamBefore(), pdfPage.GetResources(), pdfDoc);
using (Canvas canvas = new Canvas(pdfCanvas, pdfPage.GetCropBox()))
{
canvas.Add(image);
}
and you should get the desired result.
(Actually I tested that using Java and ported it to C# in writing this answer. I hope it's ported all right.)
As an aside, if you only want to put an image on the page, you don't really need the Canvas, you can directly use one of the AddImage* methods of PdfCanvas. For multiple elements to be automatically arranged, though, using the Canvas is a good idea.
Also I said above that you cannot use Document here. Actually you can if you replace the document renderer that class uses. For the task at hand that would have been an overkill, though.
When using the iText7 library to set a PDF document's properties the value for the builtin property author is getting doubled like '"Lastname, Firstname"; Lastname; Firstname'. It should be 'Lastname, Firstname'. It is getting the double quotes added, the name value twice and a comma changed to a semicolon. This has happened in two versions, 7.1.17 and 7.2.1.
The steps in creating the PDF are:
Use Microsoft.Interop.Word Document.ExportAsFixedFormat() to create the first PDF used by readerPDF. This does not get the custom document properties to populate. I need to set four custom properties used by a later step in this process.
Use iText7 to read the above PDF, add the custom document properties and also reset the built in properties and write that out to a second file accessed trough writerPDF. iText7 only modifies a PDF by reading from file and writing to a second.
In step 2 the code calls the command to set the author property, PdfDocument.PdfDocumentInfo.SetAuthor(authorvalue);
The problem seems to only happen with commas in the author value, and I need the commas to do Lastname, Firstname. That is a requirement. If I do not reset the property Author is has double quotes around it, that is not useful for our project. All other properties, builtin and custom are working as expected.
The code looks like this:
iText.Kernel.Pdf.PdfReader readerPDF;
iText.Kernel.Pdf.PdfWriter writerPDF;
string authorValue = "Lastname, Firstname";
readerPDF = new PdfReader(saveAsPathAndNameTemp);
writerPDF = new PdfWriter(pSavedPathAndPDFName);
PdfDocument pdfdocument = new PdfDocument(readerPDF, writerPDF);
PdfDocumentInfo info = pdfdocument.GetDocumentInfo();
info.SetAuthor(string.Empty);
info.SetAuthor(authorValue);
pdfdocument.Close();
readerPDF.Close();
writerPDF.Close();
There is issue in Adobe Acrobat reader. I used the next code to reproduce your issue on Java:
String filename = DESTINATION_FOLDER + "openSimpleDoc.pdf";
String author = "Test, Author";
String title = "Test, Title";
String subject = "Test, Subject";
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(filename));
pdfDoc.getDocumentInfo().setAuthor(author).setTitle(title).setSubject(subject);
pdfDoc.addNewPage();
pdfDoc.close();
PdfReader reader = new PdfReader(filename);
pdfDoc = new PdfDocument(reader);
Assert.assertEquals(author, pdfDoc.getDocumentInfo().getAuthor());
Assert.assertEquals(title, pdfDoc.getDocumentInfo().getTitle());
Assert.assertEquals(subject, pdfDoc.getDocumentInfo().getSubject());
pdfDoc.close();
As you can see, I didn't set the author twice and when I open the resulting PDF in Adobe Acrobat, I see that the author's name is enclosed in two quotes:
But in fact there are no two quotes. You can see it in PDF Studio, RUPS and Notepad++:
PDF Studio
RUPS
Notepad++
I resolved the main issue, the duplicating of the Author value if a comma was in the value. I updated the reference BouncyCastle.Crypto to 1.9.0.0. That resolved the main issue. the secondary issue of the double quotes in properties dialog box is address below by Nikita Kovaliov. I thank this poster for there input.
I am using iText to fill a pdf. This pdf contains a xfa from, I fill this form through a xml file . After filling the form user need to download it and sign it manually. So far so good everything works fine every field in form filled properly. If user sign the file adobe reader make a new copy of file with signature.
But when user try to sign that pdf it gives following error and the newly generated file with signature doesn't save data, It make all field blank.
At least one signature has problems
When user sign pdf adobe reader also give a popup on signature verification
But if i fill the same pdf manually without using itext it allow me to sign pdf successfully
this is the code that i am using to fill pdf with xml data :
public static byte[] FillXfaForm(byte[] byteArray, String xmlFilePath)
{
PdfReader reader = new PdfReader(byteArray);
using (MemoryStream ms = new MemoryStream())
{
using (PdfStamper stamper = new PdfStamper(reader, ms,'\0',true))
{
stamper.Writer.CloseStream = false;
stamper.AcroFields.Xfa.FillXfaForm(xmlFilePath);
}
if(File.Exists(xmlFilePath))
{
File.Delete(xmlFilePath);
}
return ms.ToArray();
}
}
And here is the screen shot of error message
Please help me to solve this issue.
Finally I fix this problem
The cause of this problem is that i update whole xml document to fill xfa from but when i only update the data part not the whole xml it works without any error.
I don't know what is the difference it really create as in this similar question "Bruno Lowagie" state that you can either use full xml replace or you can change data part only.
How can I set XFA data in a static XFA form in iTextSharp and get it to save?
But for me it allow me to sign the document only if I replace data part not the whole xml data.
I hope it will help someone facing similar problem.
I am generating collections (Acrobat Portfolios) via iTextSharp. I would like to assign an existing custom navigator (custom layout) to the generated collection. I believe iTextSharp allows for the CUSTOM parameter to define a custom navigator, as in the last code line of this block:
Document document = new Document();
FileStream stream = new FileStream(portfolioPath, FileMode.Create);
PdfWriter writer = PdfWriter.GetInstance(document, stream);
document.Open();
document.Add(new Paragraph(" "));
PdfCollection collection = new PdfCollection(PdfCollection.CUSTOM);
//The integer 3 can also substitute for PdfCollection.CUSTOM
However, when the collection/portfolio is generated the CUSTOM parameter inserts the TILE layout within the generated collection. I want to have the CUSTOM parameter use a custom .nav navigator I developed to insert a custom layout.
I located this post on SO:
How to embed a .nav file into pdf portfolio?
which lead to:
Adobe® Supplement to the
ISO 32000
BaseVersion: 1.7
ExtensionLevel: 3e
Pages 34 - 37 of this document says it is possible to have the collection access the custom navigator by adjusting the Navigator entry in the collection dictionary and the navigator dictionary itself. Additionally, page 541 of the Second Edition of iText in Action implies this is possible (and it is my hope what is possible in iText is also possible in iTextSharp).
So is it possible -- using iTextSharp -- to have a generated collection/portfolio access and implement a custom layout/navigator? If so, how? Or is there another way to do this via C# and/or through some workaround? All help is greatly appreciated.
I found a different way to dictate the custom layout/navigator using iTextSharp. Instead of defining the custom layout during or after
PdfCollection collection = new PdfCollection(PdfCollection.CUSTOM);
I threw out the code listed in my question and used the iTextSharp stamper.
First, I created an empty portfolio file. Within this file I assigned the custom layout that I wanted to use. When opened the file displays the layout, but contains no attached files. This file will serve as a template and assign it's navigator to each newly created iTextSharp PDF using this code:
const string templatePath = #"C:\PortfolioTemplate\PortfolioTemplate.pdf"; //this file will contain the custom navigator/layout for the new pdf
const string portfolioPath = #"C:\OutputFile\NewPortfolio.pdf";
string[] packageitems = { file-to-add-to-collection };
PdfReader reader = new PdfReader(templatePath);
FileStream outputstream = new FileStream(portfolioPath, FileMode.Create);
PdfStamper stamp = new PdfStamper(reader, outputstream);
PdfFileSpecification fs = PdfFileSpecification.FileEmbedded(stamp.Writer, packageitems[0], packageitems[0], null);
stamp.AddFileAttachment(packageitems[0], fs);
stamp.Close();
I used the above proof of concept to loop through all the files in a directory folder and I have created large portfolios without issue that are styled using the custom navigator/layout I wanted.
After coming up with the idea of using a template to pass the navigator into a newly created portfolio, I used the code in the below link to guide me to the above conclusion:
http://itextsharp.10939.n7.nabble.com/Attach-file-td3812.html
I am looking for a way to merge the content of two pdf pages.
It could be a watermark, an image or whatever.
The scenario is as follows:
I have a Word-addin that allows the user to create different templates for different customers based on several template forms. For each new customer, the user can provide a new letter paper containing header image / logos and footer. This shall be applied anyhow at runtime. Could be an image that is loaded directly into the header of the template (then I would need to render pdf to image, for the letter paper will mostly be provided as pdf-file) or when exporting the document (merging letter paper as background).
But the template shall not be accessible by the user, so this must be done programmatically.
So far, I tried Pdfsharp library, which does not support neither the version of my provided backpapers, nor the version of my documents created in Word 2007.
iTextSharp seemed very promising, but I could not manage to merge the contents so far.
I also tried pdftk.exe, but even when i ran it manually from command line, I got the error: "Done. Input errors, so no output created."
It does not matter how it is handled, but the output matters.
I forgot to mention, there is a whiteline created in the Word-template for archiving purposes, so this part may not be added as image or it has to be added afterwords into the output document.
Thanks in advance!
StampStationery.cs, a sample from the Webified iTextSharp Examples which essentially are the C#/iTextSharp versions of the Java/iText samples from the book iText in Action — 2nd Edition, does show how to add the contents of a page from one PDF document as stationery behind the content of each page of another PDF.
The central method is this:
public byte[] ManipulatePdf(byte[] src, byte[] stationery)
{
// Create readers
PdfReader reader = new PdfReader(src);
PdfReader s_reader = new PdfReader(stationery);
using (MemoryStream ms = new MemoryStream())
{
// Create the stamper
using (PdfStamper stamper = new PdfStamper(reader, ms))
{
// Add the stationery to each page
PdfImportedPage page = stamper.GetImportedPage(s_reader, 1);
int n = reader.NumberOfPages;
PdfContentByte background;
for (int i = 1; i <= n; i++)
{
background = stamper.GetUnderContent(i);
background.AddTemplate(page, 0, 0);
}
}
return ms.ToArray();
}
}
This method returns the manipulated PDF as a byte[].