Opening generated PDF in a browser using iText - pdf

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

Related

Adobe Reader can't display unicode font of pdf added with iText

I'd like to stamp text to a certain pdf with iText. As this text can be cyrillic I use a unicode font and encoding.
The following sample code represents how I do it:
string inputFile = #"sampleStamped.pdf";
PdfReader reader;
PdfStamper stamper;
FileStream fs;
byte[] binaryPdf = File.ReadAllBytes(inputFile);
reader = new PdfReader(binaryPdf);
fs = new FileStream(inputFile, FileMode.Create, FileAccess.Write);
stamper = new PdfStamper(reader, fs);
BaseFont bf = BaseFont.CreateFont("c:/windows/fonts/arialuni.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
PdfContentByte cb = stamper.GetOverContent(1);
Phrase p = new Phrase();
p.Font = new Font(bf, 25, Font.NORMAL, BaseColor.BLUE);
p.Add("Sample Text");
ColumnText.ShowTextAligned(cb, PdfContentByte.ALIGN_LEFT, p, 200, 200, 0);
if (stamper != null)
stamper.Close();
if (fs != null)
fs.Close();
if (reader != null)
reader.Close();
The program works as expected and without errors. But if I want to open the stamped pdf in Acrobat Reader 11 or DC on Windows it says that there are proplems to display content and the stamped text is not there.
I use itextsharp 5.5.8.
Any idea how to fix this problem?
Thanks
This is not an issue of iText(Sharp) but a quirk (a feature?) of Adobe Reader.
Your sample file claims to be a PDF 1.2 file. Adobe Reader seems to behave differently when confronted with composite fonts in PDF 1.2 files.
You can check this by patching your sampleStamped.pdf, simply replace the first bytes %PDF-1.2 by %PDF-1.3 and open the file in Adobe Reader... no problem anymore.
Thus, you should make sure that your stamped PDF claims to be at least PDF 1.3. If you stamp your PDF 1.2 file, you can do so by creating the PdfStamper like this:
stamper = new PdfStamper(reader, fs, (char)3);
The result:

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.

PDF generated using PDFBox is magnified when printing / saving via Safari

I generated a pdf using PDFBox which is then sent to the front-end. When I print / save this pdf in Chrome / Firefox, it looks good. However, when I try to do the same using Safari, the pdf is magnified.
Not sure if this is a browser issue or whether it has something to do with Safari not able to read the pdf properly. Any ideas?
This is the pdf generated from Chrome, and this is the one from Safari (I've redacted few details).
This is my code:
PDXObjectImage blankImg = (PDXObjectImage) object;
if(blankImg.getHeight() > 460){
BufferedImage img = ImageIO.read(new ByteArrayInputStream(shippingLabel));
BufferedImage resizedImage = Scalr.resize(img, Scalr.Method.BALANCED, Scalr.Mode.FIT_EXACT, img.getWidth(), img.getHeight());
// Convert images to jpg format
BufferedImage jpegImage = new BufferedImage(resizedImage.getWidth(),resizedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
jpegImage.createGraphics().drawImage(resizedImage, 0, 0, Color.WHITE, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(jpegImage, "jpg", baos);
// Replace empty image in template with the image generated from shipping label byte array
PDXObjectImage carrierLabel = new PDJpeg(doc, new ByteArrayInputStream(baos.toByteArray()));
blankImg.getCOSStream().replaceWithStream(carrierLabel.getCOSStream());
break;
}
PDStream updatedStream = new PDStream(doc);
OutputStream out = updatedStream.createOutputStream();
ContentStreamWriter tokenWriter = new ContentStreamWriter(out);
tokenWriter.writeTokens(tokens);
page.setContents(updatedStream);
// Convert PDDoc to byte[]
ByteArrayOutputStream outUpdated = new ByteArrayOutputStream();
doc.save(outUpdated);
return outUpdated.toByteArray();
This is what I'm doing. I have a pdf with a blank image. I read this image, and replace this with another existing image which is available as byte array, and finally return the updated pdf as a byte array as ResponseEntity from Spring boot server running in the backend.
Thanks.

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

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.

How would you programmatically embed a SWF in a PDF?

Is it possible to programmatically embed a SWF in a PDF from a C# application?
You can use the c# port of the iText library. It's called iTextSharp.
http://itextsharp.com/
An example of what the code could look like:
// create an output file stream which will be used to capture the generated file
string outputFileName = "output.pdf";
FileStream outputFile = new FileStream(outputFileName, FileMode.Create);
// open the original pdf file as a PdfReader
PdfReader reader = new PdfReader("inputfile.pdf");
// open the output pdf file as a PdfStamper
PdfStamper stamper = new PdfStamper(reader, outputFile);
// inserts a blank page at the start of the document
stamper.InsertPage(1, PageSize.A4);
// add the flash file to the output document as an annotation
PdfFileSpecification fs = PdfFileSpecification.FileEmbedded(stamper.Writer, flashFileTextBox.Text, flashFileTextBox.Text, null);
PdfAnnotation flashInsert = PdfAnnotation.CreateScreen(stamper.Writer, new Rectangle(50f,791f,545f,420f),"Flash Insert",fs, "application/x-shockwave-flash", true);
stamper.AddAnnotation(flashInsert,1);
stamper.Close();
reader.Close();
Flash SWF files can be embedded into a PDF document programmatically. Have a look at the PDF library from webSupergoo. The documentation includes examples in C# and VB.NET.