5

I am using an Oracle Database and storing PDF content in a BLOB field.

I want to read the BLOB content and then edit and output the edited content.

The editing I need to do are:

  • add a title above the BLOB content
  • add a Water mark on every page
  • add footer on every page

Then I need to output the file without any physical file getting created that is within the response stream.

I tried to achieve this using itext but was not reaching anywhere with it. I am stuck and not sure where to start with.

Also sometimes I might have to combine blob contents into one, buts thats some thing that is bound to happen Once in a million..so that not a concern now...

How can I achieve my primary requirements of the above three steps using in java? Is it possible with Itext?? Or is some other library available that would help?

Database : Oracle 10g Release 2

OS: Linux Fedora/Redhat

Front-end: Java/Servlet/JSP

EDIT

Here is what I tried to do

oracle.sql.BLOB blob = (BLOB) rs.getBlob("MYPDF");
byte[] bytes = blob.getBytes(1, (int) blob.length());
InputStream is = blob.getBinaryStream();
Document document=new Document();
ServletOutputStream servletOutputStream = response.getOutputStream();
PdfWriter writer=PdfWriter.getInstance(document, servletOutputStream);
document.open();
document.add(new Paragraph("Some title"));
document.add(new Paragraph("Some title"));
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=output.pdf");
servletOutputStream.write(bytes, 0, bytes.length);
servletOutputStream.flush();
servletOutputStream.close();
document.close();

The program outputs the pdf content in BLOB field in the database and without the title.

and when I change a bit in the code (change the order of the last few lines) to:

document.close();
servletOutputStream.flush();
servletOutputStream.close();

I get the document with the title content in it and no pdf content of BLOB field. Its the first thing(servletoutputstream/document) that is closed is been thrown as the output.

And when I closed the document before putting the blob content in outputstream:

document.close();
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=output.pdf");
servletOutputStream.write(bytes, 0, bytes.length);
servletOutputStream.flush();
servletOutputStream.close();

I got the browser displaying something like this:

%PDF-1.4 %���� 2 0 obj <>stream x�+�r �26S�00SI�2P�5��1���BҸ4��sSJ2KrR5C��*P�B�5�+��k)&� endstream endobj 4 0 obj <<<>>>/MediaBox[0 0 595 842]>> endobj 1 0 obj <> endobj 3 0 obj <> endobj 5 0 obj <> endobj 6 0 obj <> endobj xref 0 7 0000000000 65535 f 0000000304 00000 n 0000000015 00000 n 0000000392 00000 n 0000000147 00000 n 0000000443 00000 n 0000000488 00000 n trailer <]/Info 6 0 R/Size 7>> startxref 620 %%EOF 

I need the file to be outputted with the pdf content and the title as well.

Hope this edit helps a little bit...

UPDATE(File thrown out in response with the title and the BLOB Content) :

Document document = new Document(PageSize.A4, 108, 72, 30, 72);
PdfWriter writer = PdfWriter.getInstance(document, outputstream);

document.open();

///-----Added Some Title----///

rs = stmt.executeQuery(queryToGetBLOBCONTENT);

if (rs.next()) {


response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=watermark.pdf");
oracle.sql.BLOB blob = (BLOB) rs.getBlob("MYPDF");
byte[] bytes = blob.getBytes(1, (int) blob.length());
InputStream is = blob.getBinaryStream();
PdfReader pdfReader = new PdfReader(is, bytes);
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
PdfContentByte cb = writer.getDirectContent(); // Holds the PDF
PdfImportedPage page;
int currentPageNumber = 0;
int pageOfCurrentReaderPDF = 0;
while (pageOfCurrentReaderPDF < pdfReader.getNumberOfPages()) {
    if (pageOfCurrentReaderPDF > 0) {
        document.newPage();
    }
    pageOfCurrentReaderPDF++;
    currentPageNumber++;
    page = writer.getImportedPage(pdfReader, pageOfCurrentReaderPDF);
    cb.addTemplate(page, 0, 0);
}
pageOfCurrentReaderPDF = 0;
outputstream.flush();
document.close();
outputstream.close();

}

This gives me a file in response that has a the BLOB from DB with title on the top and that is done without any physical files getting generated.

Now to generate the water mark and I need to pass the document to the PDfreader how can I achieve that before closing the document (i.e. executing document.close() , which would out put the file w/o water mark as the stream got closed)

What am I doing wrong in this code? How can I achieve the same file with the watermark and that too without a file getting created at the background.

Sangeet Menon
  • 9,555
  • 8
  • 40
  • 58

2 Answers2

3

If you don't want to create temporary files, then you just need to get the PDF as an InputStream from the DB and let iText read from it and finally write to the OutputStream of the response. Your question is actually too broad to give a well-suited answer ("I am not getting anywhere" doesn't give much to work with), so here's a broad answer:

InputStream input = resultSet.getBinaryStream("columnname");
PdfReader reader = new PdfReader(input);
// ...

OutputStream output = response.getOutputStream();
PdfWriter pdfWriter = PdfWriter.getInstance(document, output);
// ...

You can also pass around a ByteArrayOutputStream instead.


Update as per your problems:

  1. You need to set the response headers before you pass the response body to PdfWriter.

    response.setContentType("application/pdf");
    response.setHeader("Content-Disposition", "attachment; filename=output.pdf");
    PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());
    // ...
    
  2. Get rid of the following lines. They would only messup things.

    byte[] bytes = blob.getBytes(1, (int) blob.length());
    servletOutputStream.write(bytes, 0, bytes.length);
    servletOutputStream.flush();
    servletOutputStream.close();
    

    The PdfWriter will already write to the response body. You don't need to repeat it yourself.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I have added a few lines of code that I tried, hope it helps and makes the question a little bit less broad...I didn't add the code at the first place because it worked only in any one direction(i.e. either the BLOB content from DB or the Title using iText) – Sangeet Menon Mar 29 '11 at 06:21
2

Instead of writing directly to servletOutputStream, you can try this approach:

  1. Create an instance of ByteArrayOutputStream
  2. Create instance of "merged" PDF document. I.e. PDF form Blob + PDF that has title. This example might help : http://java-x.blogspot.com/2006/11/merge-pdf-files-with-itext.html
  3. Write the merged PDF to instance of ByteArrayOutputStream
  4. Set content length of response
  5. Set content type and content disposition
  6. Get bytes from ByteArrayOutputStream and write those bytes to servletOutputStream
  7. Close ByteArrayOutputStream
Shamit Verma
  • 3,839
  • 23
  • 22
  • I don't have any physical file with me to merge , only thing I have is a Blob content and the data to be put in as title which is not a file...the title is dynamically generated from certain user input and DB fields...see the the code I posted.... – Sangeet Menon Mar 29 '11 at 13:13
  • PDF need not come from file. For merging, one of the PDF would be from BLOB (ByteArrayInputStream) and another PDF would be created at runtime with title that is dynamically generated. Both can remian in memory and be exposed as Byte Array Streams to PDF API. – Shamit Verma Mar 29 '11 at 13:16
  • The code on the link did the job to some extend but a line of code, `while (pageOfCurrentReaderPDF – Sangeet Menon Mar 30 '11 at 05:29
  • Only way to ass title at the To would be to shrink rest of the content on the first page. This would deform lots of documents perceptibly. In this case, it better to add that title as a new page and keep rest of document as it is. – Shamit Verma Mar 30 '11 at 05:46
  • Ok fine for the time being I let the content come on the new page but my next problem is that I need to add a water mark on it...and too without a file getting created....is that possible going forward with the procedure in the link?? If yes Please tell me how.. – Sangeet Menon Mar 31 '11 at 05:33
  • Yes you can create an empty PDF with just watermark on it and merge that with generated PDF. Both PDF can be in memory and would not require a file. – Shamit Verma Mar 31 '11 at 10:22
  • can you elaborate a bit. A sample code would help...also I am at a point where I have a document with the title opened, outputstream opened and merged the content together and then I want to add a water mark on the merged pdf... – Sangeet Menon Mar 31 '11 at 10:38
  • http://www.java2s.com/Code/Java/PDF-RTF/AddWatermarkImagetoanExistingPDFFile.htm just specify ByteArray input/output steams instead of file streams. – Shamit Verma Mar 31 '11 at 11:41
  • Please check the update on the post and please help me sort out what I am doing wrong... – Sangeet Menon Mar 31 '11 at 12:54
  • You are writing directly to servlet's outputstream. Instead of doing that, write to a ByteArrayoutputstream. Write to servlet's outputstram only after watermark has been added. – Shamit Verma Mar 31 '11 at 19:05
  • Can you provide me with sample code of how to do it with ByteArrayoutputstream and watermark the pdf by keeping them in memory...? – Sangeet Menon Apr 01 '11 at 06:02
  • In existing code, you will have to replace existing streams with byte-array streams. You have the code that does watermarking based on real streams. These examples show how to use byte-array steams in that place: http://www.java-examples.com/read-byte-array-using-bytearrayinputstream-example http://www.java-samples.com/showtutorial.php?tutorialid=387 – Shamit Verma Apr 01 '11 at 06:15
  • Thanks a lot...Well the hints you gave me worked and I am now able to watermark the file and output it...And you know what you also solved one more issue of mine I posted it [here on stackoverflow](http://stackoverflow.com/questions/5504988/show-the-number-of-pages-in-a-pdf-generated-using-itext-only-on-the-first-page)...post an answer indicating the use of Bytearrayoutputstream and PdfStamper on that and I will accept yours.... – Sangeet Menon Apr 01 '11 at 06:43