Skip to content

Images

When rendering an image, its size on the page can be specified in several ways:

  • explicit width and height (expressed in user units). The image is scaled to those dimensions, unless keep_aspect_ratio=True is specified.
  • one explicit dimension, the other being calculated automatically in order to keep the original proportions
  • no explicit dimension, in which case the image is put at 72 dpi

Note that if an image is displayed several times, only one copy is embedded in the file.

Simple example

from fpdf import FPDF

pdf = FPDF()
pdf.add_page()
pdf.image("docs/fpdf2-logo.png", x=20, y=60)
pdf.output("pdf-with-image.pdf")

By default an image is rendered with a resolution of 72 dpi, but you can control its dimension on the page using the w= & h= parameters of the image() method.

Alpha / transparency

fpdf2 allows to embed images with alpha pixels.

Technically, it is implemented by extracting an /SMask from images with transparency, and inserting it along with the image data in the PDF document. Related code is in the image_parsing module.

Assembling images

The following code snippets provide examples of some basic layouts for assembling images into PDF files.

Side by side images, full height, landscape page

from fpdf import FPDF

pdf = FPDF(orientation="landscape")
pdf.set_margin(0)
pdf.add_page()
pdf.image("imgA.png", h=pdf.eph, w=pdf.epw/2)               # full page height, half page width
pdf.set_y(0)
pdf.image("imgB.jpg", h=pdf.eph, w=pdf.epw/2, x=pdf.epw/2)  # full page height, half page width, right half of the page
pdf.output("side-by-side.pdf")

Fitting an image inside a rectangle

When you want to scale an image to fill a rectangle, while keeping its aspect ratio, and ensuring it does not overflow the rectangle width nor height in the process, you can set w / h and also provide keep_aspect_ratio=True to the image() method.

The following unit tests illustrate that:

Blending images

You can control the color blending mode of overlapping images. Valid values for blend_mode are Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color and Luminosity.

from fpdf import FPDF

pdf = FPDF()
pdf.add_page()
pdf.image("imgA.png", ...)
with pdf.local_context(blend_mode="ColorBurn"):
    pdf.image("imgB.jpg", ...)
pdf.output("blended-images.pdf")

Demo of all color blend modes: blending_images.pdf

Image clipping

You can select only a portion of the image to render using clipping methods:

Alternative description

A textual description of the image can be provided, for accessibility purposes:

pdf.image("docs/fpdf2-logo.png", x=20, y=60, alt_text="Snake logo of the fpdf2 library")

Usage with Pillow

You can perform image manipulations using the Pillow library, and easily embed the result:

from fpdf import FPDF
from PIL import Image

pdf = FPDF()
pdf.add_page()
img = Image.open("docs/fpdf2-logo.png")
img = img.crop((10, 10, 490, 490)).resize((96, 96), resample=Image.NEAREST)
pdf.image(img, x=80, y=100)
pdf.output("pdf-with-image.pdf")

SVG images

SVG images passed to the image() method will be embedded as PDF paths:

from fpdf import FPDF

pdf = FPDF()
pdf.add_page()
pdf.image("SVG_logo.svg", w=100)
pdf.output("pdf-with-vector-image.pdf")

Retrieve images from URLs

URLs to images can be directly passed to the image() method:

pdf.image("https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png")

Image compression

By default, fpdf2 will avoid altering or recompressing your images: when possible, the original bytes from the JPG or TIFF file will be used directly. Bitonal images are by default compressed as TIFF Group4.

However, you can easily tell fpdf2 to embed all images as JPEGs in order to reduce your PDF size, using set_image_filter():

from fpdf import FPDF

pdf = FPDF()
pdf.set_image_filter("DCTDecode")
pdf.add_page()
pdf.image("docs/fpdf2-logo.png", x=20, y=60)
pdf.output("pdf-with-image.pdf")

Beware that "flattening" images into JPEGs this way will fill transparent areas of your images with color (usually black).

The allowed image_filter values are listed in the image_parsing module and are currently: FlateDecode (lossless zlib/deflate compression), DCTDecode (lossy compression with JPEG) and JPXDecode (lossy compression with JPEG2000).

ICC Profiles

The ICC profile of the included images are read through the PIL function Image.info.get("icc_profile)" and are included in the PDF as objects.

Oversized images detection & downscaling

If the resulting PDF size is a concern, you may want to check if some inserted images are oversized, meaning their resolution is unnecessarily high given the size they are displayed.

There is how to enable this detection mechanism with fpdf2:

pdf.oversized_images = "WARN"

After setting this property, a WARNING log will be displayed whenever an oversized image is inserted.

fpdf2 is also able to automatically downscale such oversized images:

pdf.oversized_images = "DOWNSCALE"

After this, oversized images will be automatically resized, generating DEBUG logs like this:

OVERSIZED: Generated new low-res image with name=lowres-test.png dims=(319, 451) id=2

For finer control, you can set pdf.oversized_images_ratio to set the threshold determining if an image is oversized.

If the concepts of "image compression" or "image resolution" are a bit obscure for you, this article is a recommended reading: The 5 minute guide to image quality

Disabling transparency

By default images transparency is preserved: alpha channels are extracted and converted to an embedded SMask. This can be disabled by setting .allow_images_transparency, e.g. to allow compliance with PDF/A-1:

from fpdf import FPDF

pdf = FPDF()
pdf.allow_images_transparency = False
pdf.set_font("Helvetica", size=15)
pdf.cell(w=pdf.epw, h=30, text="Text behind. " * 6)
pdf.image("docs/fpdf2-logo.png", x=0)
pdf.output("pdf-including-image-without-transparency.pdf")

This will fill transparent areas of your images with color (usually black).

cf. also documentation on controlling transparency.

Page background

cf. Per-page format, orientation and background

Sharing the image cache among FPDF instances

Image parsing is often the most CPU & memory intensive step when inserting pictures in a PDF.

If you create several PDF files that use the same illustrations, you can share the images cache among FPDF instances:

image_cache = None

for ... # loop
    pdf = FPDF()
    if image_cache is None:
        image_cache = pdf.image_cache
    else:
        pdf.image_cache = image_cache
    ... # build the PDF
    pdf.output(...)
    # Reset the "usages" count, to avoid ALL images to be inserted in subsequent PDFs:
    image_cache.reset_usages()

This recipe is valid for fpdf2 v2.5.7+. For previous versions of fpdf2, a deepcopy of .images must be made, (cf. issue #501).