itextsharp stamper vs smartcopy, show pdf in browser without toolbar or navpanes - pdf

My application is grabbing pdf bytes from our db and sending the pdf to an iframe, using the itextsharp library. When the pdf is displayed in the iframe, the toolbar and navigation pane show, but we'd like to hide those. When I load a pdf document by simply typing in the pdf's url with #toolbar=0&navpanes=0, I see the result I'm looking for.
The application logic is using PdfStamper to add some buttons and other data to the pdf. When I write the pdf to the Response.Outputstream, the pdf shows up with the added buttons, and all is good except that I can't get rid of the toolbar and navpanes. I've tried adding "toolbar=0&navpanes=0" to the url in the response header, but to no avail.
I've written a test application which shows that using PdfSmartCopy instead of the stamper works perfectly - the pdf is shown in the browser which hides the toolbar and navpane by default.
The problem is that I still need to add some buttons to the pdf via the stamper. I've written a test app which adds the buttons via the stamper, then the smart copy grabs each page from the stamper and writes all this out to the Response.Output. The pdf shows in the browser with no toolbar or navpanes, but the buttons are not there.
Here is the code which uses both the stamper and the smart copy - your help is greatly appreciated:
private void SendStamperToCopy()
{
try
{
String filePath = #"C:\debug\PerfIndicWithDefaults.pdf";
byte[] pdfBytes = ReadFile(filePath);
Document document = new Document();
PdfSmartCopy copy = new PdfSmartCopy(document, Response.OutputStream);
document.Open();
MemoryStream memStream = new MemoryStream();
PdfReader reader = new PdfReader(pdfBytes);
PdfStamper pdfStamper = new PdfStamper(reader, memStream);
// add a button with the stamper
iTextSharp.text.Rectangle rectCancel = new iTextSharp.text.Rectangle(50, 50, 20, 20);
PushbuttonField btnCancel = new PushbuttonField(pdfStamper.Writer, rectCancel, "Cancel");
btnCancel.Text = "Cancel";
iTextSharp.text.pdf.PdfAnnotation fieldCancel = btnCancel.Field;
pdfStamper.AddAnnotation(fieldCancel, 1);
int numOfPgs = reader.NumberOfPages;
for (int n = 1; n <= numOfPgs; n++)
{
copy.AddPage(pdfStamper.GetImportedPage(reader, n));
}
String headerStr = "inline; filename=PerfIndicWithDefaults.pdf";
Response.AppendHeader("content-disposition", headerStr);
Response.ContentType = "application/pdf";
Response.OutputStream.Flush();
document.Close();
Response.OutputStream.Close();
}
catch (Exception ex)
{
Console.Write(ex);
Response.OutputStream.Flush();
Response.OutputStream.Close();
}
}

If I understand your question correctly, you want to use PdfStamper to add a button and you want to change the viewer preferences. This can be done like this:
PdfReader reader = new PdfReader(source);
System.IO.MemoryStream m = new System.IO.MemoryStream();
PdfStamper stamper = new PdfStamper(reader, m);
PdfStamper.ViewerPreferences = PdfWriter.HideToolbar | PdfWriter.PageModeUseNone;
stamper.Close();
reader.Close();
The HideToolbar will hide the toolbar, whereas PageModeUseNone means that you don't show any panels (such as the bookmarks panel, etc...).
It is not clear why you would need PdfSmartCopy in this context. Maybe I'm missing something. Also: there are some strange errors in your code: you never close the stamper instance, yet you import a page from the stamper into the copy instance. I've never seen any one try that. It's certainly not what I had in mind when I wrote iText. Your code is very confusing to me.

Related

How to add an image to a pdf file in APPEND mode using PdfStamper?

I'm using the iTextSharp library version 5.5.6.0.
This file contains customizable text fields and it's necessary to keep an interactive text form fields: https://yadi.sk/i/yoUvDI9EmtVhc .
But I can't adding an image in PdfTemplate object.
The code in c# at this stage is:
string outpath = #"D:\pdf_\output.pdf";
string inpath = #"D:\pdf_\input.pdf";
string stamp = #"D:\pdf_\img.png";
This method does'nt add the image, but the text boxes are active.
public static void onlyInteractive()
{
using (MemoryStream os = new MemoryStream())
using (PdfReader pdfReader = new PdfReader(inpath))
//APPEND mode
using (PdfStamper stamper = new PdfStamper(pdfReader, os, '\0', true))
{
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
image.SetAbsolutePosition(0, 0);
PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
template.AddImage(image);
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
os.WriteTo(new FileStream(outpath, FileMode.Create, FileAccess.ReadWrite));
}
}
The behavior of this method back to the first.
public static void onlyImage()
{
using (Stream output = new FileStream(outpath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
using (PdfReader reader = new PdfReader(inpath))
using (var stamper = new PdfStamper(reader, output, '\0', true))
{
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
image.SetAbsolutePosition(0, 0);
PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
template.AddImage(image);
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
}
}
onlyInteractive
The issue with this code is that you grab the output PDF before it is finished:
using (PdfStamper stamper = new PdfStamper(pdfReader, os, '\0', true))
{
[...]
os.WriteTo(new FileStream(outpath, FileMode.Create, FileAccess.ReadWrite));
}
When the stamper is getting closed (here implicitly at the end of its using block), some not yet stored PDF objects are written and the internal cross references and the file trailer are written.
You write the os contents to file before that. Thus, your result document is incomplete. Adobe Reader upon opening it repairs it which results in essentially your original document.
onlyImage
This code by itself is correct, it stamps the image onto the document and stores it correctly.
Your problem here is that the document itself is Reader-enabled, i.e. it is signed with a so called usage rights signature. Such signatures tell Adobe Reader upon opening a file to make additional features available displaying editing the document in question.
But when checking the signature on the document with the image, Adobe Reader sees that the document has been changed in a way that is not compatible with the usage rights granted by the signature: An image has been added to the page content which is something not granted by the signature. Thus, Adobe Reader revokes the granted features, in your case form editing.
Removing the usage rights signature
One option in this situation is to remove that signature. In that case form editing is not granted anymore by means of that signature. But in newer Adobe Reader versions (since version XI if I recall correctly) form editing has been granted to all documents by default! In your case that feature is removed due to the invalidated signature!
This can be done as follows:
using (Stream output = new FileStream(outpath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
using (PdfReader reader = new PdfReader(inpath))
using (var stamper = new PdfStamper(reader, output))
{
reader.RemoveUsageRights();
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
image.SetAbsolutePosition(0, 0);
PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
template.AddImage(image);
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
}
You can now edit the PDF with image in newer Adobe Readers.
Unfortunately, though, there is an error upon saving the document. I don't know whether they have to do with the fact that the source document is partially invalid (Adobe Preflight complains about a number of issues, foremost the use of an undefined encoding name Win1251Encoding) or whether something else gets broken.
Removing the usage rights signature in append mode
Working in append mode we have to manually remove the usage rights signature. Actually, we'll remove the whole Perms dictionary from the Catalog:
using (Stream output = new FileStream(outpath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
using (PdfReader reader = new PdfReader(inpath))
using (var stamper = new PdfStamper(reader, output, '\0', true))
{
reader.Catalog.Remove(PdfName.PERMS);
stamper.MarkUsed(reader.Catalog);
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
image.SetAbsolutePosition(0, 0);
PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
template.AddImage(image);
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
}
Now you can edit the form and save the file (at least I can in Adobe Reader DC).
PS: The correct coordinates
In a comment the OP shared another PDF and stated that it
for the other file is impossible to place a picture on a page with landscape orientation.
There indeed is an issue in the OP's code:
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
The fixed coordinates 150, 200 are a sign that the OP assumes the lower left page corner to be the origin 0, 0 of the coordinate system. While this often is the case, this is not necessarily true. One always has to take the CropBox (which defaults to the MediaBox) into account, i.e. for the OP's code:
Rectangle cropBox = reader.GetCropBox(1);
stamper.GetOverContent(1).AddTemplate(template, cropBox.Left + 150, cropBox.Bottom + 200, true);
the library takes rotation not correctly, but gives 0 degrees.
But that is correct! Your sample PDF is somewhat special as it uses an unrotated rectangle for landscape and a rotated rectangle for portrait.

Opening generated PDF in a browser using iText

I am using PDFStamper to generate a PDF file and then I want to pass it to be opened in a Browser. My code is in a JSP file. My code to actually generate a PDF to Desktop works but not to route to a browser. Below is my code.
PdfReader reader = new PdfReader("/path/pdfs/raw.pdf");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, baos);
PdfContentByte canvas = stamper.getOverContent(1);
BaseFont font = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED);
canvas.setFontAndSize(font, 12);
canvas.beginText();
canvas.showTextAligned(Element.ALIGN_LEFT, "TEST! TEST! TEST! TEST! ", 80, 713, 0);
canvas.endText();
stamper.close();
reader.close();
String filename="test.pdf";
response.setContentType("application/pdf");
response.setHeader( "Content-Disposition", "filename=" + filename );
response.setContentType("application/pdf");
OutputStream os = response.getOutputStream();
baos.writeTo(os);
os.flush();
This currently opens a blank page - I am not sure what exactly I am doing wrong.
I can make this work using iText Document but since I am opening an existing document and adding stuff to it I have to use PDFStamper and that is where the issue comes. I've confirmed the PDF file in reader exists and can be accessed via a browser by directly going to the location.
Any help would be appreciated!
Using, Struts2, Tile2, Weblogic, Java, iText

Losing javascript which is added into pdf using itext

I am trying to add javascript into a pdf using itext and later merge it with another pdf.
But the final merged pdf does not contain the javascript. The javascript is working fine if the pdf is not merged with another pdf.
Merging code :
FileOutputStream sectionR = new FileOutputStream(RESULT);
PdfCopyFields copier = new PdfCopyFields(sectionR);
for (String curInPath : listFile) {
PdfReader reader = new PdfReader(curInPath);
copier.addDocument(reader);
}
copier.close();
I tried to add JS to the resulting merged pdf, but it is not taking it. I guess its not editable.
Below is the code adding JS to pdf which is not merged yet.
FileOutputStream section1Pdf = new FileOutputStream("newPDFSection");
PdfReader readerSection1 = new PdfReader("Existing PDF - Section 1");
PdfStamper stamperSection1 = new PdfStamper(readerSection1,section1Pdf);
stamperSection1.addJavaScript(
"var nameField = this.getField('txtOwnerCity');" + "nameField.setAction('Keystroke'," +"'forceUpperCase()');" +
"" +"function forceUpperCase(){" +
"if(!event.willCommit)event.change = " +
"event.change.toUpperCase();" +
"}");
When I tried adding JS to the resulting merged pdf, it does not allow me saying it is not editable anymore.
This is how I am trying to add
FileOutputStream sectionR = new FileOutputStream(RESULT);
PdfCopyFields copier = new PdfCopyFields(sectionR);
for (String curInPath : listFile) {
PdfReader reader = new PdfReader(curInPath);
copier.addDocument(reader);
}
copier.close();
PdfReader readersectionResult = new PdfReader("result.pdf");
PdfStamper stamper = new PdfStamper(readersectionResult, new FileOutputStream("newResult.pdf"));
stamper.addJavaScript(some JS);
The error I am getting is ' WARNING: Cannot set header. Response already committed.'
I am not sure if I am doing it right above, All I am trying to do is get pdfstamper of resulting pdf to add new JS to it.
When I am trying to edit form filed values, it says not editable anymore.
AcroFields acro= stamper .getAcroFields();
acro.setField("txtOfficerName"+officerChar,officerSO.getFullName());

Using ContentByteUtils for raw PDF manipulation

This is a follow up question to:
Programmatically change the color of a black box in a PDF file?
I have a pdf I created in Illustrator that has basically a black shape in the middle of the page and nothing else. I need to change the color of that shape dynamically.
From the response to the post above I am using iTextSharp (.NET C#) to get the raw contents of the PDF through ContentByteUtils.GetContentBytesForPage() and changing the color at the raw level.
Problem is that I can't find any way of saving the results back into either the original PDF or a new PDF file via iTextSharp. I'm currently stuck with a byte array of the raw contents but need to figure out how to save.
Help please!
Why are you using ContentByteUtils.GetContentBytesForPage()?
I would use:
PdfReader reader = new PdfReader(src);
byte[] content = reader.GetPageContent(pageNumber);
// do stuff with content
reader.SetPageContent(pageNumber, content);
using (FileStream fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (PdfStamper stamper = new PdfStamper(reader, fs)) {
}
}

Dynamically Fill your PDF Forms using silverlight

string pdfTemplate = #"Trust App form.pdf";
string newFile = #"Trust App form Completed.pdf";
PdfReader pdfReader = new PdfReader(pdfTemplate);
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(
newFile, FileMode.Create));
AcroFields pdfFormFields = pdfStamper.AcroFields;
pdfFormFields.SetField("trust.trustee.entityname.line1", "Gulistan-e-Jauhar Karachi");
pdfStamper.FormFlattening = false;
pdfStamper.Close();
I am able to fill pdf forms using Itext sharp pdf.
But problem is this pdf is for .net. I WANT TO USE IT IN SILVERLIGHT.
Is there any alternative? for filling pdf form in silverlight... what i think itext sharp give silverpdf (http://silverpdf.codeplex.com/) but there is pdfstamper and acrofields classes in silverpdf.
SilverPDF looks to be inspired/based-on iTextSharp and PDFSharp, but it doesn't use an identical class layout by any means.
I just poked around in their code a bit (they have no docs that I could find), and it looks like you need to get the field's PdfAcroField object from the PdfAcroForm, which you get from a PdfDocument, which in turn you get from PdfReader.open(...).
When the docs aren't good enough, check the code if at all possible.