Import annotations (XFDF) to PDF - aspose.pdf

I have created a sample program to try to import XFDF to PDF using the Aspose library. The program can be run without exception, but the output PDF does not include any annotations. Any suggestions to solve this problem?
Update - 2014-12-12
I have also sent the issue to Aspose. They can reproduce the same problem and logged a ticket PDFNEWJAVA-34609 in their issue tracking system.
Following is my sample program:
public static void main(String[] args) {
final String ROOT = "C:\\PdfAnnotation\\";
final String sourcePDF = "hackermonthly-issue.pdf";
final String destPDF = "output.pdf";
final String sourceXFDF = "XFDFTest.xfdf";
try
{
// Specify the path of license file
License lic = new License();
lic.setLicense(ROOT + "Aspose.Pdf.lic");
//create an object of PdfAnnotationEditor class
PdfAnnotationEditor editor = new PdfAnnotationEditor();
//bind input PDF file
editor.bindPdf(ROOT + sourcePDF);
//create a file stream for input XFDF file to import annotations
FileInputStream fileStream = new FileInputStream(ROOT + sourceXFDF);
//create an enumeration of all the annotation types which you want to import
//int[] annType = {AnnotationType.Ink };
//import annotations of specified type(s) from XFDF file
//editor.importAnnotationFromXfdf(fileStream, annType);
editor.importAnnotationFromXfdf(fileStream);
//save output pdf file
editor.save(ROOT + destPDF);
} catch (Exception e) {
System.out.println("exception: " + e.getMessage());
}
}

Related

JSF PDF not downloadable while returned from Servlet [duplicate]

This question already has an answer here:
Internet Explorer 9 does not use file name for inline attachments
(1 answer)
Closed 3 years ago.
I have a form that once completed opens a new tab and calls my bean method annonceReturn().
This method sends back a pdf file. The problem is that as I open a new tab with _blank, the URL ends with .xhtml. Even the filename is displayed as being in my exemple "list.xhtml" (the last part of the URL). The problem is that I can't download this file because it's not considerated as a pdf file.
This is my xhtml file :
<h:form id="form">
<p:commandButton id="envoiRetour" onclick="this.form.target = '_blank';"
actionListener="#{returnCtrl.announceReturn()}"
value="Open PDF in new tab"
ajax="false" />
</h:form>
This is the returnCtrl.annonceReturn() method :
public void announceReturn() throws MalformedURLException, FileNotFoundException, DocumentException, BadElementException, IOException, InterruptedException {
String referenceAnnouncement = "C:/Users/path_to_my_pdf_file.pdf";
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
input = new BufferedInputStream(new FileInputStream(referenceAnnouncement), 10240);
response.reset();
response.setHeader("Content-type", "application/pdf");
response.setContentLength((int)new File(referenceAnnouncement).length());
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Content-disposition", "inline; filename=" + "file.pdf");
response.setHeader("pragma", "public");
output = new BufferedOutputStream(response.getOutputStream(), 10240);
byte[] buffer = new byte[10240];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
output.flush();
} finally {
output.close();
input.close();
}
}
How can I do to open this PDF in a new tab and be able to download it ?
When I try to download it, it says there is a network error (and it tries to save it as xhtml file).
EDIT : this is the question that helped me : How to open a PDF file in a new tab
EDIT 2 : the problem is not that the PDF doesn't show. The problem is that it shows in the new tab but when I try to download it, the explorer wants to save it as an XHTML file.
EDIT 3 : as mentionned here -> Open PDF in new tab, saving file gives wrong file name
it seems the filename is ignored if the disposition is not "attachment"... So I think I need to think about another way to do it.
Thanks for your time.
Try 'attachment' instead of 'inline' to force the browser saving the file (instead of trying to open with the associated plugin - if installed)
response.setHeader("Content-disposition", "attachment; filename=" + "file.pdf");
Hope it helps.
Beppe
Here is my code, hope it helps.
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
File temp = File("./path/abc.pdf");
temp.deleteOnExit();
ec.responseReset();
ec.setResponseContentType("application/pdf");
ec.setResponseContentLength((int)temp.length());
ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + temp.getName() + "\""); //inline;
OutputStream output = ec.getResponseOutputStream();
Files.copy(temp.toPath(), output);
fc.responseComplete();
I have tested in my project, here is the solution:
1 - Create button
<h:commandButton
onclick="this.form.target='_blank'"
id="cmdOpenPDF"
action="#{bean.openPDF(bean.code)}"
value="New PDF">
</h:commandButton>
2 - The bean has a function with a redirect link to PDF. This sample the pdf in the root folder.
public void openPDF(String code) throws Exception {
String filePdfName ="";
try {
//Make sure that this file in root
File pdf = new File("sample.pdf");
filePdfName = pdf.getName();
} catch (Exception ex) {
ex.printStackTrace();
}
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.redirect(ec.getRequestContextPath() + "/" + filePdfName);
}

iText - Encrypt Embedded Files Only

I want to create an unencrypted pdf file with an encrypted embedded file with iText as described in Section 7.6.1 of PDF 32000-1:2008:
Beginning with PDF 1.5, embedded files can be encrypted in an
otherwise unencrypted document
The following example (iText 7.0.1), however, produces a PDF file with an unencrypted embedded file stream (compression switched off to better analyze the resulting PDF file):
/* cf. 7.6.3.1: Documents in which only file attachments are
encrypted shall use the same password as the user and owner password.*/
PdfWriter writer = new PdfWriter(fileName, new WriterProperties()
.setStandardEncryption("secret".getBytes(),
"secret".getBytes(), EncryptionConstants.ALLOW_PRINTING |
EncryptionConstants.ALLOW_MODIFY_ANNOTATIONS,
EncryptionConstants.ENCRYPTION_AES_128 |
EncryptionConstants.DO_NOT_ENCRYPT_METADATA |
EncryptionConstants.EMBEDDED_FILES_ONLY)
.setCompressionLevel(CompressionConstants.NO_COMPRESSION));
PdfDocument pdf = new PdfDocument(writer);
PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(pdf,"attached file".getBytes(),
null,"attachment.txt",null,null,null,true);
pdf.addFileAttachment("attachment.txt", fs);
try (Document doc = new Document(pdf)) {
doc.add(new Paragraph("main file"));
}
This result appears to be in contrast to the spec stating:
if the contents of the stream are embedded within the PDF file (see
7.11.4, "Embedded File Streams"), they shall be encrypted like any other stream in the file
The pdf file produced by the above example contains the correct entry for the encrypted embedded file stream in the CF dictionary:
<</CF<</StdCF<</AuthEvent/EFOpen/CFM/AESV2/Length 16>>>>/EFF/StdCF
Table 20 of the spec states:
Conforming writers shall respect this value when encrypting embedded
files, except for embedded file streams that have their own crypt
filter specifier.
The stream in our case has no own CF specifier and hence should be encrytped using AESV2. In our example, however, the stream is not encrypted:
4 0 obj
<</Length 13/Params<</ModDate(D:20160930101501+02'00')/Size 13>>/Subtype /application#2foctet-stream/Type/EmbeddedFile>>stream
attached file
endstream
endobj
This leads to the following questions:
Is this a bug in iText or did I misinterpret the PDF spec?
How can I create unencrypted pdf files with encrypted embedded files
with iText?
If this is not (yet) possible, is there any other free library or command
line tool to do this?
PS: Acrobat Reader DC and PDF-XChange Viewer 2.5 ask for a password to open the attachment, whereas (non-conforming) readers like evince open the attachment without any questions. But this is not my question here. My question is not about reader behavior and possibly ethics, but about the pdf file itself and its compliance with the spec.
Update 2021:
Release 7.1.16 finally implemented encryption of embedded files in otherwise not encrypted pdf documents.
(the API changed slightly: in the test for iText 7 below, remove the last parameter of createEmbeddedFileSpec so that it reads PdfFileSpec.createEmbeddedFileSpec(pdf,"attached file".getBytes(),null,"attachment.txt",null,null,null);)
Original answer
As I didn't get any answers I made some more tests with iText 5.5.9 and iText 7.0.1 and came to the conclusion that not to encrypt embedded file streams with EMBEDDED_FILES_ONLY is a bug in the new version of iText 7. It only worked with iText 5 and ENCRYPTION_AES_256, although Acrobat reader gave a warning that an error existed on this page and it might not display the page correctly. For details see the following table:
Following is the code of the minimal, complete, and verifiable examples to produce the pdf files used in the above table with iText 5.5.9 ...
package pdfencryptef_itext5;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfFileSpecification;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class PDFEncryptEF_iText5 {
public static void main(String[] args) throws Exception {
new PDFEncryptEF_iText5().createPDF("iText5_STD128.pdf", PdfWriter.STANDARD_ENCRYPTION_128);
new PDFEncryptEF_iText5().createPDF("iText5_AES128.pdf", PdfWriter.ENCRYPTION_AES_128);
new PDFEncryptEF_iText5().createPDF("iText5_AES256.pdf", PdfWriter.ENCRYPTION_AES_256);
Security.addProvider(new BouncyCastleProvider());
new PDFEncryptEF_iText5().createPDF("iText5_AES128C.pdf", -PdfWriter.ENCRYPTION_AES_128);
new PDFEncryptEF_iText5().createPDF("iText5_AES256C.pdf", -PdfWriter.ENCRYPTION_AES_256);
}
public void createPDF(String fileName, int encryption ) throws FileNotFoundException, DocumentException, IOException, CertificateException {
Document document = new Document();
Document.compress = false;
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(fileName));
if( encryption >= 0 ){
writer.setEncryption("secret".getBytes(),"secret".getBytes(), 0,
encryption | PdfWriter.EMBEDDED_FILES_ONLY);
} else {
Certificate cert = getPublicCertificate("MyCert.cer" );
writer.setEncryption( new Certificate[] {cert}, new int[] {0}, -encryption | PdfWriter.EMBEDDED_FILES_ONLY);
}
writer.setPdfVersion(PdfWriter.VERSION_1_6);
document.open();
PdfFileSpecification fs = PdfFileSpecification.fileEmbedded(writer, null, "attachment.txt", "attached file".getBytes(), 0);
writer.addFileAttachment( fs );
document.add(new Paragraph("main file"));
document.close();
}
public Certificate getPublicCertificate(String path) throws IOException, CertificateException {
FileInputStream is = new FileInputStream(path);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
return cert;
}
}
... and iText 7.0.1:
package pdfencryptef_itext7;
import com.itextpdf.kernel.pdf.CompressionConstants;
import com.itextpdf.kernel.pdf.EncryptionConstants;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfVersion;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.WriterProperties;
import com.itextpdf.kernel.pdf.filespec.PdfFileSpec;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class PDFEncryptEF_iText7 {
public static void main(String[] args) throws Exception {
new PDFEncryptEF_iText7().createPDF("iText7_STD128.pdf", EncryptionConstants.STANDARD_ENCRYPTION_128);
new PDFEncryptEF_iText7().createPDF("iText7_AES128.pdf", EncryptionConstants.ENCRYPTION_AES_128);
new PDFEncryptEF_iText7().createPDF("iText7_AES256.pdf", EncryptionConstants.ENCRYPTION_AES_256);
Security.addProvider(new BouncyCastleProvider());
new PDFEncryptEF_iText7().createPDF("iText7_AES128C.pdf", -EncryptionConstants.ENCRYPTION_AES_128);
new PDFEncryptEF_iText7().createPDF("iText7_AES256C.pdf", -EncryptionConstants.ENCRYPTION_AES_256);
}
public void createPDF(String fileName, int encryption ) throws FileNotFoundException, IOException, CertificateException{
PdfWriter writer;
if( encryption >= 0 ){
writer = new PdfWriter(fileName, new WriterProperties().setStandardEncryption("secret".getBytes(),"secret".getBytes(),
0,
encryption | EncryptionConstants.EMBEDDED_FILES_ONLY)
.setPdfVersion(PdfVersion.PDF_1_6));
} else {
Certificate cert = getPublicCertificate("MyCert.cer" );
writer = new PdfWriter(fileName, new WriterProperties().setPublicKeyEncryption( new Certificate[] {cert},
new int[] {0},
-encryption | EncryptionConstants.EMBEDDED_FILES_ONLY )
.setPdfVersion(PdfVersion.PDF_1_6));
}
writer.setCompressionLevel(CompressionConstants.NO_COMPRESSION);
PdfDocument pdf = new PdfDocument(writer);
PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(pdf,"attached file".getBytes(),null,"attachment.txt",null,null,null,true);
pdf.addFileAttachment("attachment.txt", fs);
try (Document doc = new Document(pdf)) {
doc.add(new Paragraph("main file"));
}
}
public Certificate getPublicCertificate(String path) throws IOException, CertificateException {
FileInputStream is = new FileInputStream(path);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
return cert;
}
}
I must admit that I'm a bit disappointed that there was no feedback from the iText people to at least the first of my three questions but, hopefully, future versions of iText 7 will correctly process the EMBEDDED_FILES_ONLY flag. As the tests showed, it seems to be far from trivial for both the pdf producer as well as the reader to correctly handle this feature.

Text Extraction, Not Image Extraction

Please help me understand if my solution is correct.
I'm trying to extract text from a PDF file with a LocationTextExtractionStrategy parser. I'm getting exceptions because the ParseContentMethod tries to parse inline images? The code is simple and looks similar to this:
RenderFilter[] filter = { new RegionTextRenderFilter(cropBox) };
ITextExtractionStrategy strategy = new FilteredTextRenderListener(new LocationTextExtractionStrategy(), filter);
PdfTextExtractor.GetTextFromPage(pdfReader, pageNumber, strategy);
I realize the images are in the content stream but I have a PDF file failing to extract text because of inline images. It returns an UnsupportedPdfException of "The filter /DCTDECODE is not supported" and then it finally fails with and InlineImageParseException of "Could not find image data or EI", when all I really care about is the text. The BI/EI exists in my file so I assume this failure is because of the /DCTDECODE exception. But again, I don't care about images, I'm looking for text.
My current solution for this is to add a filterHandler in the InlineImageUtils class that assigns the Filter_DoNothing() filter to the DCTDECODE filterHandler dictionary. This way I don't get exceptions when I have InlineImages with DCTDECODE. Like this:
private static bool InlineImageStreamBytesAreComplete(byte[] samples, PdfDictionary imageDictionary) {
try {
IDictionary<PdfName, FilterHandlers.IFilterHandler> handlers = new Dictionary<PdfName, FilterHandlers.IFilterHandler>(FilterHandlers.GetDefaultFilterHandlers());
handlers[PdfName.DCTDECODE] = new Filter_DoNothing();
PdfReader.DecodeBytes(samples, imageDictionary, handlers);
return true;
} catch (IOException e) {
return false;
}
}
public class Filter_DoNothing : FilterHandlers.IFilterHandler
{
public byte[] Decode(byte[] b, PdfName filterName, PdfObject decodeParams, PdfDictionary streamDictionary)
{
return b;
}
}
My problem with this "fix" is that I had to change the iTextSharp library. I'd rather not do that so I can try to stay compatible with future versions.
Here's the PDF in question:
https://app.box.com/s/7eaewzu4mnby9ogpl2frzjswgqxn9rz5

<p:media display pdf from folder dynamically

I have several pdf files saved in ...WebContent/Manuals/filename.pdf that I am trying to display on my page. I am getting "Failed to Load PDF document" message in Chrome.
My Jsf:
<p:media value="#{reviewBean.manual}" player="pdf" height="600px" width="1000px" />
My #SessionScoped Bean:
public StreamedContent getManual() throws IOException {
String type = "application/pdf";
String path = "";
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
return new DefaultStreamedContent();
} else {
path = "C:\\.....\\WebContent\\Manuals\\filename.pdf";
InputStream is = new ByteArrayInputStream(path.getBytes());
return new DefaultStreamedContent(is, type);
}
}
There is additional logic that i have left out for clarity which decides which pdf is displayed.
I have also tried the file path of /Manuals/filename.pdf as path
I tried following the below example:
How to bind dynamic content using <p:media>?
In my case I do not need to retrieve a value using <f:param
Is my file path incorrect to display the image? Or am I building the Stream incorrectly? Any guidance is much appreciated.
I solved this by merely returning the url as a String.
public String getManual() {
return user.getManuals().get(user.getLData().getDepart());
}
Where the returned value is the file path of the pdf: Manuals/filename.pdf

Docx4j Test - No File is Output

Attempting to write my first class with docx4j (http://www.docx4java.org). Basically the idea is to find a string of text in the .docx file and replace it with another string of text. Essentially a mail merge. While I'm not receiving any errors, the merged document itself is not being saved in the path I've suggested. This makes me think it's a file path problem but I don't see anything wrong with it.
package efi.mailmerge.servlets;
import java.util.List;
import javax.xml.bind.JAXBElement;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.wml.Text;
public class WordDocTest {
/**
* Open word document /Users/Jeff/Development/ReServe-Unleashed/Dev/MailMerge/uploads/Sample.docx, replace a piece of text and save
* the result to /Users/Jeff/Development/ReServe-Unleashed/Dev/MailMerge/uploads/Sample-Out.docx.
*
* The text <<CUS_FNAME>> will be replaced with John.
*
* #param args
*/
public static void main(String[] args) {
// Text nodes begin with w:t in the word document
final String XPATH_TO_SELECT_TEXT_NODES = "//w:t";
try {
// Open the input file
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File("/Users/Jeff/Development/ReServe-Unleashed/Dev/MailMerge/uploads/Sample.docx"));
// Build a list of "text" elements
List texts = wordMLPackage.getMainDocumentPart().getJAXBNodesViaXPath(XPATH_TO_SELECT_TEXT_NODES, true);
// Loop through all "text" elements
for (Object obj : texts) {
Text text = (Text) ((JAXBElement) obj).getValue();
// Get the text value
String textValueBefore = text.getValue();
// Perform the replacement
String textValueAfter = textValueBefore.replaceAll("<<CUS_FNAME>>", "John");
// Show the element before and after the replacement
System.out.println("textValueBefore = " + textValueBefore);
System.out.println("textValueAfter = " + textValueAfter);
// Update the text element now that we have performed the replacement
text.setValue(textValueAfter);
}
wordMLPackage.save(new java.io.File("/Users/Jeff/Development/ReServe-Unleashed/Dev/MailMerge/uploads/Sample-Out.docx"));
} catch (Docx4JException e) {
Logger.getLogger(WordDocTest.class.getName()).log(Level.SEVERE, null, e);
e.printStackTrace();
} catch (Exception e) {
Logger.getLogger(WordDocTest.class.getName()).log(Level.SEVERE, null, e);
e.printStackTrace();
}
}
}
On lines 26 and 50 you can see the input/output paths. I've confirmed that the Sample.docx input file does exist and that the uploads directory has write permissions. Can you see anything wrong with my file paths here? I could be completely on the wrong path, but this is all very new to me so I'm learning as I go.
Any and all help is very much appreciated.
At first sight, I would suggest trying with your path written the following way :
wordMLPackage.save(new java.io.File("\\Users\\Jeff\\Development\\ReServe-Unleashed\\Dev\\MailMerge\\uploads\\Sample-Out.docx"));
If it still not works, please provide the stack traces ? It could help. (if no doc is saved, there must be an exception thrown)