I created a table with iText 5.5.13.2 (latest iText5 version) and I’m filling it with text and images that are read from a specific folder on the same PC:
Paragraph p = new Paragraph(); p.add(new Phrase("This is a new paragraph!")); PdfPTable table = new PdfPTable(2); table.setWidthPercentage(100); for(int i=0;i<imageArr.size();i++) { //imageArr.size()%2==0! PdfPCell cell = new PdfPCell(); String name = imageArr.get(i); String path = imgFolder + File.separator + name; File f = new File(path); if(f.isFile()) { Image img = Image.getInstance(path); //cell.setCalculatedHeight(50); cell.addElement(img); } else { cell.addElement(new Phrase(name)); } cell.setVerticalAlignment(Element.ALIGN_MIDDLE); cell.setHorizontalAlignment(Element.ALIGN_MIDDLE); //cell.setCalculatedHeight(50); table.addCell(cell); } p.add(table); doc.add(p);
Both columns in the table use the same width (which is great) and big images are automatically resized to fit the width (which is also great), the only thing that’s not working:
The cells should all be a certain height and the big images should resize accordingly (while still keeping the proper height/width ratio). It doesn’t seem to matter if I use setCalculatedHeight
before or after I add the image to the cell (only doing one or the other, see code above), the cell always sets its height according to the image’s height, so rows with only text or images in landscape format are always smaller than rows with images in portrait format.
Small images are also resized (stretched), even while using img.setScaleToFitLineWhenOverflow(false)
and img.setScaleToFitHeight(false)
, but even then the height isn’t set properly.
I already tried to use a Chunk
(cell.addElement(new Chunk(img, 0, 0))
) but then the images are tiny and my height setting is still ignored.
How do I set the cell’s height and make the images resize accordingly?
Advertisement
Answer
I managed to find a solution. A lot of testing was involved and even now I’m not 100% sure why it was behaving the way it did most of the time.
First of all: Do not add the element with addElement
because once you call this with a PdfPCell
, iText switches from “Text Mode” (seems to affect images too) to “Composite Mode” and from then on ignores all the alignment,… settings for that cell, including horizontal alignment for text – you can find a more detailed explanation by the original iText developer here (with examples here). Instead do whatever you want to do with the Image
first and only then create the PdfPCell
with that image. Afterwards the cell can be edited – using the table.getDefaultCell()
won’t work though, the changes to it won’t have any effect on the cells created with the code below.
My working code:
float docWidth = doc.getPageSize().getWidth() - doc.leftMargin() - doc.rightMargin(); float docHeight = doc.getPageSize().getHeight() - doc.topMargin() - doc.bottomMargin(); float docWidthDiv2 = docWidth/2 - 10; float docHeightDiv2 = docHeight/2 - 10; PdfPCell cell = null; if(f.isFile()) { Image img = Image.getInstance(path); //img.scaleAbsolute(100, 50); if(img.getWidth() < docWidthDiv2 && img.getHeight < docHeightDiv2) { cell = new PdfPCell(img, false); } else { cell = new PdfPCell(img, true); } } else { cell = new PdfPCell(new Phrase(name)); } cell.setFixedHeight(50); //"setCalculatedHeight" doesn't work
Why do I compare the image’s width to docWidthDiv2
and the image’s height to docHeightDiv2
?
There are a lot of combinations for setting the cell’s height but none show 100% of the behavior I expected: Really big images should be scaled down to fit the width of the column (more important for images in landscape mode) but also respect the cell’s fixed height (more important for images in portrait mode), while still keeping their aspect ratio. Small images that already fit the cell comfortably should not be scaled at all.
The documentation for new PDfPCell(Image image, boolean fit)
describes the fit
parameter with:
true
to fit the image to the cell
In my case true
resizes the image (while still respecting its aspect ratio and the cell’s height) until it touches two opposite sides of the cell, hence: Big images are reduced in size and small images are stretched.
With false
the aspect ratio of the image and the cell’s height are still respected but while small images keep their size, big images in landscape mode “bleed” into the neighboring cell (and setScaleToFitLineWhenOverflow
doesn’t help) and big images in portrait mode might not even be displayed at all (when they’re too tall for the cell).
To not stretch small images but decrease the size of big images, a combination of both is needed. I only added the -10
, so a potential default padding won’t mess with it. If you want to add text before or after the table, then you have to deduct its height from docHeightDiv2
too.
As mentioned, there are also other combinations I tested, the most important information I took away from it:
If the cell’s height is set before the image is added, then the image’ll overwrite the height, no matter if it’s smaller (cell shrinks in height) or bigger (cell’s height increases) than the cell.
There are a couple of combinations that can be used, between the parameter, setting the image size and setting the cell’s height but with most of them the images either keep their original size (e.g. 2000×1000 won’t be completely visible on the page) or they’re increased in size until they touch two opposite sides of the cell (which also increases the height of the cell). In the end there’s only one combination left that’s still useful (in my opinion) – an example:
img.scaleAbsolute(100, 50); cell = new PdfPCell(img, false); cell.setVerticalAlignment(Element.ALIGN_MIDDLE); //"center" doesn't work here cell.setHorizontalAlignment(Element.ALIGN_CENTER); //"middle" doesn't work here cell.setFixedHeight(150);
This’ll create an image with a size of 100×50 (the original aspect ratio is ignored) in the center of a cell that’s 150 units tall (= padding of 50 units above and below the image).
Additional information about iText’s table:
Columns share the available width of the table equally and there’s no need to change it, even if the first cell contains a really small image and the second a really big one. The only thing that you have to pay attention to, in that regard, is the number of cells that are added – rows always have to be completely filled, so a table with 3 columns has to contain 3 cells per row, otherwise that row won’t be printed into the pdf file (the same way an empty new page also won’t be printed). It’s possible to create empty extra cells to fill the rest of the row:
PdfPCell extra = new PdfPCell(); extra.setFixedHeight(50); table.addCell(extra);