iText Tutorial SourceForge.net Logo iText, a Free Java-PDF library
by
Bruno Lowagie
[Home] [Previous] [TOC] [Next] [PDF]

Part I: Simple iText

Chapter 6: Images
Remark: in contrast to some other PDF libraries, there are no special X requirements for running iText on a Unix box, except when you are adding a java.awt.Image.

The Image object
If you study the API, you will notice that there are several constructors you can use to create an image. However in this tutorial, we will only look at the most simple solution, i.e. by asking the Image object an instance of an Image identified by an URL or a filename:
public static Image getInstance(URL url)
   throws BadElementException, MalformedURLException, IOException
public static Image getInstance(String filename)
   throws BadElementException, MalformedURLException, IOException


Image is an abstract class, so the getInstance method will detect the type of the given image (GIF, Jpeg, PNG,...) and return an object of type Gif, Jpeg, Png,... Some images will be rejected, please consult the FAQ if you have questions about rejected images.

Getting an instance of an image using an URL
This is the most simple way to add an Image. In example 1, we add a WMF (a Windows Meta File 33kByte), a GIF (a picture of SF-writer Kurt Vonnegut 26 kByte), a Jpeg (a picture of my children 7 kByte) and a PNG (a picture of Alfred Hitchcock 16 kByte) to the document, using 3 URLs referring to my site:
Image wmf = Image.getInstance(new URL("../examples/harbour.wmf"));
Image gif = Image.getInstance(new URL("../examples/vonnegut.gif"));
Image jpeg = Image.getInstance(new URL("../examples/myKids.jpg"));
Image png = Image.getInstance(new URL("../examples/hitchcock.png"));

The resulting PDF file is 74 kByte: it contains the image data of the 4 images. The resulting HTML file is 1 kByte: it contains the references to the urls of the 4 images.

Remark:
Lots of PDF libraries decompress images and change them into a Bitmap-like format before adding them to the PDF-file. There are several reasons why I avoided such an approach:
  • This results in huge PDF files. The size of the resulting file is tens of times larger than the sum of the different images.
  • In order to be able to use such a library, you often need to change some UNIX configurations (X11).
  • There is a legal problem: the LZW-algorithm is patented, so I was not allowed to use this algorithm to decompress GIF-files.
I found it much easier to copy the bits of the image file into the PDF file instead of decompressing/compressing the image data (thus avoiding all practical, technical and legal problems).

Getting an instance of an image using a filename
We can change example 1 into example 2 by simply changing the way images are instanciated:
Image gif = Image.getInstance("vonnegut.gif");
Image jpeg = Image.getInstance("myKids.jpg");
Image png = Image.getInstance("hitchcock.png");

The resulting PDF file is identical to the one in example 1, but there is a big difference in the resulting HTML file.
If we study the source code, we can immediately see what causes the problem:
<IMG BORDER="0" HEIGHT="149" SRC="file:/D:/cvs/lib/vonnegut.gif" WIDTH="198">
I generated the HTML file on the D:-drive of my NT workstation and afterwards I put this file on my LINUX webserver. It is evident that the links to my local D:-drive are broken (or isn't it: I see lots of similar errors on amateur webpages).
You can avoid this problem by telling the HtmlWriter to use a given basepath for images:
HtmlWriter writer = HtmlWriter.getInstance(document, new FileOutputStream("Chap0603.html"));
writer.setImagepath("../../images/kerstmis/");

In this example, we tell the writer to use a relative path (in this case the path to some Christmas photo's) for every image we add. This is the resulting PDF and HTML.


Positioning the Image
alignment
An image can be aligned, using the method
setAlignment(Image.RIGHT)
setAlignment(Image.MIDDLE)
setAlignment(Image.LEFT)
See example 4 and the resulting PDF: we added the picture of Vonnegut to the right, the picture of my children in the middle and hitchcock to the left.

Images and text
But there's more, you can also specify that text has to be wrapped around the image (see example 5 and the resulting PDF):
setAlignment(Image.RIGHT | Image.TEXTWRAP)
setAlignment(Image.MIDDLE)
setAlignment(Image.LEFT | Image.UNDERLYING)
The text is wrapped on the left side of the Vonnegut-picture, isn't wrapped around the picture of my children and is written over the Hitchcock-image.
Remark: these functionalities still have a lot of bugs.

Absolute positions
When generating PDF-files, you can use the method
public void setAbsolutePosition(int absoluteX, int absoluteY)
to place an image at an absolute position on a page. In example 6 we add two pictures at different coordinates. In the resulting PDF, you can see that the given coordinates are used to position the lowerleft corner of the image. We took the width and height of the image as x- and y-coordinate for the first image and two times these values for the second.


Scaling and Rotating the Image
Scaling
There are several possibilities to scale an image:
public void scaleAbsolute(int newWidth, int newHeight)
public void scalePercent(int percent)
public void scalePercent(int percentX, int percentY)
public void scaleToFit(int fitWidth, int fitHeight)
The picture of my children is 194x202 pixels. If I wanted to make this picture smaller I could scale it using scaleAbsolute(97, 101), but using scalePercent(50) would have the same effect.
I could also reduce it like this: scaleAbsolute(194, 101), this would be the same as doing this: scalePercent(100, 50). All these examples are bundled in example 7, which results in this PDF-document.
Finally, there is also the ScaleToFit-method. This method is used in the Calendar-class. It reduces the image, preserving the original aspect ratio. In the Calendar-application, this method is used to allow you to put images of different size on each Calendar-page. They are all resized to Fit on a certain area of the page.

Impact on the resolution
If an image is placed without any scaling the the resolution will be 72. If an image is placed with a scaling of 50% the the resolution will be 144. With lower scalings the resolution will increase because the pixels are the same but the size will be smaller. To put a picture with 300dpi use a scaling of 72/300=24%. For instance: if you have a 5X5 inch image that you scan at 300 dpi, the resultant image is 1500X1500 pixels (5X300 = 1500). When you place this image in the pdf with a scaling of 24% (72/300 = 0.24), the image in the pdf will be 5X5 inch with 1500X1500 pixel at 300 dpi. The image will always be 1500X1500 pixel whatever the size.

Rotating
With the following method, you can rotate images:
public void setRotation(double r)
This method is demonstrated in example 8 (see result).


Raw Image data
Uptil now all examples used images that were stored on your harddisk or that were retrieved from some webserver, but it is also possible to get an instance of an image using an array of bytes containing the image data:
public static Image getInstance(byte[] img)
This method has the same effect as the other getInstance-methods discussed earlier: it returns a new Image-object of type Gif, Jpeg or Png.
In example 9, we first add an image that was read from a jpeg-file into an array of bytes. It is evident that in this case it is better to use another getInstance-method, but this is just an example. This getInstance-method is especially useful when you have images that were created 'on the fly', images that were never saved to a file as such.
The example also demonstrates how you can create a Raw Image and use:
public static Image getInstance(int width, int height, int components, int bpc, byte data[])
In the example an image of 100 by 100 pixels is created. The images is 100 x 100 x 3 bytes large, because every pixels is described by a RGB-value. You can see the result of the algorithm in file Chap0609.pdf.


java.awt.Image
Example 10 is a very advanced example for three reasons:
  1. In the first place the class java.awt.Image is used. This is a class in the JDK and it can be used for a big variety of image-types, for instance TIFF-files, GIF-files that are on the iText list of not supported images,... You will have to check the JDK to see if the image type you need is supported.
  2. Also there is something you may have noticed in the previous examples: it doesn't matter when you add an image, the text is allways on top of your image. In this example we want the image to be on top of the text. That's why we are going to use the class com.lowagie.text.pdf.PdfContentByte (this class will be explained in Chapter 10).
  3. Finally, you will notice that the image used in this example is a transparent gif. Check out the resulting PDF-file.
TIFF and CCITT
Example 11 and example 12 are also rather advanced. These examples convert two tiff-files: 338814-00.tif and 12.tif into a PDF file: Chap0612.pdf and Chap0612.pdf. You need the Java Advanced Imaging API from SUN in order to compile and execute these examples. More specific: you need to add two extra jars to your classpath: jai_codec.jar and jai_core.jar. You can find these jars at http://java.sun.com/.

Image masks
In example 13, we create an image that can be used as mask:
                                        3C
                7E
                E7
                C3
                C3
                E7
                7E
                3C

This image has a size of 8 by 8 pixels, 1 component and 1 byte per component. Using the method makeMask(), it can be turned into a mask:

byte maskr[] = {(byte)0x3c, (byte)0x7e, (byte)0xe7, (byte)0xc3, (byte)0xc3, (byte)0xe7, (byte)0x7e, (byte)0x3c};
Image mask = Image.getInstance(8, 8, 1, 1, maskr);
mask.makeMask();
mask.setInvertMask(true);

We can use this mask for explicit masking to clip some parts of an image:

PdfContentByte cb = writer.getDirectContent();
Image image = Image.getInstance("vonnegut.gif");
image.setImageMask(mask);

Or we can use this mask for stencil masking:

PdfContentByte cb = writer.getDirectContent();
cb.setRGBColorFill(255, 0, 0);
cb.addImage(mask, mask.scaledWidth() * 8, 0, 0, mask.scaledHeight() * 8, 100, 400);

Please take a look at the resulting PDF.
(for more info on the ContentByte-object read Chapter 10).


Images and other objects
Images inside a Chunk
In some cases it can be handy to wrap an image inside a Chunk. Just create a Chunk with an image and an offset:
Chunk ck = new Chunk(img, 0, -5);
As you can see in example 14 and the resulting PDF, we can add this special image chunk to a phrase, a table,...

Images inside a Table
You can add an image to a Cell, but because of the technical complexity, you have to take two side-effects into account:
  • The width of a Table is calculated internally. If an image doesn't fit the cell, the image is 'scaled-to-fit' automatically.
  • You can't use Image.TEXTWRAP or Image.UNDERLYING.
See example 15 (Chap0615.pdf).

Annotations and images
If you want a clickable image or you want to add an annotation to an image, you have to construct an Annotation-object and add it to the image. You don't need to specify a position (you can take 0, 0, 0, 0). The position will be internally updated to fit the image:
gif.setAnnotation(new Annotation(0, 0, 0, 0, "Chap1102b.pdf", 3));
jpeg.setAnnotation(new Annotation("picture", "These are my children", 0, 0, 0, 0));

This is demonstrated inexample 16 (Chap0616.pdf).




[Top] [Previous] [TOC] [Next] [PDF]
Page Updated: $Date: 2003/06/25 07:36:35 $
Copyright © 2000, 2001 by Bruno Lowagie
Adolf Baeyensstraat 121, 9040 Gent, BELGIUM,
tel +00 32 92 28 10 97 mailto:itext-questions@lists.sourceforge.net