File: Images.md

package info (click to toggle)
fpdf2 2.8.4-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 53,860 kB
  • sloc: python: 39,487; sh: 133; makefile: 12
file content (300 lines) | stat: -rw-r--r-- 10,722 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# 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 ##

```python
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()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.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]( https://github.com/py-pdf/fpdf2/blob/master/fpdf/image_parsing.py) 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 ###

```python
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()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.image) method.

The following unit tests illustrate that:

* [test_image_fit.py](https://github.com/py-pdf/fpdf2/blob/master/test/image/test_image_fit.py)
* resulting document: [image_fit_in_rect.pdf](https://github.com/py-pdf/fpdf2/blob/master/test/image/image_fit_in_rect.pdf)

### 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`.

```python
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](https://github.com/py-pdf/fpdf2/blob/master/test/drawing/generated_pdf/blending_images.pdf)


## Image clipping ##

![](image-clipping.png)

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

* [`rect_clip()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.rect_clip):
    - [example code](https://github.com/py-pdf/fpdf2/blob/master/test/image/test_image_clipping.py#L10)
    - [resulting PDF](https://github.com/py-pdf/fpdf2/blob/master/test/image/rect_clip.pdf)
* [`round_clip()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.round_clip):
    - [example code](https://github.com/py-pdf/fpdf2/blob/master/test/image/test_image_clipping.py#L33)
    - [resulting PDF](https://github.com/py-pdf/fpdf2/blob/master/test/image/round_clip.pdf)
* [`elliptic_clip()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.elliptic_clip):
    - [example code](https://github.com/py-pdf/fpdf2/blob/master/test/image/test_image_clipping.py#L56)
    - [resulting PDF](https://github.com/py-pdf/fpdf2/blob/master/test/image/elliptic_clip.pdf)


## Alternative description ##

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

```python
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](https://pillow.readthedocs.io/en/stable/) library,
and easily embed the result:

```python
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()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.image) method
will be embedded as [PDF paths](SVG.md):
```python
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()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.image) method:

```python
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()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.set_image_filter):

```python
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")
```

The allowed `image_filter` values are listed in the [`set_image_filter()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.set_image_filter) method documentation.

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

## Output Intents ##
_New in [:octicons-tag-24: 2.8.3](https://github.com/py-pdf/fpdf2/blob/master/CHANGELOG.md)_

> Output Intents [allow] the contents of referenced icc profiles to be embedded directly within the body of the PDF file. This makes the PDF file a self-contained unit that can be stored or transmitted as a single entity.

The dedicated method for adding output intent to a PDF is [`add_output_intent()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.add_output_intent).

You can optionally provide a [`PDFICCProfileObject`](https://py-pdf.github.io/fpdf2/fpdf/output.html#fpdf.output.PDFICCProfileObject) as `icc_profile`.

Example:
```python
from pathlib import Path
from fpdf import FPDF
from fpdf.enums import OutputIntentSubType
from fpdf.output import PDFICCProfileObject

HERE = Path(__file__).resolve().parent

pdf = FPDF()

with open(HERE / "sRGB2014.icc", "rb") as iccp_file:
    icc_profile = PDFICCProfileObject(
        contents=iccp_file.read(), n=3, alternate="DeviceRGB"
    )

pdf.add_output_intent(
    OutputIntentSubType.PDFA,
    "sRGB",
    'IEC 61966-2-1:1999',
    "http://www.color.org",
    icc_file,
    "sRGB2014 (v2)",
)
```

The needed profiles and descriptions can be found at [International Color Consortium](https://color.org/).

## 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.

An ICC profile can also be added by using the [`.add_output_intent()` method](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.add_output_intent),
as described in the previous section.

## 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`:

```python
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:

```python
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](https://medium.com/unsplash/the-5-minute-guide-to-image-quality-ad7c3503c845)


## 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](https://en.wikipedia.org/wiki/PDF/A#Description):

```python
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](Transparency.md).


## Page background ##

_cf._ [Per-page format, orientation and background](PageFormatAndOrientation.md#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:

```python
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](https://github.com/py-pdf/fpdf2/issues/501#issuecomment-1224310277)).