I am using itextpdf-5.5.4 jar to merge or add two pdf into one PDF.
I did not get any error or exception while running code but displayed below text in Merged PDF. I did not get below text when i open individual PDF's.
The document you are trying to load requires Adobe Reader 8 or higher.
You may not have the Adobe Reader installed or your viewing
environment may not be properly configured to use Adobe Reader.
For information on how to install Adobe Reader and configure your
viewing environment please see
http://www.adobe.com/go/pdf_forms_configure.
void mergePdfFiles(List<InputStream> inputPdfList, OutputStream outputStream) throws Exception {
// Create document and pdfReader objects.
Document document = new Document();
List<PdfReader> readers = new ArrayList<PdfReader>();
int totalPages = 0;
// 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, outputStream);
// 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.
outputStream.flush();
document.close();
outputStream.close();
System.out.println("Pdf files merged successfully.");
}
public static void main(String args[]) {
try {
List<InputStream> inputPdfList = new ArrayList<InputStream>();
inputPdfList.add(new FileInputStream("pdf1.pdf"));
inputPdfList.add(new FileInputStream("pdf2.pdf"));
OutputStream outputStream = new FileOutputStream("Merge-PDF.pdf");
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
mergePdfFiles(inputPdfList, byteStream);
byte[] byteS = byteStream.toByteArray();
outputStream.write(byteS);
} catch (Exception e) {
e.printStackTrace();
}
}
Please help me out on this.
Related
I am trying to read .rpt file and generate pdf using ReportClientDocument,ByteArrayInputStream and ByteArrayOutputStream. After generating the pdf file I am unable to open it. It is showing "It may be damaged or use a file format that Preview doesn’t recognise." My Source code is provided below
public static void generatePDFReport()
{
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
LocalDateTime now = LocalDateTime.now();
System.out.println(dtf.format(now));
try {
ReportClientDocument rcd = new ReportClientDocument();
String rptPath="/Users/florapc/Desktop/Report/AcStatement.rpt";
String outputPath=String.format("/Users/florapc/Desktop/Report/%s.pdf",dtf.format(now));
File inputFile = new File(rptPath);
File outputFile = new File(outputPath);
rcd.open(rptPath, 0);
System.out.println(rptPath);
List<IParameterField> fld = rcd.getDataDefController().getDataDefinition().getParameterFields();
List<String> reportContent = new ArrayList<String>();
System.out.println(fld.size());
for (int i = 0; i < fld.size(); i++) {
System.out.println(fld.get(i).getDescription());
reportContent.add(fld.get(i).getDescription().replaceAll("[^a-zA-Z0-9]", " "));
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(reportContent);
byte[] bytes = bos.toByteArray();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
byte[] byteArray = new byte[byteArrayInputStream.available()];
int x = byteArrayInputStream.read(byteArray, 0, byteArrayInputStream.available());
System.out.println(x);
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();;
byteArrayOutputStream.write(byteArray, 0, x);
byteArrayOutputStream.writeTo(fileOutputStream);
System.out.println(fileOutputStream);
System.out.println("File exported succesfully");
byteArrayInputStream.close();
byteArrayOutputStream.close();
fileOutputStream.close();
rcd.close();
} catch (Exception e) {
e.printStackTrace();
}
}
I can read .rpt file and print it in console. Please help me finding the best way to generate pdf properly.
I'm not familiar with ReportClientDocument. As far as I understand it's not a PDF document itself but a report that can be saved as PDF. ObjectOutputStream won't achieve this as it's Java specific format and has nothing to do with PDF.
It looks as if a PrintOutputController is needed for PDF export. Thus your code would look more like so:
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
InputStream is = rcd.getPrintOutputController().export(ReportExportFormat.PDF);
copy(is, fileOutputStream);
fileOutputStream.close();
...
void copy(InputStream source, OutputStream target) throws IOException {
byte[] buf = new byte[8192];
int length;
while ((length = source.read(buf)) > 0) {
target.write(buf, 0, length);
}
}
Note that no byte array streams are needed. They are a detour, slowing down your program and drive up memory consumption.
I have this method in which I add a password to the pdf, but I am doing it with pdf from the computer. What I want to try is to receive as input parameter a string that would be pdf in base 64 and respond to a base64.
public static void main(String[] args) {
try {
OutputStream file = new FileOutputStream(new File("D:\\Test.pdf"));
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, file);
writer.setEncryption(USER_PASS.getBytes(), OWNER_PASS.getBytes(),
PdfWriter.ALLOW_PRINTING, PdfWriter.ENCRYPTION_AES_128);
document.open();
document.add(new Paragraph("Hello World, iText"));
document.add(new Paragraph(new Date().toString()));
document.close();
file.close();
} catch (Exception e) {
e.printStackTrace();
}
}
It was complicated how to handle a Base64 pdf because it was the first time, but in the end I was able to develop the method where you can add the password to a pdf that is already in base64.
public String EncriptarPDFconContraseña(String pdfBase64, String passwordUser, String passwordOwner) throws IOException, DocumentException {
PdfReader reader = new PdfReader(Base64.decode(pdfBase64));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, baos);
stamper.setEncryption(passwordUser.getBytes(), passwordOwner.getBytes(), PdfWriter.ALLOW_PRINTING, PdfWriter.ENCRYPTION_AES_128);
stamper.close();
String base64 = Base64.encodeBytes(baos.toByteArray());
return base64;
}
I am using iText 2.1.7 to merge some document PDFs into a single PDF. The code below seems to work just fine, however it appears in some instances the rendered PDF is scaled slightly smaller, like at 90% of the PDF if printed directly before processing.
Is there a way to keep the current size?
private void doMerge(List<InputStream> list, OutputStream outputStream) throws DocumentException, IOException {
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
PdfContentByte cb = writer.getDirectContent();
for (InputStream in : list) {
PdfReader reader = new PdfReader(in);
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
document.newPage();
//import the page from source pdf
PdfImportedPage page = writer.getImportedPage(reader, i);
//add the page to the destination pdf
cb.addTemplate(page, 0, 0);
}
}
outputStream.flush();
document.close();
outputStream.close();
}
The API was already available with that version. I would even suggest to use PdfSmartCopy instead of PdfCopy (or PdfCopyFields if form fields are inside).
private PdfSmartCopy copier;
public void SomeMainMethod(){
Document finalPdf = new Document();
copier = new PdfSmartCopy(finalPdf, outputstream);
//Start adding pdfs
finalPdf.open();
//add n documents
addDocuments(...);
finalPdf.close();
formCopier.close();
}
public void addDocument(InputStream pdfDocument, int startPage, int endPage){
PdfReader reader= new PdfReader(pdfDocument);
int startPage = 1;
int endPage = reader.getNumberOfPages();
for (int i = startPage; i <= endPage; i++) {
copier.addPage(this.copier.getImportedPage(reader,i));
}
if(copier!=null){
//Important: Free Memory!
copier.flush();
copier.freeReader(reader);
}
if (reader!=null) {
reader.close();
reader=null;
}
pdfDocument.close();
}
In my current code I am merging the documents consisting PDF files.
public static void appApplicantDownload(File file) {
Connection con = getConnection();
Scanner sc = new Scanner(System.in);
List < InputStream > list = new ArrayList < InputStream > ();
try {
OutputStream fOriginal = new FileOutputStream(file, true); // original
list.add(new FileInputStream(file1));
list.add(new FileInputStream(file2));
list.add(new FileInputStream(file3));
doMerge(list, fOriginal);
} catch (Exception e) {
}
}
public static void doMerge(List < InputStream > list, OutputStream outputStream) throws DocumentException, IOException {
try {
System.out.println("Merging...");
Document document = new Document();
PdfCopy copy = new PdfCopy(document, outputStream);
document.open();
for (InputStream in : list) {
ByteArrayOutputStream b = new ByteArrayOutputStream();
IOUtils.copy( in , b);
PdfReader reader = new PdfReader(b.toByteArray());
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
copy.addPage(copy.getImportedPage(reader, i));
}
}
outputStream.flush();
document.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
But now I want to change the code such that it should allow Image as well as PDFs to be merged. Above code is giving me the error that No PDF Signature found
First, you have to know somehow if the file is a PDF or an image. The easiest way would be to use the extension of the file. So you would have get extension of the file and then pass this information to your doMerge method. Do achieve that, I would change your current method
public static void doMerge(List<InputStream> list, OutputStream outputStream)
For something like
public static void doMerge(Map<InputStream, String> files, OutputStream outputStream)
So each InputStream is associated with a extension.
Second, you have to load images and pdf seperately. So your loop should look like
for (InputStream in : files.keySet()) {
String ext = files.get(in);
if(ext.equalsIgnoreCase("pdf"))
{
//load pdf here
}
else if(ext.equalsIgnoreCase("png") || ext.equalsIgnoreCase("jpg"))
{
//load image here
}
}
In java, you can easily load an Image using ImageIO. Look at this question for more details on this topic: Load image from a filepath via BufferedImage
Then to add your image into the PDF, use the PdfWriter
PdfWriter pw = PdfWriter.GetInstance(doc, outputStream);
Image img = Image.GetInstance(inputStream);
doc.Add(img);
doc.NewPage();
If you want to convert your image into PDF before and merge after you also can do that but you just have to use the PdfWriter to write them all first.
Create a new page in the opened PDF document and use the function for inserting images to place the image on that page.
We are trying to upgrade from iText 5 to iText 7 and saw few issues. I am getting an exception as "com.itextpdf.io.IOException: PDF startxref not found." inside PdfReader#readPdf() and finally in the caller method getting an exception as "com.itextpdf.kernel.PdfException: Trailer not found.".
My use case is creating a PdfReader instance using inputSream and then creating PdfDocument from the reader and passing PdfWriter as a constructor parameter. We are trying to modify existing PDF, and the sample code is as below
PdfReader pdfReader = new PdfReader(inputStream);
pdfReader.setUnethicalReading(true);
ByteArrayOutputStream os = new ByteArrayOutputStream();
PdfDocument pdfDocument = new PdfDocument(pdfReader, new PdfWriter(os));
What am I doing wrong and how can we fix this issue?
We have a utility method that writes the output stream and creates a new PDF attachment.
Copying the answer from the comments:
I got this issue fixed, I need to close pdfDocument before I am
writing attachments from the output stream.
I was not closing the stream properly, I created the pdfDocument
instance and reading from output stream before closing the
pdfDocument. So I need to close pdfDocument stream first and then read
from output stream to create attachments.
I had this exact same problem after add some elements to document (itextpdf 7.2.1), but the instance of PdfDocument was being closed (using a "try with resources"):
public static byte[] stampDocument(byte[] fileBytes, Integer startPageNumber) throws IOException {
try (ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfDocument pdf = new PdfDocument(new PdfReader(bais), new PdfWriter(baos, new WriterProperties().setFullCompressionMode(true)))) {
addStamps(pdf, startPageNumber);
baos.flush();
return baos.toByteArray();
}
}
private static void addStamps(PdfDocument pdf, Integer startPageNumber) throws IOException {
int iStartPageNumber = (startPageNumber == null ? 0 : startPageNumber - 1);
for (int i = 1; i <= pdf.getNumberOfPages(); i++) {
Rectangle rect = pdf.getPage(i).getPageSize();
PdfCanvas canvas = new PdfCanvas(pdf.getPage(i).newContentStreamBefore(), pdf.getPage(i).getResources(), pdf);
stampPage(canvas, iStartPageNumber + i, rect.getHeight(), rect.getWidth());
}
}
private static void stampPage(PdfCanvas canvas, int pageNumber, float height, float width) throws IOException {
float x = width - 85;
float y = height - 100;
Rectangle recta = new Rectangle(x, y, 75, 75);
try (Canvas ca = new Canvas(canvas, recta)) {
ca.showTextAligned(new Paragraph(new Text(String.valueOf(pageNumber)).setFontSize(FONT_SIZE)), x + (recta.getWidth()/2), recta.getHeight()/2 - FONT_SIZE/2 + y, TextAlignment.CENTER);
}
canvas.rectangle(recta);
}
The solution was add a Document instance to be closed after add the new elements:
public static byte[] stampDocument(byte[] fileBytes, Integer startPageNumber) throws IOException {
try (ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfDocument pdf = new PdfDocument(new PdfReader(bais), new PdfWriter(baos, new WriterProperties().setFullCompressionMode(true)))) {
Document doc = new Document(pdf);
addStamps(pdf, startPageNumber);
doc.close();
baos.flush();
return baos.toByteArray();
}
}