How to resize a PdfPTable to fit the page? - java

I am generating a document, like in the following code, except ofcourse the contents of the table, which are varying. What I need to do is make sure that this table never exceeds one page in size, regardless of the amount of content in the cells. Is there a way to do it ?
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import java.awt.Desktop;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public void createTemplate() throws DocumentException, FileNotFoundException, IOException{
String TARGET = System.getProperty("user.home")+"\temp.pdf";
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(TARGET));
document.open();
PdfPTable table = new PdfPTable(7);
for (int i = 0; i < 105; i++) {
Phrase p = new Phrase("some text");
PdfPCell cell = new PdfPCell();
cell.addElement(p);
table.addCell(cell);
}
table.setTotalWidth(PageSize.A4.getWidth()-10);
table.setLockedWidth(true);
PdfContentByte canvas = writer.getDirectContent();
PdfTemplate template = canvas.createTemplate(table.getTotalWidth(),table.getTotalHeight());
table.writeSelectedRows(0, -1, 0, PageSize.A4.getHeight(), template);
Image img = Image.getInstance(template);
img.scaleToFit(PageSize.A4.getWidth(), PageSize.A4.getHeight());
img.setAbsolutePosition(0, PageSize.A4.getHeight());
document.add(img);
document.close();
Desktop desktop = Desktop.getDesktop();
File file = new File(TARGET);
desktop.open(file); }
Edit: #Bruno Lowagie. The hint with the template wrapped in an image sounds just right to me, and I changed the code according, but all I get now is an empty PDF. Am I doing something wrong, or is this the wrong approach alltogether?

If you want a table to fit a page, you should create the table before even thinking about page size and ask the table for its height as is done in the TableHeight example. Note that the getTotalHeight() method returns 0 unless you define the width of the table. This can be done like this:
table.setTotalWidth(width);
table.setLockedWidth(true);
Now you can create a Document with size Rectangle(0, 0, width + margin * 2, getTotalHeight() + margin * 2) and the table should fit the document exactly when you add it with the writeSelectedRows() method.
If you don't want a custom page size, then you need to create a PdfTemplate with the size of the table and add the table to this template object. Then wrap the template object in an Image and use scaleToFit() to size the table down.
public static void main(String[] args) throws DocumentException, FileNotFoundException, IOException {
String TARGET = "temp.pdf";
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(TARGET));
document.open();
PdfPTable table = new PdfPTable(7);
for (int i = 0; i < 700; i++) {
Phrase p = new Phrase("some text");
PdfPCell cell = new PdfPCell();
cell.addElement(p);
table.addCell(cell);
}
table.setTotalWidth(PageSize.A4.getWidth());
table.setLockedWidth(true);
PdfContentByte canvas = writer.getDirectContent();
PdfTemplate template = canvas.createTemplate(table.getTotalWidth(), table.getTotalHeight());
table.writeSelectedRows(0, -1, 0, table.getTotalHeight(), template);
Image img = Image.getInstance(template);
img.scaleToFit(PageSize.A4.getWidth(), PageSize.A4.getHeight());
img.setAbsolutePosition(0, (PageSize.A4.getHeight() - table.getTotalHeight()) / 2);
document.add(img);
document.close();
}

Related

How to reduce table cell size with image in it using iText

I have generated a pie char using JFreeCharts and have put it in Image of iText.
Later putting this image in table.
But the size of the cell is increasing even when the original image is not of that size. How can I reduce size of that cell.
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.io.FileOutputStream;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset;
import com.itextpdf.awt.PdfGraphics2D;
import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;
public class JFreeChartTest {
public static void main(String[] args) {
writeChartToPDF(generatePieChart(), 50, 50, "D://piechart5.pdf");
}
public static JFreeChart generatePieChart() {
DefaultPieDataset dataSet = new DefaultPieDataset();
dataSet.setValue("China", 30);
dataSet.setValue("India", 30);
dataSet.setValue("United States", 40);
JFreeChart chart = ChartFactory.createPieChart(
"", dataSet, false, true, false);
PiePlot piePlot = (PiePlot) chart.getPlot();
piePlot.setBackgroundPaint(Color.WHITE); //set background color white
piePlot.setOutlineVisible(false); // remove background border
piePlot.setLabelGenerator(null); // remove pie section labels
piePlot.setSectionPaint("China", Color.GRAY);
piePlot.setSectionPaint("India", Color.GREEN);
piePlot.setSectionPaint("United States", Color.BLUE);
piePlot.setShadowPaint(Color.WHITE);
return chart;
}
public static void writeChartToPDF(JFreeChart chart, int width, int height, String fileName) {
PdfWriter writer = null;
Document document = new Document();
try {
writer = PdfWriter.getInstance(document, new FileOutputStream(
fileName));
document.open();
PdfContentByte pdfContentByte = writer.getDirectContent();
PdfTemplate pdfTemplateChartHolder = pdfContentByte.createTemplate(50,50);
Graphics2D graphics2d = new PdfGraphics2D(pdfTemplateChartHolder,50,50);
Rectangle2D chartRegion = new Rectangle2D.Double(0,0,50,50);
chart.draw(graphics2d,chartRegion);
graphics2d.dispose();
Image chartImage = Image.getInstance(pdfTemplateChartHolder);
document.add(chartImage);
PdfPTable table = new PdfPTable(5);
// the cell object
// we add a cell with colspan 3
PdfPCell cellX = new PdfPCell(new Phrase("A"));
cellX.setBorder(com.itextpdf.text.Rectangle.NO_BORDER);
cellX.setRowspan(6);
table.addCell(cellX);
PdfPCell cellA = new PdfPCell(new Phrase("A"));
cellA.setBorder(com.itextpdf.text.Rectangle.NO_BORDER);
cellA.setColspan(4);
table.addCell(cellA);
PdfPCell cellB = new PdfPCell(new Phrase("B"));
table.addCell(cellB);
PdfPCell cellC = new PdfPCell(new Phrase("C"));
table.addCell(cellC);
PdfPCell cellD = new PdfPCell(new Phrase("D"));
table.addCell(cellD);
PdfPCell cellE = new PdfPCell(new Phrase("E"));
table.addCell(cellE);
PdfPCell cellF = new PdfPCell(new Phrase("F"));
table.addCell(cellF);
PdfPCell cellG = new PdfPCell(new Phrase("G"));
table.addCell(cellG);
PdfPCell cellH = new PdfPCell(new Phrase("H"));
table.addCell(cellH);
PdfPCell cellI = new PdfPCell(new Phrase("I"));
table.addCell(cellI);
PdfPCell cellJ = new PdfPCell(new Phrase("J"));
cellJ.setColspan(2);
cellJ.setRowspan(3);
cellJ.setImage(chartImage);
table.addCell(cellJ);
PdfPCell cellK = new PdfPCell(new Phrase("K"));
cellK.setColspan(2);
table.addCell(cellK);
PdfPCell cellL = new PdfPCell(new Phrase("L"));
cellL.setColspan(2);
table.addCell(cellL);
PdfPCell cellM = new PdfPCell(new Phrase("M"));
cellM.setColspan(2);
table.addCell(cellM);
document.add(table);
} catch (Exception e) {
e.printStackTrace();
}
document.close();
}
}
The two options coming to my mind are:
setting a fixed cell height and
adding the image to the cell wrapped in a Chunk using addElement.
The first option has one disadvantage: If the other cells in the same row require a larger height, a cell with a fixed size eventually also gets that larger height, and so would the image in the cell.
The second option does not have this disadvantage. One has to experiment a bit with the x and y offsets of the image in the chunk.
In the case of the OP the following values turned out to be good:
Chunk chunk = new Chunk(chartImage, 20, -50);
cellJ.addElement(chunk);

Merge pdf documents of different width using iText

I am having problem while merging documents of different width using iText.
Below is the code I'm using to merge.
public static void doMerge(List<InputStream> list, OutputStream outputStream) throws Exception {
Rectangle pagesize = new Rectangle(1700f, 20f);
com.itextpdf.text.Document document = new com.itextpdf.text.Document(pagesize);
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
document.setPageSize(pagesize);
com.itextpdf.text.pdf.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
com.itextpdf.text.pdf.PdfImportedPage page = writer.getImportedPage(reader, i);
//calculate the y for merging it from top
float y = document.getPageSize().getHeight() - page.getHeight();
//add the page to the destination pdf
cb.addTemplate(page, 0, y);
}
reader.close();
in.close();
}
outputStream.flush();
document.close();
outputStream.close();
}
First page of pdf will be of 14 inch of width and 13 inch of height. All the other pages on document will be always smaller than it.
I want to merge all the documents altogether in a single document.
I don't know how to set a width and height of a single merged document.
I think Rectangle pagesize = new Rectangle(1700f, 20f); should do it but it's not working means if change it to Rectangle pagesize = new Rectangle(1700f, 200f);, document has no effect.
Please guide me further.
Using the PdfWriter class to merge documents goes against all the recommendations given in the official documentation, though there are unofficial examples that may have lured you into writing bad code. I hope that you understand that I find these bad examples even more annoying than you do.
Please take a look at Table 6.1 in chapter 6 of my book. It gives you an overview showing when to use which class. In this case, you should use PdfCopy:
String[] files = { MovieLinks1.RESULT, MovieHistory.RESULT };
// step 1
Document document = new Document();
// step 2
PdfCopy copy = new PdfCopy(document, new FileOutputStream(RESULT));
// step 3
document.open();
// step 4
PdfReader reader;
int n;
// loop over the documents you want to concatenate
for (int i = 0; i < files.length; i++) {
reader = new PdfReader(files[i]);
// loop over the pages in that document
n = reader.getNumberOfPages();
for (int page = 0; page < n; ) {
copy.addPage(copy.getImportedPage(reader, ++page));
}
copy.freeReader(reader);
reader.close();
}
// step 5
document.close();
If you are using a recent version of iText, you can even use the addDocument() method in which case you don't need to loop over all the pages. You also need to take special care if forms are involved. There are several examples demonstrating the new functionality (dating from after the book was written) in the Sandbox.
with the itext version 5.5 we can merge pdf more easly using the method PdfCopy.addDocument :
package tn.com.sf.za.rd.controller;
import java.io.FileOutputStream;
import java.io.IOException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
public class ReportMerging {
public static void main(String[] args) throws DocumentException, IOException {
String DOC_ONE_PATH = "D:/s.zaghdoudi/tmp/one.pdf";
String DOC_TWO_PATH = "D:/s.zaghdoudi/tmp/two.pdf";
String DOC_THREE_PATH = "D:/s.zaghdoudi/tmp/three.pdf";
Document document = new Document();
PdfCopy copy = new PdfCopy(document, new FileOutputStream(DOC_THREE_PATH));
document.open();
PdfReader readerOne = new PdfReader(DOC_ONE_PATH);
PdfReader readerTwo = new PdfReader(DOC_TWO_PATH);
copy.addDocument(readerOne);
copy.addDocument(readerTwo);
document.close();
}
}

Using iText to create PDF

I'm trying to create a PDF using iText and I'm having a great deal of difficulty. In short, what I want to do is:
Read in a template pdf
Make a copy in memory of the template
Draw a table on the copy
Write the copy pdf to an outputstream
So far, it's looking like this
// read in template pdf
InputStream templateStream = getServletContext().getResourceAsStream(labelsTemplate);
PdfReader reader = new PdfReader(templateStream);
// create a table in a new document
Document document = new Document();
PdfCopy copy = new PdfCopy(document, os);
document.open();
PdfPTable table = new PdfPTable(2);
PdfPCell cell;
cell = new PdfPCell(new Phrase("row 1; cell 1"));
table.addCell(cell);
cell = new PdfPCell(new Phrase("row 1; cell 2"));
table.addCell(cell);
document.add(table);
Can someone explain how I can make a copy of the template once I've used PdfReader to read it? Is there a way to write the table onto the template copy and not a new document?
For future references, here's what I've done:
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "inline;filename=\"scheduler-labels.pdf\"");
ServletOutputStream os = response.getOutputStream();
// read in template pdf
InputStream templateStream = getServletContext().getResourceAsStream(labelsTemplate);
PdfReader reader = new PdfReader(templateStream);
// make new pdf document to draw table and output to memory
Document document = new Document(reader.getPageSize(1));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter.getInstance(document, baos);
// write table
document.open();
PdfPTable table = new PdfPTable(2);
table.setWidthPercentage(110);
PdfPCell cell;
cell = new PdfPCell(new Phrase("row 1; cell 1"));
table.addCell(cell);
cell = new PdfPCell(new Phrase("row 1; cell 2"));
table.addCell(cell);
cell = new PdfPCell(new Phrase("row 2; cell 1"));
table.addCell(cell);
cell = new PdfPCell(new Phrase("row 2; cell 2"));
table.addCell(cell);
document.add(table);
document.close();
// read in newly generated table pdf
PdfReader tableReader = new PdfReader(baos.toByteArray());
ByteArrayOutputStream baosCombined = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(tableReader, baosCombined);
// get a page from the template pdf
PdfImportedPage page = stamper.getImportedPage(reader, 1);
// add to background of table pdf
PdfContentByte background;
background = stamper.getUnderContent(1);
background.addTemplate(page, 0, 0);
stamper.close();
tableReader.close();
reader.close();
// write to servlet output
baosCombined.writeTo(os);
os.flush();
os.close();
As studying the sample referenced in my comment was just what [Tuan] needed, I formulate it as an answer:
The sample Stationery.java from chapter 6 of iText in Action — 2nd Edition essentially shows how to use the contents of a given PDF as background (stationery-like) of a new PDF while filling its foreground with new content.
The central code is as follows:
public class Stationery extends PdfPageEventHelper
{
[...]
public void createPdf(String filename) throws Exception
{
// step 1
Document document = new Document(PageSize.A4, 36, 36, 72, 36);
// step 2
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filename));
useStationary(writer);
// step 3
document.open();
// step 4
[... add content to PDF ...]
// step 5
document.close();
}
[...]
public void useStationary(PdfWriter writer) throws IOException
{
writer.setPageEvent(this);
PdfReader reader = new PdfReader(STATIONERY);
page = writer.getImportedPage(reader, 1);
}
public void onEndPage(PdfWriter writer, Document document)
{
writer.getDirectContentUnder().addTemplate(page, 0, 0);
}
[...]
}
As implicit close() calls have been removed more and more recently, the PdfReader reader instantiated in useStationary nowerdays should be stored in some variable of Stationery and closed after createPdf has executed.

how to insert text into a scanned pdf document using java

I have to add text to pdf documents where there are many scanned pdf documents so the inserted text is inserted back to the scanned image and not over the image. how to add text over the scanned image inside the pdf.
package editExistingPDF;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;
import org.apache.commons.io.FilenameUtils;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
public class AddPragraphToPdf {
public static void main(String[] args) throws IOException, DocumentException, BiffException {
String tan = "no tan";
File inputWorkbook = new File("lars.xls");
Workbook w;
w = Workbook.getWorkbook(inputWorkbook);
// Get the first sheet
Sheet sheet = w.getSheet(0);
Cell[] tnas =sheet.getColumn(0);
File ArticleFolder = new File("C:\\Documents and Settings\\sathishkumarkk\\My Documents\\article");
File[] listOfArticles = ArticleFolder.listFiles();
for (int ArticleInList = 0; ArticleInList < listOfArticles.length; ArticleInList++)
{
Document document = new Document(PageSize.A4);
// System.out.println(listOfArticles[ArticleInList].toString());
PdfReader pdfArticle = new PdfReader(listOfArticles[ArticleInList].toString());
if(listOfArticles[ArticleInList].getName().contains(".si."))
{continue;}
int noPgs=pdfArticle.getNumberOfPages();
String ArticleNoWithOutExt = FilenameUtils.removeExtension(listOfArticles[ArticleInList].getName());
String TanNo=ArticleNoWithOutExt.substring(0,ArticleNoWithOutExt.indexOf('.'));
// Create output PDF
PdfWriter writer = PdfWriter.getInstance(document,new FileOutputStream("C:\\Documents and Settings\\sathishkumarkk\\My Documents\\toPrint\\"+ArticleNoWithOutExt+".pdf"));
document.open();
PdfContentByte cb = writer.getDirectContent();
//get tan form excel sheet
System.out.println(TanNo);
for(Cell content : tnas){
if(content.getContents().contains(TanNo)){
tan=content.getContents();
System.out.println(tan);
}else{
continue;
}
}
// Load existing PDF
//PdfReader reader = new PdfReader(new FileInputStream("1.pdf"));
for (int i = 1; i <= noPgs; i++) {
PdfImportedPage page = writer.getImportedPage(pdfArticle, i);
// Copy first page of existing PDF into output PDF
document.newPage();
cb.addTemplate(page, 0, 0);
// Add your TAN here
Paragraph p= new Paragraph(tan);
Font font = new Font();
font.setSize(1.0f);
p.setLeading(12.0f, 1.0f);
p.setFont(font);
document.add(p);
}
document.close();
}
}
}
NOTE: The problem is that when there is a pdf create with only text I have no problem but when a pdf is with full of scanned document and when I try to add text; it gets added to the back of the scanned document. so while I print those pdf I will not get those text I added.
From this iText Example (which is the reverse of what you want, but switch getUnderContent with getOverContent and you'll be fine) :
Blockquote
Each PDF page has two extra layers; one that sits on top of all text / graphics and one that goes to the bottom. All user added content gets in-between these two. If we get into this bottommost content, we can write anything under that we want. To get into this bottommost layer, we can use the " getUnderContent" method of PdfStamper object.
This is documented in iText API Reference as shown below:
public PdfContentByte getUnderContent(int pageNum)
Gets a PdfContentByte to write under the page of the original document.
Parameters:
pageNum - the page number where the extra content is written
Returns:
a PdfContentByte to write under the page of the original document
To do this, you will need to first read in the PDF document, extract the elements and then add text to the document and resave it as a PDF document. This of course assumes that you can read the PDF document in the first place.
I'd recommend iText (see Example Code iText) to help you do this.

File not found when inserting image file into PDF using itext

How to add images and design header, footer to pdf using itext?
I have written this ,but getting exception file not found.
Image image = Image.getInstance("\resources\image.gif");
thanks
I used the following code to insert an image from the classpath. Typically useful when you need to include an image that is not accessible from a public url.
Image img = Image.getInstance(getClass().getClassLoader().getResource("MyImage.jpg"));
In my case, I use maven, so I put MyImage.jpg in src/main/resources
take a look at this example
import java.io.*;
import com.lowagie.text.*;
import com.lowagie.text.pdf.*;
public class CreatePDF{
public static void main(String arg[])throws Exception{
try{
Document document=new Document();
FileOutputStream fos=new FileOutputStream("C:/header-footer.pdf");
PdfWriter writer = PdfWriter.getInstance(document, fos);
document.open();
Image image1 = Image.getInstance("C:/image1.jpg");
Image image2 = Image.getInstance("C:/image2.jpg");
image1.setAbsolutePosition(0, 0);
image2.setAbsolutePosition(0, 0);
PdfContentByte byte1 = writer.getDirectContent();
PdfTemplate tp1 = byte1.createTemplate(600, 150);
tp1.addImage(image2);
PdfContentByte byte2 = writer.getDirectContent();
PdfTemplate tp2 = byte2.createTemplate(600, 150);
tp2.addImage(image1);
byte1.addTemplate(tp1, 0, 715);
byte2.addTemplate(tp2, 0, 0);
Phrase phrase1 = new Phrase(byte1 + "", FontFactory.getFont(FontFactory.TIMES_ROMAN, 7, Font.NORMAL));
Phrase phrase2 = new Phrase(byte2 + "", FontFactory.getFont(FontFactory.TIMES_ROMAN, 7, Font.NORMAL));
HeaderFooter header = new HeaderFooter(phrase1, true);
HeaderFooter footer = new HeaderFooter(phrase2, true);
document.setHeader(header);
document.setFooter(footer);
document.close();
System.out.println("File is created successfully showing header and footer.");
}
catch (Exception ex){
System.out.println(ex);
}
}
}

Categories