Merging files into single pdf generate different view - java

I´m trying to merge into one file with one or more PDF files stored files and a JasperReports file using iText.
I did this method.
Map<String, Object> parameters = new HashMap<String, Object>();
List<String> arquivos = new LinkedList<String>();
arquivos.add("/Formulario/teste.jrxml");
arquivos.add("/Formulario/teste.pdf");
try {
Document document = new Document(PageSize.A4);
document.setMargins(0F, 0F, 0F, 0F);
PdfCopy pdfCopy = new PdfCopy(document, new FileOutputStream("c:\\labels\\teste.pdf"));
pdfCopy.setMargins(0, 0, 0, 0);
document.open();
PdfReader pdfReader = null;
InputStream inputStream = null;
for (String arquivo : arquivos) {
inputStream = ReportService.class.getResourceAsStream(arquivo);
if (FilenameUtils.getExtension(arquivo).equals("jrxml")) {
JasperReport report = JasperCompileManager.compileReport(inputStream);
JasperPrint jasperPrint = JasperFillManager.fillReport(report, parameters, new JREmptyDataSource());
inputStream = new ByteArrayInputStream(JasperExportManager.exportReportToPdf(jasperPrint));
}
pdfReader = new PdfReader(inputStream);
for (int i = 1; i <= pdfReader.getNumberOfPages(); i++) {
pdfCopy.addPage(pdfCopy.getImportedPage(pdfReader, i));
}
pdfCopy.freeReader(pdfReader);
pdfReader.close();
}
document.close();
} catch (DocumentException | IOException | JRException e) {
e.printStackTrace();
}
I looked at google, but didn't found any answer. So whats wrong? It's possible to generate these pages in the same margins?

Related

Unable to read PDF using itextpdf

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.

How can I merge the documents consisting PDFs as well as images?

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.

concatenate n pdf reports into one pdf (jasper report) [duplicate]

I have a web application with a dropdown from where user could select the type of report viz. report1, report2, report3, etc.
Based on the report selected, a Jasper report is compiled on the server and opens as a pop up in PDF format.
On the server side, I am implementing each report in a separate method using below code say for e.g. for report1:
JRBeanCollectionDataSource report1DataSource = new JRBeanCollectionDataSource(resultSetBeanListReport1);
InputStream inputStreamReport1 = new FileInputStream(request.getSession().getServletContext ().getRealPath(jrxmlFilePath + "report1.jrxml"));
JasperDesign jasperDesignReport1 = JRXmlLoader.load(inputStreamReport1);
JasperReport jasperReportReport1 = JasperCompileManager.compileReport(jasperDesignReport1);
bytes = JasperRunManager.runReportToPdf(jasperReportReport1, titleMapReport1, report1DataSource);
Similarly, report2 is in a separate method with below code:
JRBeanCollectionDataSource invstSummDataSource = new JRBeanCollectionDataSource(resultSetBeanListInvstOfSumm);
InputStream inputStreamInvstSumm = new FileInputStream(request.getSession().getServletContext().getRealPath(jrxmlFilePath + "investSummary.jrxml"));
JasperDesign jasperDesignInvstSumm = JRXmlLoader.load(inputStreamInvstSumm);
JasperReport jasperReportInvstSumm = JasperCompileManager.compileReport(jasperDesignInvstSumm);
bytes = JasperRunManager.runReportToPdf(jasperReportInvstSumm, titleMapInvstSumm, invstSummDataSource);
Now I have a requirement that if report1 is selected from the dropdown, the resulting PDF should contain all the reports one after other in the same PDF.
How can I combine above two lines of codes to finally generate a single PDF?
Here is sample code for combining multiple jasper prints
List<JasperPrint> jasperPrints = new ArrayList<JasperPrint>();
// Your code to get Jasperreport objects
JasperReport jasperReportReport1 = JasperCompileManager.compileReport(jasperDesignReport1);
jasperPrints.add(jasperReportReport1);
JasperReport jasperReportReport2 = JasperCompileManager.compileReport(jasperDesignReport2);
jasperPrints.add(jasperReportReport2);
JasperReport jasperReportReport3 = JasperCompileManager.compileReport(jasperDesignReport3);
jasperPrints.add(jasperReportReport3);
JRPdfExporter exporter = new JRPdfExporter();
//Create new FileOutputStream or you can use Http Servlet Response.getOutputStream() to get Servlet output stream
// Or if you want bytes create ByteArrayOutputStream
ByteArrayOutputStream out = new ByteArrayOutputStream();
exporter.setParameter(JRExporterParameter.JASPER_PRINT_LIST, jasperPrints);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, out);
exporter.exportReport();
byte[] bytes = out.toByteArray();
This answer is to help user using latest version of Jasper-Report. In
#Sangram Jadhav accept answer the
JRExporterParameter.JASPER_PRINT_LIST is deprecated
The current code would be:
Map<String, Object> paramMap = new HashMap<String, Object>();
List<JasperPrint> jasperPrintList = new ArrayList<JasperPrint>();
JasperPrint jasperPrint1 = JasperFillManager.fillReport(report1, paramMap);
jasperPrintList.add(jasperPrint1);
JasperPrint jasperPrint2 = JasperFillManager.fillReport(report2, paramMap);
jasperPrintList.add(jasperPrint2);
JRPdfExporter exporter = new JRPdfExporter();
exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList)); //Set as export input my list with JasperPrint s
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput("pdf/output.pdf")); //or any other out streaam
SimplePdfExporterConfiguration configuration = new SimplePdfExporterConfiguration();
configuration.setCreatingBatchModeBookmarks(true); //add this so your bookmarks work, you may set other parameters
exporter.setConfiguration(configuration);
exporter.exportReport();
You can either merge reports before generating PDFs using JasperPrint or after generating PDFs using iText.
For the JasperPrint solution: you will generate the 2 (or more) JasperPrints then get the content pages and concat them.
JasperPrint jp1 = JasperFillManager.fillReport(url.openStream(), parameters,
new JRBeanCollectionDataSource(inspBean));
JasperPrint jp2 = JasperFillManager.fillReport(url.openStream(), parameters,
new JRBeanCollectionDataSource(inspBean));
List pages = jp2 .getPages();
for (int j = 0; j < pages.size(); j++) {
JRPrintPage object = (JRPrintPage)pages.get(j);
jp1.addPage(object);
}
JasperViewer.viewReport(jp1,false);
For the iText solution after generating the PDFs:
void concatPDFs(List<InputStream> streamOfPDFFiles, OutputStream outputStream, boolean paginate) {
Document document = new Document();
try {
List<InputStream> pdfs = streamOfPDFFiles;
List<PdfReader> readers = new ArrayList<PdfReader>();
int totalPages = 0;
Iterator<InputStream> iteratorPDFs = pdfs.iterator();
// Create Readers for the pdfs.
while (iteratorPDFs.hasNext()) {
InputStream pdf = iteratorPDFs.next();
PdfReader pdfReader = new PdfReader(pdf);
readers.add(pdfReader);
totalPages += pdfReader.getNumberOfPages();
}
// Create a writer for the outputstream
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
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()) {
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;
}
outputStream.flush();
document.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document.isOpen())
document.close();
try {
if (outputStream != null)
outputStream.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
Here is my code which i use on grails code .Its gives me two different report in one pdf.
String reportDir = Util.getReportDirectory() // my report directory
Map reportParams = new LinkedHashMap()
Map reportParams1 = new LinkedHashMap()
String outputReportName="Test_Output_copy"
reportParams.put('parameter name',"parameter")
reportParams1.put('copy',"Customer's Copy")
JasperReportDef reportDef1 = new JasperReportDef(name: 'testBillReport.jasper', fileFormat: JasperExportFormat.PDF_FORMAT,
parameters: reportParams, folder: reportDir)
JasperReportDef reportDef2 = new JasperReportDef(name: 'testBillReport.jasper', fileFormat: JasperExportFormat.PDF_FORMAT,
parameters: reportParams1, folder: reportDir)
List<JasperReportDef> jasperPrintList = new ArrayList<JasperReportDef>();
jasperPrintList.add(reportDef1);
jasperPrintList.add(reportDef2);
ByteArrayOutputStream report1 = jasperService.generateReport(jasperPrintList);
response.setHeader("Content-disposition", "inline;filename="+outputReportName+'.pdf')
response.contentType = "application/pdf"
response.outputStream << report1.toByteArray()
You can try this one this is work for me
JasperPrint jp1 = JasperFillManager.fillReport(reportFile1,reportParams,Connection);
JasperPrint jp2 = JasperFillManager.fillReport(reportFile2,reportParams,Connection);
for (int j = 0; j < jp1.getPages().size(); j++) {
//Add First report to second report
jp2.addPage((JRPrintPage) jp1.getPages().get(j));
}

iText 7 - com.itextpdf.io.IOException: PDF startxref not found

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();
}
}

How to read Images in the .doc file

How to read images in the ms-office .doc file using Apache poi? I have tried with the following code but it is not working.
try {
POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream("C:\\DATASTORE\\ImageDocument.doc"));
Document document = new Document();
OutputStream fileOutput = new FileOutputStream(new File("C:/DATASTORE/ImageDocumentPDF.pdf"));
PdfWriter.getInstance(document, fileOutput);
document.open();
HWPFDocument hdocument=new HWPFDocument(fs);
Range range=hdocument.getOverallRange();
PdfPTable createTable;
CharacterRun run;
PicturesTable picture=hdocument.getPicturesTable();
int picoffset=run.getPicOffset();
for(int i=0;i<range.numParagraphs();i++) {
run =range.getCharacterRun(i);
if(picture.hasPicture(run)) {
Picture pic=picture.extractPicture(run, true);
byte[] picturearray=pic.getContent();
com.itextpdf.text.Image image=com.itextpdf.text.Image.getInstance(picturearray);
document.add(image);
}
}
}
When i execute the above code and prints the picture offset value it displays -1
and when print picture.hasPicture(run) it returns false though the input file has an image.
Please help me to find the solution.
Thank you
public static List<byte[]> extractImagesFromWord(File file) {
if (file.exists()) {
try {
List<byte[]> result = new ArrayList<byte[]>();
if ("docx".equals(getMimeType(file).getExtension())) {
org.apache.poi.xwpf.usermodel.XWPFDocument doc = new XWPFDocument(new FileInputStream(file));
for (org.apache.poi.xwpf.usermodel.XWPFPictureData picture : doc.getAllPictures()) {
result.add(picture.getData());
}
} else if ("doc".equals(getMimeType(file).getExtension())) {
org.apache.poi.hwpf.HWPFDocument doc = new HWPFDocument(new FileInputStream(file));
for (org.apache.poi.hwpf.usermodel.Picture picture : doc.getPicturesTable().getAllPictures()) {
result.add(picture.getContent());
}
}
return result;
} catch (Exception e) {
throw new RuntimeException( e);
}
}
return null;
}
it worked for me, if picOffset returns -1, it means there is no image for current CharacterRun

Categories