how to download mulitple .PDF files in java - java

OnClick of button on JSP Page, I am trying to download more than one pdf one by one using java code but not able to done it and Using Following snippet code for the same
Document document[]= new Document[20];
httpServletResponse.setHeader("Content-Disposition",
"attachment;filename=welcome.pdf");
httpServletResponse.setContentType("application/pdf");
try{
for(int i=0;i<3;i++)
{
System.out.println(i);
document[i]=new Document();
PdfWriter.getInstance(document[i], httpServletResponse.getOutputStream());
document[i].open();
document[i].add(new Paragraph("Hello Prakash"));
document[i].add(new Paragraph(new Date().toString()));
document[i].close();
}
}catch(Exception e){
e.printStackTrace();
}
It is not working and alaways only one .PDF file is downloading, anyone help me out?

One could prepare a page, that does multiple requests to the server, every one which of downloads a PDF. This is not so nice a user experience.
I would use a zip file containing all PDFs:
response.setContentType("application/zip"); // application/octet-stream
response.setHeader("Content-Disposition", "inline; filename=\"all.zip\"");
try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
for (int i = 0; i < 3; i++) {
ZipEntry ze = new ZipEntry("document-" + i + ".pdf");
zos.putNextEntry(ze);
// It would be nice to write the PDF immediately to zos.
// However then you must take care to not close the PDF (and zos),
// but just flush (= write all buffered).
//PdfWriter pw = PdfWriter.getInstance(document[i], zos);
//...
//pw.flush(); // Not closing pw/zos
// Or write the PDF to memory:
ByteArrayOutputStream baos = new ...
PdfWriter pw = PdfWriter.getInstance(document[i], baos);
...
pw.close();
byte[] bytes = baos.toByteArray();
zos.write(baos, 0, baos.length);
zos.closeEntry();
}
}
Just read, you cannot use ZIP download.
Maybe you might use HTML5 offering a nicer download experience (progress bars?).

Related

Edit iText PDF Java

I've been trying to load a PDF file located at "/resources/pdf/". I want to load the pdf, fill the form fields and return a stream. This is working so far, there are no errors or exceptions.
The problem is that when the resulting PDF is printed parts of the document is missing. Using this pdf, it is just printing the form fields, but not the images or the text. The code is running in a tomcat7 in combination with primefaces:
public StreamedContent modify() {
String pdfFile = "mypdf.pdf";
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
InputStream istream = getClass().getResourceAsStream("/pdf/" + pdfFile);
PdfReader reader = new PdfReader(istream);
pdfStamper = new PdfStamper(reader, bos );
pdfForm = pdfStamper.getAcroFields();
// fillData();
pdfStamper.close();
reader.close();
istream.close();
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
bis.close();
bos.close();
return new DefaultStreamedContent( bis, "application/pdf", "report.pdf" );
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
I do build project this way: mvn clean install tomcat7:redeploy -DskipTests
Any idea what is wrong? Thanks.
I have finally decided to do it in another way.
In the project properties file I have added a new property with the path where the PDF is located, in this way I can load the pdfReader object with File through the new FileInputStream
Final code
public StreamedContent modify() {
File file = getPdfFile();
PdfReader reader = new PdfReader(new FileInputStream(file));
pdfStamper = new PdfStamper(reader, bos );
// fillData();
pdfStamper.close();
bos.close();
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
return new DefaultStreamedContent( bis, "application/pdf", "report.pdf" );
}
public File getPdfFile() {
try {
Properties prop = new Properties();
prop.load(getClass().getClassLoader()
.getResourceAsStream("myfile.properties"));
String pdfPath = prop.getProperty("pdf.path");
String pdfName = prop.getProperty("pdf.name");
File file = new File(pdfPath + pdfName);
return file;
} catch (Exception ex) {
LOGGER.error("ERROR: " + ex.getMessage());
return null;
}
}
Thank you very much!
Regards,
Update:
I just experienced the same problem! After intensive research I detected that maven broke the encoding of my PDF files. I should have more carefully read MKLs comment ;-)
I added the resource plugin to my maven project:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<nonFilteredFileExtensions>
<!-- Please note that images like jpg, jpeg, gif, bmp and png are (already) implicitly excluded -->
<nonFilteredFileExtension>pdf</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
Old post:
Your post lacks vital information:
How do you print your report.pdf? From the webbrowser or Adobe Reader? Please post the report.pdf so we can analyze.
What I understand is, that the code you posted works fine (no error, no exception). The problem occurs only at printing?
One shot what might be wrong:
You do not set the encoding (e.g. UTF-8) for your stream:
return new DefaultStreamedContent( bis, "application/pdf", "report.pdf", "YourEncoding");
and by the way the original PDF is buggy, too (E.g. Preflight reports serveral errors.)

Using iText 2.1.7 to merge large PDFs

I am using an older version of iText (2.1.7) to merge PDFs. Because that is the last version under the MPL available to me. I cannot change this.
Anyways. I am trying to merge multiple PDFs. Everything seems to work ok, but when I go over about 1500 pages, then the generated PDF fails to open (behaves as if it is corrupted)
This is how I am doing it:
private byte[] mergePDFs(List<byte[]> pdfBytesList) throws DocumentException, IOException {
Document document = new Document();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfCopy copy = new PdfCopy(document, outputStream);
document.open();
for (byte[] pdfByteArray : pdfBytesList) {
ByteArrayInputStream readerStream = new ByteArrayInputStream(pdfByteArray);
PdfReader reader = new PdfReader(readerStream);
for (int i = 0; i < reader.getNumberOfPages(); ) {
copy.addPage(copy.getImportedPage(reader, ++i));
}
copy.freeReader(reader);
reader.close();
}
document.close();
return outputStream.toByteArray();
}
Is this the correct approach? Is there anything about this that would hint at breaking when going over a certain amount of pages? There are no exceptions thrown or anything.
For anyone curious, the issue had nothing to do with iText and instead was the code responsible for returning the response from iText.

Vaadin Convert and display image as PDF

Does anyone know how image file can be easily converted into PDF format. What I need is to get the image from database and display it on the screen as PDF. What am I doing wrong? I tried to use iText but with no results.
My code:
StreamResource resource = file.downloadFromDatabase();//get file from db
Document converToPdf=new Document();//Create Document Object
PdfWriter.getInstance(convertToPdf, new FileOutputStream(""));//Create PdfWriter for Document to hold physical file
convertToPdf.open();
Image convertJpg=Image.getInstance(resource); //Get the input image to Convert to PDF
convertToPdf.add(convertJpg);//Add image to Document
Embedded pdf = new Embedded("", convertToPdf);//display document
pdf.setMimeType("application/pdf");
pdf.setType(Embedded.TYPE_BROWSER);
pdf.setSizeFull();
Thanks.
You're not using iText correctly:
You never close your writer, so the addition of the image never gets written to the outputstream.
You pass an empty string to your FileOutputStream. If you want to keep the pdf in memory, use a ByteArrayOutputStream. If not, define a temporary name instead.
You pass your Document object, which is a iText-specific object to your Embedded object and treat it like a file. It is not a pdf-file or byte[]. You'll probably want to pass either your ByteArrayOutputStream or read the temp file as a ByteArrayOutputStream into memory and pass that to Embedded.
Maybe someone will use (Vaadin + iText)
Button but = new Button("FV");
StreamResource myResource = getPDFStream();
FileDownloader fileDownloader = new FileDownloader(myResource);
fileDownloader.extend(but);
hboxBottom.addComponent( but );
private StreamResource getPDFStream() {
StreamResource.StreamSource source = new StreamResource.StreamSource() {
public InputStream getStream() {
// step 1
com.itextpdf.text.Document document = new com.itextpdf.text.Document();
// step 2
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
com.itextpdf.text.pdf.PdfWriter.getInstance(document, baos);
// step 3
document.open();
document.add(Chunk.NEWLINE); //Something like in HTML :-)
document.add(new Paragraph("TEST" ));
document.add(Chunk.NEWLINE); //Something like in HTML :-)
document.newPage(); //Opened new page
//document.add(list); //In the new page we are going to add list
document.close();
//file.close();
System.out.println("Pdf created successfully..");
} catch (DocumentException ex) {
Logger.getLogger(WndOrderZwd.class.getName()).log(Level.SEVERE, null, ex);
}
ByteArrayOutputStream stream = baos;
InputStream input = new ByteArrayInputStream(stream.toByteArray());
return input;
}
};
StreamResource resource = new StreamResource ( source, "test.pdf" );
return resource;
}

download file from internet returns error 400 on Java, on browser works ok

I need to download a file using java from this webpage
http://www.okaa.gr/files/1/%CE%9F%CE%9A%CE%91%CE%91/%CE%A4%CE%99%CE%9C%CE%95%CE%A3 %CE%A7%CE%9F%CE%9D%CE%94%CE%A1%CE%99%CE%9A%CE%97%CE%A3/20150409-pasxa.pdf
the text there is in greek letters.
If you use this url on a browser, it works ok, and it opens up a pdf file. using it in Java, i get a 400 error.
I have used a bunch of different methods that supposingly do what i want, but they all get the same error.
This does work for a different site and a different file
String okaa="http://www.okaa.gr/";
String link="gr/nea-kai-anakoinoseis/statistika-deltia-timon/?date=09&month=4&year=2015&catname=0";
URL okaaLink = new URL(okaa+link);
BufferedReader in = new BufferedReader(
new InputStreamReader(okaaLink.openStream()));
ArrayList<String> links =new ArrayList<String>();
String inputLine;
while ((inputLine = in.readLine()) != null)
{
if(inputLine.contains(".pdf"))
{
String newLink=inputLine.substring(inputLine.indexOf("href")+6,inputLine.indexOf("download")-2);
links.add(okaa+newLink);
}
}
in.close();
ArrayList<String> links =new ArrayList<String>();
links.add(url); //the url in question
for (int i=0;i<links.size();i++)
{
// download and save the file
URL website = new URL(links.get(i));//the url link
ReadableByteChannel rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(i+".pdf");
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
}
Any help?
Edit:
Updated code. I first read from the main page the list of the links, strip the html parts (the substring command) and pass it to the ArrayList.
Then using the urls on the array list i want to download the files
But this doesnt work even if i copy the url fromthe browser and paste it directly in the command URL website = new URL("....");
Solved:
Thanks #Yannick, all i had to do was remove the spaces using newLink=newLink.replaceAll("\\s","");
I would NEVER figured it out!
Maybe the problem is that the link contains a space at
...%A3 %CE...
Your browser automatically replaces " " with "", because links with a space are not valid.
The solution of newuserua_ext doesn't contain this space and that could be the reason that it works.
That's what i tried and downloaded pdf file ;
ArrayList<String> links = new ArrayList<String>();
links.add("http://www.okaa.gr/files/1/%CE%9F%CE%9A%CE%91%CE%91/%CE%A4%CE%99%CE%9C%CE%95%CE%A3%20%CE%A7%CE%9F%CE%9D%CE%94%CE%A1%CE%99%CE%9A%CE%97%CE%A3/20150409-pasxa.pdf");
for (int i = 0; i < links.size(); i++) {
System.out.println("opening connection");
URL url = new URL(links.get(i));
InputStream in = url.openStream();
FileOutputStream fos = new FileOutputStream(new File(i + ".pdf"));
System.out.println("reading file...");
int length = -1;
byte[] buffer = new byte[1024];// buffer for portion of data from
// connection
while ((length = in.read(buffer)) > -1) {
fos.write(buffer, 0, length);
}
fos.close();
in.close();
System.out.println("file was downloaded");
}
Output;

OutOfMemoryError during the pdf merge

the below code merges the pdf files and returns the combined pdf data. while this code runs, i try to combine the 100 files with each file approximately around 500kb, i get outofmemory error in the line document.close();. this code runs in the web environment, is the memory available to webspehere server is the problem? i read in an article to use freeReader method, but i cannot get how to use it my scenario.
protected ByteArrayOutputStream joinPDFs(List<InputStream> pdfStreams,
boolean paginate) {
Document document = new Document();
ByteArrayOutputStream mergedPdfStream = new ByteArrayOutputStream();
try {
//List<InputStream> pdfs = pdfStreams;
List<PdfReader> readers = new ArrayList<PdfReader>();
int totalPages = 0;
//Iterator<InputStream> iteratorPDFs = pdfs.iterator();
Iterator<InputStream> iteratorPDFs = pdfStreams.iterator();
// Create Readers for the pdfs.
while (iteratorPDFs.hasNext()) {
InputStream pdf = iteratorPDFs.next();
if (pdf == null)
continue;
PdfReader pdfReader = new PdfReader(pdf);
readers.add(pdfReader);
totalPages += pdfReader.getNumberOfPages();
}
//clear this
pdfStreams = null;
//WeakReference ref = new WeakReference(pdfs);
//ref.clear();
// Create a writer for the outputstream
PdfWriter writer = PdfWriter.getInstance(document, mergedPdfStream);
writer.setFullCompression();
document.open();
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA,
BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
PdfContentByte cb = writer.getDirectContent(); // Holds the PDF
// data
PdfImportedPage page;
int currentPageNumber = 0;
int pageOfCurrentReaderPDF = 0;
Iterator<PdfReader> iteratorPDFReader = readers.iterator();
// Loop through the PDF files and add to the output.
while (iteratorPDFReader.hasNext()) {
PdfReader pdfReader = iteratorPDFReader.next();
// Create a new page in the target for each source page.
while (pageOfCurrentReaderPDF < pdfReader.getNumberOfPages()) {
pageOfCurrentReaderPDF++;
document.setPageSize(pdfReader
.getPageSizeWithRotation(pageOfCurrentReaderPDF));
document.newPage();
// pageOfCurrentReaderPDF++;
currentPageNumber++;
page = writer.getImportedPage(pdfReader,
pageOfCurrentReaderPDF);
cb.addTemplate(page, 0, 0);
// Code for pagination.
if (paginate) {
cb.beginText();
cb.setFontAndSize(bf, 9);
cb.showTextAligned(PdfContentByte.ALIGN_CENTER, ""
+ currentPageNumber + " of " + totalPages, 520,
5, 0);
cb.endText();
}
}
pageOfCurrentReaderPDF = 0;
System.out.println("now the size is: "+pdfReader.getFileLength());
}
mergedPdfStream.flush();
document.close();
mergedPdfStream.close();
return mergedPdfStream;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document.isOpen())
document.close();
try {
if (mergedPdfStream != null)
mergedPdfStream.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
return mergedPdfStream;
}
Thanks
V
This code merges all the PDF's in an array in the memory (the heap) so yes, memory usage will grow linearly with the number of files merged.
I don't know about the freeReader method, but maybe you could try to write the merged PDF into a temporary file instead of a byte array ? mergedPdfStream would be a FileOutputStream instead of a ByteArrayOutputStream. Then you return e.g. a File reference to the client code.
Or you could increase the quantity of memory Java can use (-Xmx JVM parameter), but if the number of files to merge eventually increases, you will find yourself with the same problem.
First, why do you clutter your code with all those Iterator<> boilerplate code?
Do you ever heard of the for statement?
i.e
for (PDfReader pdfReader: readers) {
// code for each single PDF reader in readers
}
Second: consider to close the pdfReader as soon as it is done. This will hopefully flush some buffers and free the memory occupied by the original PDF.
This is not proper way of doing file operation. You are doing merging of files using ArrayList and Array in memory. You should rather use File IO with buffering techniques.
Do you wish to show the final merged file at last? Then you can open the file after all your merging is done.
Do not use only in-memory buffering as you have shown. Use File Io with buffering (byte[] i mean)
Close each file after you read it and append it.
Java has limited memory you allocated at startup time, so merging some big number of file at once like this will lead to crashing of application. You should try this merging operation in separate thread using ThreadPool, so that your application will not get stucked for this.
thanks.
100 files * 500 kB is something around 50 MB. If maximum heap size is 64 MB I'm pretty sure this code won't work in such conditions.

Categories

Resources