Colours, Images & SVG

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

Everything a Bookshelf Billing invoice shows that is not text comes from this page: the brand colour of the heading, the shop logo, a QR code, and the sales chart on a monthly statement. iText models all of it with a small number of types. A colour is a Color object, whose subclasses name the PDF colour space. A bitmap is an ImageData loaded by ImageDataFactory, wrapped in a layout Image when it flows with the text. A vector drawing is an SVG document converted by the svg module into a form XObject (a reusable group of drawing operators, see How a PDF File Works).

Versions are stated as of 2026-10-09: iText Core 9.8.0 on Java 21. Every example below was compiled and run against that version, and the resulting PDFs were rendered to check them. Where the iText Knowledge Base tutorials still show an older API, the examples follow the API as compiled in 9.8.0.

The iText modules used here (kernel, io, layout and svg) are part of the itext-core aggregator and are licensed under the AGPLv3 or under a commercial licence from Apryse. For a closed-source service, the AGPL obliges you to offer the source to users who interact with it over the network, so a commercial licence is needed. The licensing consequences are discussed in Introduction & Approaches.

Maven coordinates

The same coordinates as in Getting Started with Spring Boot are used. itext-core is a POM aggregator, so it must be declared with <type>pom</type>. The Bouncy Castle adapter is only required for signing and encryption, so these examples do not need it, but it is harmless to keep it on the classpath.

<properties>
    <maven.compiler.release>21</maven.compiler.release>
    <itext.version>9.8.0</itext.version>
</properties>

<dependencies>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itext-core</artifactId>
        <version>${itext.version}</version>
        <type>pom</type>
    </dependency>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>bouncy-castle-adapter</artifactId>
        <version>${itext.version}</version>
    </dependency>
</dependencies>

See Installing iText for Java in the iText Knowledge Base.

Colour spaces

A PDF colour is always interpreted in a colour space, and the choice matters when the file reaches a printer. iText exposes the colour spaces as subclasses of com.itextpdf.kernel.colors.Color:

Class PDF colour space Typical use

DeviceRgb

DeviceRGB, three components

Screen output: brand colours, links, table stripes. Constructed from 0-255 integers or from 0-1 floats.

DeviceCmyk

DeviceCMYK, four components

Print workflows. A pure black text in CMYK should be K = 1 and the others 0, so that it prints with one ink only.

DeviceGray

DeviceGray, one component

Black and white documents, secondary text, borders.

CalRgb, CalGray, Lab, IccBased

Calibrated spaces

Colour-managed output. PDF/A and PDF/X accept device colours only together with an output intent, see PDF Standards & Conformance.

PatternColor

Pattern

Tiling patterns and shadings, see below.

DeviceN, Color.makeColor(PdfSpecialCs.Separation, ...)

Spot colours

A named ink such as a Pantone colour, see below.

ColorConstants offers thirteen named colours (ColorConstants.RED, ColorConstants.LIGHT_GRAY, …​). Conversion between the device spaces is available as Color.convertRgbToCmyk and Color.convertCmykToRgb; these are the naive mathematical conversions and do not apply an ICC profile, so they are not suitable for colour-critical printing.

Colouring text, backgrounds and borders

On layout elements the colour is a property: setFontColor, setBackgroundColor and setBorder (with a Border that carries its own colour). The same Color objects are used on the low-level PdfCanvas through setFillColor and setStrokeColor.

Old code written against iText 1 to 5, including the examples in the book B1, used java.awt.Color or BaseColor, and applied colours through Chunk and setBackground. In iText 7 and later those classes are gone: use Color and its device subclasses, as in the example below. The same applies to Chunk, whose role is now played by the Text element.

Spot colours with the Separation colour space

A spot colour is a named ink that the printer reproduces with a dedicated plate, such as a corporate orange. In PDF it is a Separation colour space with three parts: the ink name, an alternate space used by viewers that cannot render the ink, and a tint transformation function that maps a tint from 0 (no ink) to 1 (full ink) onto the alternate space. iText provides PdfSpecialCs.Separation, and a Type 2 (exponential interpolation) function in PdfType2Function is enough for the usual one-ink case. Tints are then applied with Color.makeColor(separation, new float[] {tint}).

Patterns and gradients

A tiling pattern repeats a small piece of drawing to fill an area. In iText it is a PdfPattern.Tiling, drawn with a PdfPatternCanvas, and used by wrapping it in a PatternColor, which can then be passed to setFillColor like any other colour. The second constructor argument of the tiling selects a coloured pattern (the pattern draws its own colours) or an uncoloured one (the pattern is a stencil and the colour is supplied when it is used).

Gradients are PdfPattern.Shading objects at the PDF level, and iText 8 and 9 add builders so that they can be described the way CSS does. StrategyBasedLinearGradientBuilder and LinearGradientBuilder produce linear gradients, with colour stops (GradientColorStop) and a spread method (PAD, REFLECT, REPEAT). iText 9.8 adds radial gradients (StrategyBasedRadialGradientBuilder and RadialGradientBuilder), where the centre and radius can be given explicitly or by one of the CSS strategies (CLOSEST_SIDE, FARTHEST_CORNER, …​). A built gradient is attached to an element as a BackgroundImage, or turned into a colour with buildColor, and for a hand-made shading PdfCanvas.paintShading and setFillColorShading are the low-level entry points.

import com.itextpdf.kernel.colors.Color;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.colors.DeviceCmyk;
import com.itextpdf.kernel.colors.DeviceGray;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.colors.PatternColor;
import com.itextpdf.kernel.colors.gradients.GradientColorStop;
import com.itextpdf.kernel.colors.gradients.GradientSpreadMethod;
import com.itextpdf.kernel.colors.gradients.StrategyBasedLinearGradientBuilder;
import com.itextpdf.kernel.colors.gradients.StrategyBasedRadialGradientBuilder;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.PdfPatternCanvas;
import com.itextpdf.kernel.pdf.colorspace.PdfDeviceCs;
import com.itextpdf.kernel.pdf.colorspace.PdfPattern;
import com.itextpdf.kernel.pdf.colorspace.PdfSpecialCs;
import com.itextpdf.kernel.pdf.function.PdfType2Function;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Div;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Text;
import com.itextpdf.layout.properties.BackgroundImage;

import java.io.IOException;

public class ColorExamples {

    public static void main(String[] args) throws IOException {
        try (PdfDocument pdf = new PdfDocument(new PdfWriter("colors.pdf"));
             Document document = new Document(pdf)) {

            // 1. Device colour spaces: RGB, CMYK (0..1 floats or 0..255 ints) and gray.
            document.add(new Paragraph("Bookshelf Billing: colours").setFontSize(18));
            document.add(new Paragraph()
                    .add(new Text("Brand RGB ").setFontColor(new DeviceRgb(0x1F, 0x4E, 0x79)))
                    .add(new Text("Print CMYK ").setFontColor(new DeviceCmyk(1f, 0.6f, 0f, 0.4f)))
                    .add(new Text("Secondary gray ").setFontColor(new DeviceGray(0.4f)))
                    .add(new Text("Highlighted").setBackgroundColor(ColorConstants.YELLOW)));

            // 2. A spot colour: Separation space with a Type 2 tint transformation (white -> spot ink).
            PdfSpecialCs.Separation brandInk = new PdfSpecialCs.Separation(
                    "BOOKSHELF ORANGE",
                    new PdfDeviceCs.Cmyk(),
                    new PdfType2Function(new float[]{0, 1}, null,
                            new float[]{0f, 0f, 0f, 0f},      // tint 0.0 = no ink
                            new float[]{0f, 0.65f, 1f, 0f},   // tint 1.0 = CMYK fallback
                            1));
            Color orange = Color.makeColor(brandInk, new float[]{1f});
            Color lightOrange = Color.makeColor(brandInk, new float[]{0.3f});
            document.add(new Paragraph()
                    .add(new Text("Spot 100 % ").setFontColor(orange))
                    .add(new Text("Spot 30 %").setFontColor(lightOrange)));

            // 3. Linear and radial gradients as CSS-like background images (radial since 9.8).
            StrategyBasedLinearGradientBuilder linear = new StrategyBasedLinearGradientBuilder()
                    .setGradientDirectionAsCentralRotationAngle(90);
            linear.addStopColor(new GradientColorStop(new float[]{0.12f, 0.31f, 0.47f}));
            linear.addStopColor(new GradientColorStop(new float[]{0.95f, 0.6f, 0.1f}));
            linear.setSpread(GradientSpreadMethod.PAD);
            document.add(new Div()
                    .setHeight(60).setWidth(300)
                    .setBackgroundImage(new BackgroundImage.Builder().setLinearGradientBuilder(linear).build()));
            document.add(new Paragraph(" "));
            StrategyBasedRadialGradientBuilder radial = new StrategyBasedRadialGradientBuilder()
                    .setRadiusFromCenterStrategy(true,
                            StrategyBasedRadialGradientBuilder.GradientStrategy.FARTHEST_CORNER);
            radial.addStopColor(new GradientColorStop(new float[]{1f, 1f, 1f}));
            radial.addStopColor(new GradientColorStop(new float[]{0.12f, 0.31f, 0.47f}));
            document.add(new Div()
                    .setHeight(80).setWidth(300)
                    .setBackgroundImage(new BackgroundImage.Builder().setGradientBuilder(radial).build()));

            // 4. A coloured tiling pattern used as a fill colour.
            PdfPattern.Tiling dots = new PdfPattern.Tiling(10, 10, true);
            new PdfPatternCanvas(dots, pdf)
                    .setFillColor(new DeviceRgb(0.12f, 0.31f, 0.47f))
                    .circle(5, 5, 2)
                    .fill();
            PdfCanvas canvas = new PdfCanvas(pdf.getFirstPage());
            canvas.setFillColor(new PatternColor(dots))
                    .rectangle(new Rectangle(36, 36, 200, 60))
                    .fill();
            canvas.release();
        }
    }
}

The example writes colors.pdf with, from top to bottom, RGB, CMYK and gray text, a spot colour at two tints, a linear gradient box, a radial gradient box and a dotted tiling pattern at the bottom of the page. The two gradient builders return the IGradientBuilder interface from addStopColor, so the stops are added in separate statements rather than in a fluent chain. The linear gradient direction is given as a central rotation angle; the lower-level LinearGradientBuilder.setGradientVector takes absolute coordinates instead, which is rarely what an element of unknown size needs.

Images

iText reads bitmaps through ImageDataFactory, which returns an ImageData (the decoded or raw image plus its metadata) that is independent of the document. The same ImageData can be reused for several Image elements, so a logo is decoded only once.

Format Factory method

JPEG, PNG, GIF, BMP, TIFF, JPEG 2000, JBIG2, WebP

ImageDataFactory.create(byte[]) detects the format from the content. Format-specific methods exist (createPng, createJpeg, createTiff(url, recoverFromImageError, page, direct), createJbig2(url, page), createGifFrame, createWebP) for cases where the type must be forced.

Raw pixels

ImageDataFactory.create(width, height, components, bpc, data, transparency) and createRawImage take already decoded samples.

java.awt.Image

ImageDataFactory.create(awtImage, color) is available when the headless AWT classes exist, see Getting Started with Spring Boot.

JPEG data is embedded as it is, without recompressing, which makes it the cheapest format for photographs. PNG is decoded and stored with Flate compression. SVG is not an ImageData: it goes through SvgConverter, described below. The authoritative list of supported formats and their limits (for example, animated GIF frames, multi-page TIFF and CMYK JPEG) is in Supported PDF image formats.

Layout images

The layout com.itextpdf.layout.element.Image wraps an ImageData (or a PdfImageXObject, or a PdfFormXObject) and takes part in the layout like a paragraph does.

  • Sizing: scaleToFit(w, h) keeps the aspect ratio inside a box, scaleAbsolute(w, h) forces the size, scale(x, y) multiplies, and setAutoScale(true) shrinks the image so that it fits the available area. Without any of these, the image takes its pixel size at the image’s DPI, which for a screenshot is usually far too large.

  • Position: setHorizontalAlignment, margins, or setFixedPosition(x, y) for an absolute position independent of the flow.

  • Rotation: setRotationAngle(radians), and the Property.TRANSFORM property through setTransform(Transform), which chains rotate, scaleX, skewX and translate like the CSS transform property.

  • Accessibility: getAccessibilityProperties().setAlternateDescription(...) writes the alternative text that PDF/UA requires for every figure, see PDF Standards & Conformance.

  • Opacity: setOpacity(Float) is available on every element.

Transparency and masks

A PNG with an alpha channel is converted automatically to an image with a soft mask: a second grayscale image whose values are the per-pixel opacity. This is the right choice for logos with soft edges. A one-bit stencil (a hard-edged mask) is built with ImageData.makeMask() on a one-bit-per-component image, and attached with setImageMask(mask). The soft mask gives smooth edges and costs more space; the stencil is small and is the right tool when a shape must be cut out cleanly. PDF/A-1 forbids transparency altogether, while PDF/A-2 and later allow it, see PDF Standards & Conformance.

Affine transformations on the canvas

Below the layout level, PdfCanvas.addImageWithTransformationMatrix(imageData, a, b, c, d, e, f) places an image with an arbitrary matrix: the unit square of the image is mapped through [a b c d e f], so that a and d are the width and height, b and c are the shear components and e and f are the translation. Rotation, flipping and skewing are all special cases of the same six numbers. java.awt.geom.AffineTransform is not used; iText ships its own com.itextpdf.kernel.geom.AffineTransform with the same semantics. The same matrix idea is behind the coordinate system and the content streams explained in How a PDF File Works.

The following program creates a logo with Java 2D so that it needs no file on disk, and then shows scaling, alignment, alternative text, rotation, the Transform property, a stencil mask and a canvas-level matrix.

import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.geom.AffineTransform;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.properties.HorizontalAlignment;
import com.itextpdf.layout.properties.Transform;

import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class ImageExamples {

    /** Draws a small test logo with an alpha channel, so the example needs no external file. */
    static byte[] logoPng() throws IOException {
        BufferedImage img = new BufferedImage(240, 120, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = img.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setColor(new Color(0x1F, 0x4E, 0x79));
        g.fillRoundRect(0, 0, 240, 120, 40, 40);
        g.setColor(new Color(0xF2, 0x99, 0x1A, 160));          // semi-transparent circle
        g.fillOval(60, 10, 100, 100);
        g.dispose();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write(img, "png", out);
        return out.toByteArray();
    }

    /** A 1-bit stencil: 1 = masked out. Here the left half of an 8x8 image is hidden. */
    static ImageData stencil() {
        byte[] bits = new byte[8];            // 8 rows, 1 byte (8 pixels) per row
        for (int row = 0; row < 8; row++) {
            bits[row] = (byte) 0b11110000;
        }
        ImageData mask = ImageDataFactory.create(8, 8, 1, 1, bits, null);
        mask.makeMask();
        return mask;
    }

    public static void main(String[] args) throws IOException {
        byte[] png = logoPng();
        try (PdfDocument pdf = new PdfDocument(new PdfWriter("images.pdf"));
             Document document = new Document(pdf, PageSize.A4)) {

            // 1. Layout Image: scaling, alignment and alternative text.
            ImageData logoData = ImageDataFactory.create(png);
            Image logo = new Image(logoData)
                    .scaleToFit(160, 80)
                    .setHorizontalAlignment(HorizontalAlignment.CENTER);
            logo.getAccessibilityProperties().setAlternateDescription("Bookshelf logo");
            document.add(new Paragraph("Scaled to fit 160 x 80 points"));
            document.add(logo);

            // 2. Rotation and the 9.8 transform property.
            document.add(new Paragraph("Rotated 15 degrees"));
            document.add(new Image(ImageDataFactory.create(png)).scaleToFit(120, 60)
                    .setRotationAngle(Math.toRadians(15)));
            document.add(new Paragraph("Transform: rotate and scale"));
            document.add(new Image(ImageDataFactory.create(png)).scaleToFit(120, 60)
                    .setTransform(new Transform(2).rotate((float) Math.toRadians(-10)).scaleX(0.8f)));

            // 3. An explicit image mask (stencil) on a copy of the image.
            ImageData masked = ImageDataFactory.create(png);
            masked.setImageMask(stencil());
            document.add(new Paragraph("Explicit stencil mask"));
            document.add(new Image(masked).scaleToFit(120, 60));

            // 4. Canvas level: image placed with an AffineTransform (skew + scale + translate).
            PdfCanvas canvas = new PdfCanvas(pdf.getFirstPage());
            AffineTransform at = new AffineTransform(120, 0, 30, 60, 350, 400);
            float[] m = new float[6];
            at.getMatrix(m);
            canvas.addImageWithTransformationMatrix(ImageDataFactory.create(png),
                    m[0], m[1], m[2], m[3], m[4], m[5]);
            canvas.release();
        }
    }
}

The matrix new AffineTransform(120, 0, 30, 60, 350, 400) (arguments m00 m10 m01 m11 m02 m12) draws the image 120 points wide and 60 high, skewed by 30 points to the right, with its lower-left corner at (350, 400). The stencil example hides the left half of the picture, because the 8 by 8 mask is stretched over the whole image.

The class pages are ImageDataFactory and Image. The tutorials this example derives from are Image examples, Images and affine transformations and Image masks.

SVG

The svg module (a dependency of itext-core, same licence) converts SVG into PDF drawing operators. The result is vector output: it stays sharp at any zoom and is usually far smaller than the equivalent bitmap. SvgConverter offers the same conversion at different levels of integration:

Method Result

SvgConverter.convertToImage(InputStream, PdfDocument)

A layout Image that flows with the text and can be scaled like a bitmap.

SvgConverter.convertToXObject(String or InputStream, PdfDocument)

A PdfFormXObject, to be converted once and drawn many times (headers, logos on every page).

SvgConverter.drawOnCanvas(String, PdfCanvas, ...), drawOnPage, drawOnDocument

Draws directly, optionally at a given position (x, y) or onto a given page number of the document.

SvgConverter.createPdf(InputStream, OutputStream)

A complete PDF whose single page is the SVG, the shortest route for a one-off conversion.

Each of them has an overload taking ISvgConverterProperties (implemented by SvgConverterProperties) where the base URI used to resolve relative href references, the FontProvider for text, the charset and the media device description are set. Text in an SVG is drawn with the fonts available to that provider, so a font used in the chart must be registered in the same way as for the rest of the document, see the Spring Boot page for fonts in containers. The converter supports basic shapes, paths, text, transforms, clipPath, use, pattern, gradients, and CSS in style attributes and <style> elements; iText 9.8 adds the <mask> element. Support is a subset of SVG, so animation and scripting are never executed. The Knowledge Base pages Improving SVG to PDF conversion and Overview: Using CSS in SVG with iText SDK describe the supported subset. Elements outside the supported subset are generally skipped with a log message instead of failing the conversion, so a visual check of the rendered PDF is part of the work.

Charts as SVG

The monthly statement of Bookshelf Billing needs a bar chart of sales by category. The book B1 solved this class of problem in its chapters on graphics with PdfGraphics2D, a java.awt.Graphics2D implementation that wrote into a PDF canvas, so that Swing components, applets and chart libraries such as JFreeChart (through Batik for SVG) could be drawn into the document. That class is not part of iText 7 and later, and neither is the Swing or applet export path; Java AWT is also an awkward dependency in a container, where it needs headless mode and system fonts.

The current approach has two options. The first is to produce the chart as SVG and let SvgConverter draw it. Most chart libraries can write SVG, and for simple charts, as below, a text block is enough. The second is to build the chart directly with PdfCanvas (rectangles, lines and text), which is the better choice when the chart must be pixel-exact or be tagged for accessibility, see the low-level canvas page in this section. JasperReports has its own chart components for the template route, described in the JasperReports pages of this section.

The example uses Java 21 features: a text block with formatted, var in the loop over map entries, and try-with-resources for the document. Values are interpolated with Locale.ROOT, so that the decimal separator in the SVG is always a dot even on a Spanish locale.

import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.svg.converter.SvgConverter;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;

public class SvgChartExample {

    /** Builds a bar chart as an SVG document: no Swing, no AWT, no Batik. */
    static String barChart(Map<String, Double> salesByCategory, int width, int height) {
        double max = salesByCategory.values().stream().mapToDouble(Double::doubleValue).max().orElse(1);
        int barWidth = (width - 40) / salesByCategory.size();
        StringBuilder svg = new StringBuilder("""
                <svg xmlns="http://www.w3.org/2000/svg" width="%d" height="%d" viewBox="0 0 %d %d">
                  <rect width="%d" height="%d" fill="#ffffff" stroke="#999999"/>
                """.formatted(width, height, width, height, width, height));
        int i = 0;
        for (var entry : salesByCategory.entrySet()) {
            double barHeight = (height - 60) * entry.getValue() / max;
            int x = 20 + i * barWidth;
            svg.append(String.format(Locale.ROOT, """
                      <rect x="%d" y="%.1f" width="%d" height="%.1f" fill="#1f4e79"/>
                      <text x="%d" y="%d" font-family="Helvetica" font-size="10" text-anchor="middle">%s</text>
                    """, x + 5, height - 30 - barHeight, barWidth - 10, barHeight,
                    x + barWidth / 2, height - 14, entry.getKey()));
            i++;
        }
        return svg.append("</svg>").toString();
    }

    public static void main(String[] args) throws IOException {
        Map<String, Double> sales = new LinkedHashMap<>();
        sales.put("Fiction", 1280.0);
        sales.put("Science", 640.0);
        sales.put("History", 910.0);
        sales.put("Kids", 1530.0);
        String svg = barChart(sales, 360, 200);

        try (PdfDocument pdf = new PdfDocument(new PdfWriter("svg-chart.pdf"));
             Document document = new Document(pdf, PageSize.A4)) {

            // 1. As a layout element: flows with the text and can be scaled like any Image.
            document.add(new Paragraph("Monthly sales by category"));
            Image chart = SvgConverter.convertToImage(
                    new ByteArrayInputStream(svg.getBytes(StandardCharsets.UTF_8)), pdf);
            document.add(chart.scaleToFit(360, 200));

            // 2. As a reusable form XObject: converted once, drawn many times.
            PdfFormXObject xObject = SvgConverter.convertToXObject(svg, pdf);
            PdfCanvas canvas = new PdfCanvas(pdf.getFirstPage());
            canvas.addXObjectAt(xObject, 36, 400);
            canvas.addXObjectFittedIntoRectangle(xObject, new com.itextpdf.kernel.geom.Rectangle(36, 200, 180, 100));

            // 3. Drawn straight onto a canvas.
            SvgConverter.drawOnCanvas(svg, canvas, 320, 200);
            canvas.release();
        }
    }
}

The program draws the same chart three ways: as a flowing Image, as a reusable form XObject placed at an absolute position and fitted into a rectangle, and directly on the canvas. For a document with many charts, convert each distinct SVG once and reuse the form XObject, as it is stored once in the file.

The class pages are SvgConverter and Image. The tutorial it derives from is the Knowledge Base page Improving SVG to PDF conversion.

Outdated material and current practice

The book B1 (Lowagie, iText in Action, 1st edition) is consulted for the concept coverage of this page: colour spaces, patterns, transparency and masks, images and the graphics chapters. It targets iText 1.4 and com.lowagie.*. Three points matter when reading it today.

  • The graphics export chapter, with PdfGraphics2D, Swing and applet output and Batik, describes classes that iText 7 and later do not contain. Use SVG support in the svg module, or render the chart to SVG, as shown above. This is finding O7 of the section. The official entry points are the SVG pages of the Knowledge Base and the SvgConverter API page.

  • The packages and the licence differ. iText 7 and later are a rewrite split into modules, and are licensed under the AGPLv3 or a commercial licence, while the 1.x and 2.x code the book uses was MPL and LGPL. The fork of that old API, under the LGPL and MPL, is OpenPDF; see itext-java for the current iText line.

  • The book targets Java 1.4: no generics, no var, no text blocks, and finally blocks for closing. The examples on this page and on the other pages of the section use Java 21 and rely on try-with-resources, so closing the Document closes the PdfDocument and the writer, and on text blocks and String.formatted where they shorten the code. This is finding O28.