Save pdf to bytearray using itext in Java - java

I am using itext to read a large pdf file and save selected pages.
PdfReader reader = null;
reader = new PdfReader("customPath/largePdf.pdf");
int pages = reader.getNumberOfPages();
List<Integer> pagesList = new ArrayList<Integer>();
pagesList.add(1);
pagesList.add(2);
reader.selectPages(pagesList);
String path;
PdfStamper stamper = null;
path = String.format("customerPath/split.pdf");
stamper = new PdfStamper(reader, new FileOutputStream(path));
All good until now, i can open the split.pdf .
Now, Instead of saving to a file, i want to save it to a bytearray (so that i can save it as a blob later)
Tried this:
PdfReader reader = null;
reader = new PdfReader("customPath/largePdf.pdf");
int pages = reader.getNumberOfPages();
List<Integer> pagesList = new ArrayList<Integer>();
pagesList.add(1);
pagesList.add(2);
reader.selectPages(pagesList);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfStamper stamper2 = new PdfStamper(reader, baos);
byte[] byteARy = baos.toByteArray();
Just to make sure it works, i tried writing this bytearray to a file:
OutputStream out = new FileOutputStream("customPath/fromByteArray.pdf");
out.write(byteARy);
out.close();
fromByteArray.pdf does not open and the size is zero, any idea what might be wrong ?

You retrieve the byte array (using baos.toByteArray()) immediately after creating the PdfStamper.
PdfStamper stamper2 = new PdfStamper(reader, baos);
byte[] byteARy = baos.toByteArray();
At that time there is (next to) nothing in the output. You must instead wait until after closing your PdfStamper to retrieve the output.
PdfStamper stamper2 = new PdfStamper(reader, baos);
...
stamper2.close();
byte[] byteARy = baos.toByteArray();
Now the byte array should contain the complete, stamped PDF.

Related

Delete pdf pages in java with iTextpdf

I have an existing function to show pdf files that I can't change.
The input of function is an InputStream variable.
In the past they used to pass a pdf file to it and it shows it.
But right now they asked me to show only first 30 pages of the pdf. So I am using iTextpdf and I do something like this:
PdfReader reader = new PdfReader (inputStream);
reader.selectPages("1-30");
Now I should send the result as InputStream variable to show method.
How I should do it?
Thanks
You can store the result using a PdfStamper like this:
PdfReader reader = new PdfReader (inputStream);
reader.selectPages("1-30");
ByteArrayOutputStream os = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, os);
stamper.close();
byte[] changedPdf = os.toByteArray();
If you want the result again to be in the InputStream inputStream variable, simply add a line
inputStream = new ByteArrayInputStream(changedPdf);
Get the reader of existing pdf file by
PdfReader pdfReader = new PdfReader("source pdf file path");
Now update the reader by
reader.selectPages("1-5,15-20");
then get the pdf stamper object to write the changes into a file by
PdfStamper pdfStamper = new PdfStamper(pdfReader,
new FileOutputStream("destination pdf file path"));
close the PdfStamper by
pdfStamper.close();
It will close the PdfReader too.

Create PDFReader from String or InputStream

Below is my code to create PDF from input String or byte[]
This input is working with iText5. When I pass input to PdfReader in iText5 it was able to create PdfReader object.
Case 1:
byte[] bytesDecoded = Base64.decodeBase64(input.getBytes(StandardCharsets.UTF_8));
InputStream is = IOUtils.toInputStream(bytesDecoded.toString(), StandardCharsets.UTF_8);
PdfReader reader = new PdfReader(is);
Case 2:
PdfReader reader = new PdfReader(IOUtils.toInputStream(input, StandardCharsets.UTF_16));
Exception:
Exception in thread "main" com.itextpdf.io.IOException: PDF header not found.
at com.itextpdf.io.source.PdfTokenizer.getHeaderOffset(PdfTokenizer.java:223)
at com.itextpdf.kernel.pdf.PdfReader.getOffsetTokeniser(PdfReader.java:1018)
Not working in iText7
This is the way I have done. Sharing it as may be useful in future.
ByteArrayOutputStream pdfos = new ByteArrayOutputStream();
byte[] bytesDecoded = Base64.decodeBase64(src.getBytes(StandardCharsets.UTF_8));
ByteArrayInputStream inStream = new ByteArrayInputStream(bytesDecoded);
PdfReader reader = new PdfReader(inStream);
PdfSigner signer = new PdfSigner(reader, pdfos, false);
This is the easiest method to create a PdfReader from a Byte[] or a String.
byte[] template;
PdfReader templatePdf = new PdfReader(new RandomAccessSourceFactory().CreateSource(new MemoryStream(template).ToArray()),new ReaderProperties());

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)

Generate and open PDF in new browser at clients machine with java IText

I am trying to write in an existing pdf file and want to open it in new browser at clients machine. I saw many post related this and i tried all answers but still i am not getting result. File can be generated on my disk but i want to open it at new window once created.
Code :
response.setContentType("application/pdf");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = new FileInputStream("Challan.pdf");
PdfReader pdfReader = new PdfReader(is, null);
PdfStamper pdfStamper = new PdfStamper(pdfReader, baos);
for(int i=1; i<= pdfReader.getNumberOfPages(); i++){
Phrase Namephrase = new Phrase("John Smith");
Phrase Idphrase = new Phrase("DPG10001");
Phrase Datephrase = new Phrase("11/10/1980");
PdfContentByte pdfcontent = pdfStamper.getUnderContent(i);
pdfcontent.beginText();
ColumnText.showTextAligned(pdfcontent, Element.ALIGN_JUSTIFIED_ALL, Idphrase, 500, 428, 0); /*Do not change this values*/
ColumnText.showTextAligned(pdfcontent, Element.ALIGN_JUSTIFIED, Namephrase, 500, 407, 0);
ColumnText.showTextAligned(pdfcontent, Element.ALIGN_JUSTIFIED, Datephrase, 500, 386, 0);
pdfcontent.endText();
}
pdfStamper.close();
pdfReader.close();
// write ByteArrayOutputStream to the ServletOutputStream
response.setHeader("Content-Disposition", "inline;filename=ChallanStamped.pdf");
// the contentlength
response.setContentLength(baos.size());
ServletOutputStream sos = response.getOutputStream();
baos.writeTo(sos);
sos.flush();
sos.close();
In this i am trying to read challan.pdf and want to update file and create new one.From jsp i am calling this servlet.
Please help me.
Update:
I tried with some changes but still not working. My updated code is
` ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedInputStream is = new BufferedInputStream(new FileInputStream("Challan.pdf"));
PdfReader pdfReader = new PdfReader(is, null);
PdfStamper pdfStamper = new PdfStamper(pdfReader, baos);
-----------Some Code -------------
pdfStamper.close();
pdfReader.close();
response.setHeader("Content-Disposition", "inline;filename=ChallanStamped.pdf");
response.setContentLength(baos.size());
output = new BufferedOutputStream(response.getOutputStream());
byte[] buffer = new byte[4096];
int length;
while ((length = input.read(buffer)) != -1) {
output.write(buffer, 0, length);
}
output.flush();
output.close();
input.close();
I am calling servlet from jsp through Ajax(sending lot of data).
And also i am getting java.io.IOException: Stream closed exception with this updated code.
In order to open the pdf file in new window you need to do some changes in your jsp form.
<form action="yourServletURLPattern" method="post" target="_blank">
-- Some Fields--
-- Submit Button--
</form>
target=_blank will do the needful.
Now coming to your servlet code :
ByteArrayOutputStream baos = new ByteArrayOutputStream();
---------- Some Code in between-----------------------
ServletOutputStream sos = response.getOutputStream();
baos.writeTo(sos);
But this do nothing since your ByteArrayOutputStream Object contains nothing so what will you write to ServletOutputStream
I will not write code for you but can guide, So that you can achieve it yourself
Read File after editing using BufferedInputStream
Write it on OutputStream of Response using BufferedOutputStream (Simply Loop
through the file)
Flush the Response's Output Stream

Incorrect upload file use FileOutputStream. Incorrect size

When I try upload the file from server, I use this code. I get the file size of 500kb, when the original file size about 300kb.
What am I doing wrong?
attachmentContent = applicationApi.getApplicationAttachmentContent(applicationame);
InputStream in = new BufferedInputStream(attachmentContent.getAttachmentContent().getInputStream());
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int n=0;
while (-1 !=(n=in.read(buf)))
{
out.write(buf,0,n);
}
out.close();
in.close();
byte[] response = out.toByteArray();
File transferredFile = new File(attachmentName);
FileOutputStream outStream = new FileOutputStream(transferredFile);
attachmentContent.getAttachmentContent().writeTo(outStream);
outStream.write(response);
outStream.close();
Simplify. The same result:
File transferredFile = new File(attachmentName);
FileOutputStream outStream = new FileOutputStream(transferredFile);
attachmentContent.getAttachmentContent().writeTo(outStream);
outStream.close();
The ByteArrayOutputStream is a complete waste of time and space. You're reading the attachment twice, and writing it twice too. Just read from the attachment and write directly to the file. Simplify, simplify. You don't need 90% of this.

Categories