How to write content into pdf? Google Cloud Storage Service - java

How can i create a pdf into gcs, and also insert some data?
This is my code:
GcsService gcsService = GcsServiceFactory.createGcsService(new RetryParams.Builder()
.initialRetryDelayMillis(10)
.retryMaxAttempts(10)
.totalRetryPeriodMillis(15000)
.build());
GcsFilename filename = new GcsFilename("areteaics", "test.pdf");
GcsFileOptions options = new GcsFileOptions.Builder().mimeType("application/pdf").build();
GcsOutputChannel writeChannel = gcsService.createOrReplace(filename,options);
PrintWriter out = new PrintWriter(Channels.newWriter(writeChannel, "UTF8"));
//out.println("The woods are lovely dark and deep.");
//out.println("But I have promises to keep.");
//out.flush();
writeChannel.waitForOutstandingWrites();
//writeChannel.write(ByteBuffer.wrap("And miles to go before I sleep.".getBytes()));
writeChannel.close();

It doesn't look like you are creating a pdf formatted file (you're just making a file with the extension pdf). You need to use a library like itext to create the pdf file and then write it to cloudstorage.
e.g using itext to write to outputstream src:
Document document = new Document();
PdfWriter.getInstance(document, response.getOutputStream());
document.open();
document.add(new Paragraph("This is a paragraph"));
document.close();
You'd need to modify the above code to write to gcs (instead of response outputstream).

Related

merge many pdf files into one pdf files in web application java

I have many pdf files and I have to merge all pdf into one big pdf file and render it into browser.I am using itext. Using this, I am able to merge pdf files into one file into disk but I cannot merge into browser and there is only last pdf in browser..following is my code.. please help me on this.
Thanks in advance.
Document document = new Document();
List<PdfReader> readers =
new ArrayList<PdfReader>();
int totalPages = 0;
ServletOutputStream servletOutPutStream = response.getOutputStream();;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();;
InputStream is=null;
List<InputStream> inputPdfList = new ArrayList<InputStream>();
System.err.println(imageMap.size());
for(byte[] imageList:imageMap)
{
System.out.println(imageList.toString()+" "+imageList.length);
byteArrayOutputStream.write(imageList);
byteArrayOutputStream.writeTo(response.getOutputStream());
is = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
inputPdfList.add(is);
}
response.setContentType("application/pdf");
response.setContentLength(byteArrayOutputStream.size());
System.out.println(inputPdfList.size()+""+inputPdfList.toString());
//Create pdf Iterator object using inputPdfList.
Iterator<InputStream> pdfIterator =
inputPdfList.iterator();
// Create reader list for the input pdf files.
while (pdfIterator.hasNext()) {
InputStream pdf = pdfIterator.next();
PdfReader pdfReader = new PdfReader(pdf);
readers.add(pdfReader);
totalPages = totalPages + pdfReader.getNumberOfPages();
}
// Create writer for the outputStream
PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());
//Open document.
document.open();
//Contain the pdf data.
PdfContentByte pageContentByte = writer.getDirectContent();
PdfImportedPage pdfImportedPage;
int currentPdfReaderPage = 1;
Iterator<PdfReader> iteratorPDFReader = readers.iterator();
// Iterate and process the reader list.
while (iteratorPDFReader.hasNext()) {
PdfReader pdfReader = iteratorPDFReader.next();
//Create page and add content.
while (currentPdfReaderPage <= pdfReader.getNumberOfPages()) {
document.newPage();
pdfImportedPage = writer.getImportedPage(
pdfReader,currentPdfReaderPage);
pageContentByte.addTemplate(pdfImportedPage, 0, 0);
currentPdfReaderPage++;
}
currentPdfReaderPage = 1;
}
//Close document and outputStream.
servletOutPutStream.flush();
outputStream.flush();
document.close();
outputStream.close();
servletOutPutStream.close();
System.out.println("Pdf files merged successfully.");
There are numerous errors in your code:
Only write to the response output stream what you want to return to the browser
Your code writes a wild collection of data to the response output stream:
ServletOutputStream servletOutPutStream = response.getOutputStream();;
[...]
for(byte[] imageList:imageMap)
{
[...]
byteArrayOutputStream.writeTo(response.getOutputStream());
[...]
}
[...]
PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());
[... merge PDFs into the writer]
servletOutPutStream.flush();
document.close();
servletOutPutStream.close();
This results in many copies of the imageMap elements to be written there and the merged file only to be added thereafter.
What do you expect the browser to do, ignore all the leading source PDF copies until finally the merged PDF appears?
Thus, please only write the merged PDF to the response output stream.
Don't write a wrong content length
It is a good idea to write the content length to the response... but only if you use the correct value!
In your code you write a content length:
response.setContentLength(byteArrayOutputStream.size());
but the byteArrayOutputStream at this time only contains a wild mix of copies of the source PDFs and not yet the final merged PDF. Thus, this will only serve to confuse the browser even more.
Thus, please do not add false headers to the response.
Don't mangle your input data
In the loop
for(byte[] imageList:imageMap)
{
System.out.println(imageList.toString()+" "+imageList.length);
byteArrayOutputStream.write(imageList);
byteArrayOutputStream.writeTo(response.getOutputStream());
is = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
inputPdfList.add(is);
}
you take byte arrays which I assume contain a single source PDF each, pollute the response output stream with them (as mentioned before), and create a collection of input streams where the first one contains the first source PDF, the second one contains the concatenation of the first two source PDFs, the third one the concatenation of the first three source PDFs, etc...
Because you never reset or re-instantiate the byteArrayOutputStream, it only gets bigger and bigger.
Thus, please start or end loops like this with a reset of the byteArrayOutputStream.
(Actually you don't need that loop at all, the PdfReader has a constructor which can immediately take a byte[], no need to wrap it in a byte stream.)
Don't merge PDFs using a plain PdfWriter, use a PdfCopy
You merge the PDFs using a PdfWriter / getImportedPage / addTemplate approach. There are dozens of questions and answer on stack overflow (many of them answered by iText developers) explaining that this usually is a bad idea and that you should use PdfCopy.
Thus, please make use of the many good answers which already exist on this topic here and use PdfCopy for merging.
Don't flush or close streams only because you can
You finalize the response output by closing numerous streams:
//Close document and outputStream.
servletOutPutStream.flush();
outputStream.flush();
document.close();
outputStream.close();
servletOutPutStream.close();
I have not seen a line in which you declared or set that outputStream variable, but even if it contained the response output stream, there is no need to close that because you already close it in the servletOutPutStream variable.
Thus, please remove unnecessary calls like this.
//Suppose we want to merge one pdf with another main pdf
InputStream is1 = null;
if (file1 != null) {
FileInputStream fis1 = new FileInputStream(file1);
byte[] file1Data = new byte[(int) file1.length()];
fis1.read(file1Data);
is1 = new java.io.ByteArrayInputStream(file1Data);
}
//
InputStream mainContent = <ur main content>
org.apache.pdfbox.pdmodel.PDDocument mergedPDF = new org.apache.pdfbox.pdmodel.PDDocument();
org.apache.pdfbox.pdmodel.PDDocument mainDoc = org.apache.pdfbox.pdmodel.PDDocument.load(mainContent);
org.apache.pdfbox.multipdf.PDFMergerUtility merger = new org.apache.pdfbox.multipdf.PDFMergerUtility();
merger.appendDocument(mergedPDF, mainDoc);
PDDocument doc1 = null;
if (is1 != null) {
doc1 = PDDocument.load(is1);
merger.appendDocument(mergedPDF, doc1);
//1st file appended to main pdf");
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mergedPDF.save(baos);
//Now either u save it here or convert into InputStream if u want
ByteArrayInputStream mergedInputStream = new ByteArrayInputStream(baos.toByteArray());

how to set attributes for existing pdf that contains only images using java itext?

I would like to set attributes to pdf before uploading it into a server.
Document document = new Document();
try
{
OutputStream file = new FileOutputStream({Localpath});
PdfWriter.getInstance(document, file);
document.open();
//Set attributes here
document.addTitle("TITLE");
document.close();
file.close();
} catch (Exception e)
{
e.printStackTrace();
}
But its not working. The file is getting corrupted
In a comment to another answer the OP clarified:
I want to set attributes to an existing pdf(not to create new pdf)
Obviously, though, his code creates a new document from scratch (as is obvious from the fact that a mere FileOutputStream is used to access the file, no reading, only writing).
To manipulate an existing PDF, one has to use a PdfReader / PdfWriter couple. Bruno Lowagie provided an example for that in his answer to the stack overflow question "iText setting Creation Date & Modified Date in sandbox.stamper.SuperImpose.java":
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
Map info = reader.getInfo();
info.put("Title", "New title");
info.put("CreationDate", new PdfDate().toString());
stamper.setMoreInfo(info);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XmpWriter xmp = new XmpWriter(baos, info);
xmp.close();
stamper.setXmpMetadata(baos.toByteArray());
stamper.close();
reader.close();
}
(ChangeMetadata.java)
As you see the code sets the metadata both in the ol'fashioned PDF info dictionary (stamper.setMoreInfo) and in the XMP metadata (stamper.setXmpMetadata).
Obviously src and dest should not be the same here.
Without a second file
In yet another comment the OP clarified that he had already tried a similar solution but that he wants to prevent the
Temporary existence of second file
This can easily be prevented by first reading the original PDF into a byte[] and then stamping to it as the target file. E.g. if File singleFile references the original file which is also to be the target file, you can implement:
byte[] original = Files.readAllBytes(singleFile.toPath());
PdfReader reader = new PdfReader(original);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(singleFile));
Map<String, String> info = reader.getInfo();
info.put("Title", "New title");
info.put("CreationDate", new PdfDate().toString());
stamper.setMoreInfo(info);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XmpWriter xmp = new XmpWriter(baos, info);
xmp.close();
stamper.setXmpMetadata(baos.toByteArray());
stamper.close();
reader.close();
(UpdateMetaData test testChangeTitleWithoutTempFile)

How to convert an html String to a PDF InputStream?

If we have string with a content of a html page, how can we convert it to a InputStream made after transform this string to a pdf document?
I'm trying to use iText with XMLWorkerHelper, and this following code works, but the problem is I don't want the output on a file. I have tried several variations in order to get the result on a InputStream that I could convert to a Primefaces StreamedContent but no success. How we can do it?
Is there another technique that we can use to solve this problem?
The motivation to this is use xhtml files wich is already rendered and output it as a pdf to be downloaded by the user.
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document,
new FileOutputStream("results/loremipsum.pdf"));
document.open();
XMLWorkerHelper.getInstance().parseXHtml(writer, document,
new FileInputStream("/html/loremipsum.html"));
document.close();
If you need an InputStream from which some other code can read the PDF your code produces, you can simply create the PDF using a byte array output stream and thereafter wrap the byte array from that stream in a byte array input stream:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, baos);
document.open();
XMLWorkerHelper.getInstance().parseXHtml(writer, document, new FileInputStream("/html/loremipsum.html"));
document.close();
ByteArrayInputStream pdfInputStream = new ByteArrayInputStream(baos.toByteArray());
You can optimize this a bit by creating and processing the PDF in different threads and using a PipedOutputStream and a PipedInputStream instead.

How to add external CSS while generating PDF?

Currently i am using following code to generate PDF in a JSP file:
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment;filename=reports.pdf");
Document document = new Document();
document.setPageSize(PageSize.A1);
PdfWriter writer = null;
writer = PdfWriter.getInstance(document, response.getOutputStream());
document.open();
ByteArrayInputStream bis = new ByteArrayInputStream(htmlSource.toString().getBytes());
XMLWorkerHelper.getInstance().parseXHtml(writer, document, bis);
document.close();
With this am able to generate PDF.
But i would like to add CSS file while generating PDF.
Please Help me...
i am not sure in java how can you use but in c# you can add external style sheet code or syntax by this code:-
StyleSheet css = new StyleSheet();
css.LoadTagStyle("body", "face", "Garamond");
css.LoadTagStyle("body", "encoding", "Identity-H");
css.LoadTagStyle("body", "size", "12pt");
may be this helps you
Regards,
vinit
Please take a look at the ParseHtmlTable1 example. In this example, we have HTML stored in a StringBuilder object and some CSS stored in a String. In my example, I convert the sb object and the CSS object to an InputStream. If you have files with the HTML and the CSS, you could easily use a FileInputStream.
Once you have an InputStream for the HTML and the CSS, you can use this code:
// CSS
CSSResolver cssResolver = new StyleAttrCSSResolver();
CssFile cssFile = XMLWorkerHelper.getCSS(new ByteArrayInputStream(CSS.getBytes()));
cssResolver.addCss(cssFile);
// HTML
HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
// Pipelines
PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer);
HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);
CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);
// XML Worker
XMLWorker worker = new XMLWorker(css, true);
XMLParser p = new XMLParser(worker);
p.parse(new ByteArrayInputStream(sb.toString().getBytes()));
Or, if you don't like all that code:
ByteArrayInputStream bis = new ByteArrayInputStream(htmlSource.toString().getBytes());
ByteArrayInputStream cis = new ByteArrayInputStream(cssSource.toString().getBytes());
XMLWorkerHelper.getInstance().parseXHtml(writer, document, bis, cis);
You may try this code reference.
$html .= '<style>'.file_get_contents(_BASE_PATH.'stylesheet.css').'</style>';
Change content type to
response.setContentType("application/pdf");

Java Set local file Hyperlink in existing pdf using itext

I am trying to provide a hyper link in a existing PDF, which when clicked will open the file. How can this be done?
I have try following Code it work fine for external hyper link like http://www.google.com but not working for local file hyperlink like D:/intro.pdf .
i am using itext pdf library.
Code :
String in = "D:/introduction.pdf";
String out = "D:/introduction.pdf";
try {
PdfReader reader = new PdfReader(in);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, baos);
PdfContentByte canvas=stamper.getOverContent(6);
Chunk imdb = new Chunk("Local Link");
imdb.setAnchor("http://www.google.com"); // this work
// imdb.setAnchor("D://intro.pdf"); // this does not work
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, new Phrase(imdb), 100, 10, 0);
stamper.close();
FileOutputStream fileOutputStream = new FileOutputStream(out);
IOUtils.write(baos.toByteArray(), fileOutputStream);
} catch (Exception e) {
}
i have also try using Annotation as below :
PdfAnnotation annotation;
PdfName aa=new PdfName("test test");
annotation = PdfAnnotation.createLink(stamper.getWriter(),
new Rectangle(50f, 750f, 180f, 800f),aa,PdfAction.gotoRemotePage("file:///D:/intro.pdf","1", false, true));
annotation.setTitle("Click Here");
stamper.addAnnotation(annotation, 1);
I have also try below code comment by #Bruno Lowagie : [ it create link on given page but in intro.pdf file and when i click on link it on same page (intro.pdf)]
as per above image ( image of intro.pdf page number-2 )
PdfReader reader1 = new PdfReader("D://introduction.pdf");
PdfStamper stamper1 = new PdfStamper(reader1, new FileOutputStream("D://intro.pdf"));
PdfAnnotation link1 = PdfAnnotation.createLink(stamper1.getWriter(),
new Rectangle(136, 780, 559, 806), PdfAnnotation.HIGHLIGHT_INVERT,
new PdfAction("D://introduction.pdf", 1));
link1.setTitle("Click Here");
stamper1.addAnnotation(link1, 2);
stamper1.close();
Thanks in advance.
You need to specify the protocol. For web pages, your URI starts with http://; for files your URI should start with file://.
However, as the file you want to link to is also a PDF file, you probably don't want to use the setAnchor() method. You should use the setRemoteGoto() method instead. See the MovieLinks2 example.
If you want to add a link to an existing document, this is how to do it:
PdfReader reader = new PdfReader("hello.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("hello_link.pdf"));
PdfAnnotation link = PdfAnnotation.createLink(stamper.getWriter(),
new Rectangle(36, 790, 559, 806), PdfAnnotation.HIGHLIGHT_INVERT,
new PdfAction("hello.pdf", 1));
stamper.addAnnotation(link, 1);
stamper.close();
If you look inside the PDF document, you'll see that the new file named hello_link.pdf contains a Link annotation that refers to the old file hello.pdf:

Categories