Skip to content

Commit ccb742e

Browse files
committed
Change default file type to AVIF (Baseline 2024)
1 parent 2eb0059 commit ccb742e

File tree

10 files changed

+270
-260
lines changed

10 files changed

+270
-260
lines changed

.github/workflows/ci.yml

+6
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ jobs:
8888
uses: actions/setup-python@v5
8989
with:
9090
python-version: ${{ matrix.python-version }}
91+
- run: sudo apt update && sudo apt install libavif-dev libwebp-dev libjpeg8-dev -y
92+
- run: 'python -m pip install --upgrade Pillow --no-binary :all:'
9193
- run: python -m pip install .[test]
9294
- run: python -m pip install django~=${{ matrix.django-version }}.0
9395
- run: python -m pytest
@@ -115,6 +117,8 @@ jobs:
115117
uses: actions/setup-python@v5
116118
with:
117119
python-version: ${{ matrix.python-version }}
120+
- run: sudo apt update && sudo apt install libavif-dev libwebp-dev libjpeg8-dev -y
121+
- run: 'python -m pip install --upgrade Pillow --no-binary :all:'
118122
- run: python -m pip install .[test]
119123
- run: python -m pip install django~=${{ matrix.django-version }}.0
120124
- run: python -m pytest
@@ -142,6 +146,8 @@ jobs:
142146
uses: actions/setup-python@v5
143147
with:
144148
python-version: 3.x
149+
- run: sudo apt update && sudo apt install libavif-dev libwebp-dev libjpeg8-dev -y
150+
- run: 'python -m pip install --upgrade Pillow --no-binary :all:'
145151
- name: Install redis
146152
if: matrix.extras == 'dramatiq' || matrix.extras == 'django-rq'
147153
run: sudo apt install -y redis-server

README.md

+45-41
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44

55
Responsive cross-browser image library using modern codes like AVIF & WebP.
66

7-
* responsive web images using the [picture](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture) tag
8-
* native grid system support
9-
* serve files with or without a CDN
10-
* placeholders for local development
11-
* migration support
12-
* async image processing for [Celery], [Dramatiq] or [Django RQ][django-rq]
13-
* [DRF] support
7+
- responsive web images using the [picture](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture) tag
8+
- native grid system support
9+
- serve files with or without a CDN
10+
- placeholders for local development
11+
- migration support
12+
- async image processing for [Celery], [Dramatiq] or [Django RQ][django-rq]
13+
- [DRF] support
1414

1515
[![PyPi Version](https://img.shields.io/pypi/v/django-pictures.svg)](https://pypi.python.org/pypi/django-pictures/)
1616
[![Test Coverage](https://codecov.io/gh/codingjoe/django-pictures/branch/main/graph/badge.svg)](https://codecov.io/gh/codingjoe/django-pictures)
@@ -21,8 +21,9 @@ Responsive cross-browser image library using modern codes like AVIF & WebP.
2121
Before you start, it can be a good idea to understand the fundamentals of
2222
[responsive images](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images).
2323

24-
Once you get a feeling how complicated things can get with all device types, you'll probably find
25-
a new appreciation for this package and are ready to adopt in you project :)
24+
Once you get a feeling how complicated things can get with all device types,
25+
you'll probably find a new appreciation for this package,
26+
and are ready to adopt in your project :)
2627

2728
```python
2829
# models.py
@@ -41,12 +42,13 @@ class Profile(models.Model):
4142
```
4243

4344
The keyword arguments `m=6 l=4` define the columns the image should take up in
44-
a grid at a given breakpoint. So in this example, the image will take up
45-
6 columns on medium screens and 4 columns on large screens. You can define your
46-
grid and breakpoints as you want, refer to the [grid columns](#grid-columns) and
45+
a grid at a given breakpoint. So in this example, the image will take up
46+
six columns on medium screens and four columns on large screens. You can define
47+
your grid and breakpoints as you want, refer to the [grid columns](#grid-columns) and
4748
[breakpoints](#breakpoints) sections.
4849

4950
The template above will render into:
51+
5052
```html
5153
<picture class="my-picture">
5254
<source type="image/webp"
@@ -89,7 +91,7 @@ PICTURES = {
8991
},
9092
"GRID_COLUMNS": 12,
9193
"CONTAINER_WIDTH": 1200,
92-
"FILE_TYPES": ["WEBP"],
94+
"FILE_TYPES": ["AVIF"],
9395
"PIXEL_DENSITIES": [1, 2],
9496
"USE_PLACEHOLDERS": True,
9597
"QUEUE_NAME": "pictures",
@@ -128,19 +130,16 @@ Although the `picture`-tag is [adequate for most use-cases][caniuse-picture],
128130
some remain, where a single `img` tag is necessary. Notably in email, where
129131
[most clients do support WebP][caniemail-webp] but not [srcset][caniemail-srcset].
130132
The template tag `img_url` returns a single size image URL.
131-
In addition to the ratio you will need to define the `file_type`
133+
In addition to the ratio, you will need to define the `file_type`
132134
as well as the `width` (absolute width in pixels).
133135

136+
Sadly, AVIF support [requires a little more setup][libavif-install].
134137

135138
```html
136139
{% load pictures %}
137-
<img src="{% img_url profile.picture ratio="3/2" file_type="webp" width=800 %}" alt="profile picture">
140+
<img src="{% img_url profile.picture ratio='3/2' file_type='webp' width=800 %}" alt="profile picture">
138141
```
139142

140-
[caniuse-picture]: https://caniuse.com/picture
141-
[caniemail-webp]: https://www.caniemail.com/features/image-webp/
142-
[caniemail-srcset]: https://www.caniemail.com/features/html-srcset/
143-
144143
## Config
145144

146145
### Aspect ratios
@@ -172,17 +171,17 @@ class Profile(models.Model):
172171
If you don't specify an aspect ratio or None in your template, the image will be
173172
served with the original aspect ratio of the file.
174173

175-
You may only use aspect ratios in templates, that have been defined on the model.
174+
You may only use aspect ratios in templates that have been defined on the model.
176175
The model `aspect_ratios` will default to `[None]`, if other value is provided.
177176

178177
### Breakpoints
179178

180-
You may define your own breakpoints, they should be identical to the ones used
181-
in your css library. Simply override the `PICTURES["BREAKPOINTS"]` setting.
179+
You may define your own breakpoints they should be identical to the ones used
180+
in your CSS library. This can be achieved by overriding the `PICTURES["BREAKPOINTS"]` setting.
182181

183182
### Grid columns
184183

185-
Grids are so common in web design, that they even made it into CSS.
184+
Grids are so common in web design that they even made it into CSS.
186185
We default to 12 columns, but you can override this setting, via the
187186
`PICTURES["GRID_COLUMNS"]` setting.
188187

@@ -196,13 +195,14 @@ You may also set it to `None`, should you not use a container.
196195

197196
### File types
198197

199-
Unless you still services IE11 clients, you should be fine serving just
200-
[WebP](https://caniuse.com/webp). Sadly, [AVIF](https://caniuse.com/avif)
201-
(WebP's successor) is
202-
[not yet supported by Pillow](https://github.com/python-pillow/Pillow/pull/5201).
198+
[AVIF](https://caniuse.com/avif) ([WebP](https://caniuse.com/webp)'s successor)
199+
is the best and most efficient image format available today. It is part of
200+
Baseline 2024 and is supported by all major browsers. Additionally, most modern
201+
devices will have hardware acceleration for AVIF decoding. This will not only
202+
reduce network IO but speed up page rendering.
203203

204-
If you are serving IE11 use add `JPEG` to the list. Beware though, that this may
205-
drastically increase you storage needs.
204+
Should you still serve IE11, use add `JPEG` to the list. But, beware, this may
205+
drastically increase your storage needs.
206206

207207
### Pixel densities
208208

@@ -224,13 +224,11 @@ processor, should you need to do some custom processing.
224224
## Migrations
225225

226226
Django doesn't support file field migrations, but we do.
227-
You can simply auto create the migration and replace Django's
227+
You can auto create the migration and replace Django's
228228
`AlterField` operation with `AlterPictureField`. That's it.
229229

230230
You can follow [the example][migration] in our test app, to see how it works.
231231

232-
[migration]: tests/testapp/migrations/0002_alter_profile_picture.py
233-
234232
## Contrib
235233

236234
### Django Rest Framework ([DRF])
@@ -254,10 +252,10 @@ from rest_framework import serializers
254252
from pictures.contrib.rest_framework import PictureField
255253

256254
class PictureSerializer(serializers.Serializer):
257-
picture = PictureField(aspect_ratios=["16/9"], file_types=["WEBP"])
255+
picture = PictureField(aspect_ratios=["16/9"], file_types=["AVIF"])
258256
```
259257

260-
You also may provide optional GET parameters to the serializer,
258+
You also may provide optional GET parameters to the serializer
261259
to specify the aspect ratio and breakpoints you want to include in the response.
262260
The parameters are prefixed with the `fieldname_`
263261
to avoid conflicts with other fields.
@@ -303,7 +301,7 @@ Should you use a CDN, or some other external image processing service, you can
303301
set this up in two simple steps:
304302

305303
1. Override `PICTURES["PROCESSOR"]` to disable the default processing.
306-
2. Override `PICTURES["PICTURE_CLASS"]` implement any custom behavior.
304+
1. Override `PICTURES["PICTURE_CLASS"]` implement any custom behavior.
307305

308306
```python
309307
# settings.py
@@ -317,10 +315,11 @@ The `MyPicture`class should implement the url property, which returns the URL
317315
of the image. You may use the `Picture` class as a base class.
318316

319317
Available attributes are:
320-
* `parent_name` - name of the source file uploaded to the `PictureField`
321-
* `aspect_ratio` - aspect ratio of the output image
322-
* `width` - width of the output image
323-
* `file_type` - file type of the output image
318+
319+
- `parent_name` - name of the source file uploaded to the `PictureField`
320+
- `aspect_ratio` - aspect ratio of the output image
321+
- `width` - width of the output image
322+
- `file_type` - format of the output image
324323

325324
```python
326325
# path/to.py
@@ -337,7 +336,12 @@ class MyPicture(Picture):
337336
)
338337
```
339338

340-
[drf]: https://www.django-rest-framework.org/
339+
[caniemail-srcset]: https://www.caniemail.com/features/html-srcset/
340+
[caniemail-webp]: https://www.caniemail.com/features/image-webp/
341+
[caniuse-picture]: https://caniuse.com/picture
341342
[celery]: https://docs.celeryproject.org/en/stable/
342-
[dramatiq]: https://dramatiq.io/
343343
[django-rq]: https://github.com/rq/django-rq
344+
[dramatiq]: https://dramatiq.io/
345+
[drf]: https://www.django-rest-framework.org/
346+
[libavif-install]: https://pillow.readthedocs.io/en/latest/installation/building-from-source.html#external-libraries
347+
[migration]: tests/testapp/migrations/0002_alter_profile_picture.py

pictures/conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def get_settings():
1717
},
1818
"GRID_COLUMNS": 12,
1919
"CONTAINER_WIDTH": 1200,
20-
"FILE_TYPES": ["WEBP"],
20+
"FILE_TYPES": ["AVIF"],
2121
"PIXEL_DENSITIES": [1, 2],
2222
"USE_PLACEHOLDERS": settings.DEBUG,
2323
"QUEUE_NAME": "pictures",

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ classifiers = [
3434
"Framework :: Django :: 5.2",
3535
]
3636
requires-python = ">=3.9"
37-
dependencies = ["django>=4.2.0", "pillow>=9.0.0"]
37+
dependencies = ["django>=4.2.0", "pillow>=11.2.0"]
3838

3939
[project.optional-dependencies]
4040
test = [

tests/contrib/test_cleanup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def test_delete(self, stub_worker, image_upload_file):
1919
stub_worker.join()
2020

2121
name = obj.picture.name
22-
path = obj.picture.aspect_ratios["16/9"]["WEBP"][100].path
22+
path = obj.picture.aspect_ratios["16/9"]["AVIF"][100].path
2323
assert default_storage.exists(name)
2424
assert path.exists()
2525
with transaction.atomic(get_using(obj)):

0 commit comments

Comments
 (0)