Skip to main content

Wagtail Exact Crop

Exact image cropping for Wagtail content editors.

Give content editors precise control over image crops in the Wagtail image admin. Instead of relying on focal points, editors move and scale the image inside fixed crop areas and see the result immediately.

Installation

pip install wagtail-exact-crop

Add wagtail_exact_crop to installed apps:

INSTALLED_APPS = [
    "wagtail_exact_crop",
    ...
]

Use the ExactCropImageMixin to add the exact_crops field to your custom image model:

from django.db import models
from wagtail.images.models import AbstractImage, AbstractRendition
from wagtail_exact_crop.models import ExactCropImageMixin


class CustomImage(ExactCropImageMixin, AbstractImage):
    admin_form_fields = (
        "title",
        "file",
        "description",
        "collection",
        "tags",
        "focal_point_x",
        "focal_point_y",
        "focal_point_width",
        "focal_point_height",
        "exact_crops",  # !
    )


class CustomRendition(AbstractRendition):
    image = models.ForeignKey(
        CustomImage,
        on_delete=models.CASCADE,
        related_name="renditions",
    )

    class Meta:
        unique_together = (("image", "filter_spec", "focal_point_key"),)

Define the custom image model in your settings:

WAGTAILIMAGES_IMAGE_MODEL = "images.CustomImage"

After adding the model, run makemigrations and migrate.

Define crop sizes:

WAGTAIL_EXACT_IMAGE_CROP_PRESETS = {
    "avatar": {"width": 300, "height": 300},
    "medium_shot": {"width": 400, "height": 800},
    "list_image_small": {"width": 400, "height": 300},
    "list_image_medium": {"width": 800, "height": 600},
    "hero_image": {"width": 1600, "height": 600},
}

Define widgets (admin interface). Note that images with the same aspect ratio might share widget:

WAGTAIL_EXACT_IMAGE_CROP_WIDGETS = {
    "avatar": {
        "title": "Avatar image",
        "description": "Used in listings and teasers",
        "presets": ["avatar"],
    },
    "medium_shot": {
        "title": "Medium shot image",
        "description": "Used in listings and teasers",
        "presets": ["medium_shot"],
    },
    "list_image": {
        "title": "List image",
        "description": "Used in listings and teasers",
        "presets": ["list_image_small", "list_image_medium"],
    },
    "hero_image": {
        "title": "Hero image",
        "description": "Large banner at top of page",
        "presets": ["hero_image"],
    },
}

Wagtail Exact Crop disables Wagtail's focal point editor by default. To use focal point and exact crops side by side, enable it explicitly:

WAGTAIL_EXACT_IMAGE_CROP_FOCAL_POINT_ENABLED = True

This setting only controls the focal point editor in the Wagtail admin. Existing focal point data is preserved either way and will still be submitted with the image form.

Exact crop is registered as a custom image filter, so you can use it in your templates like any other image filter. https://docs.wagtail.org/en/latest/extending/custom_image_filters.html

Just use the exact- prefix followed by the crop preset name to apply the crop:

{% load wagtailimages_tags %}

{% image some_image exact-avatar %}
{% image some_image exact-medium_shot %}
{% image some_image exact-list_image_small %}
{% image some_image exact-list_image_medium %}
{% image some_image exact-hero_image %}

Development and testing

Install the package with test dependencies:

uv venv
source .venv/bin/activate
pip install -e ".[test]"

Run the automated tests:

pytest

Demo project

The tests/test_project Django/Wagtail project can be used for manual testing and demonstration.

python tests/test_project/manage.py migrate
python tests/test_project/manage.py createsuperuser
python tests/test_project/manage.py runserver

Then open http://127.0.0.1:8000/admin/, upload an image, edit it, adjust the exact crop widgets, and save. The exact crop demo at http://127.0.0.1:8000/exact-crop/ renders the latest uploaded image using the documented exact-* filters. The focal point comparison page at http://127.0.0.1:8000/focal-point/ renders the same target sizes with Wagtail's fill-* filters.

Releasing

Releases are published to PyPI by GitHub Actions when a v* tag is pushed.

Update the project version in pyproject.toml.

git add pyproject.toml
git commit -m "Release 0.1.1"
git tag -a v0.1.1 -m v0.1.1
git push
git push origin v0.1.1

The Git tag should be the package version with a v prefix. For example, version = "0.1.1" in pyproject.toml is released with tag v0.1.1.

You can also create the GitHub Release in the web UI after pushing the tag. If you create the tag through the GitHub Release UI, make sure the version bump commit is already on the target branch.

To build and inspect the package locally:

uv build

This writes the release artifacts to dist/. Before publishing, inspect the generated files and verify the package data is included:

tar -tf dist/wagtail_exact_crop-*.tar.gz
unzip -l dist/wagtail_exact_crop-*.whl

Release files for wagtail-exact-crop 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wagtail-exact-crop 0.2.0
File Size Uploaded
wagtail_exact_crop-0.2.0.tar.gz 57.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wagtail-exact-crop 0.2.0
File Interpreter ABI Platform
wagtail_exact_crop-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 71.8 kB

Release files / wagtail_exact_crop-0.2.0.tar.gz

Download URL wagtail_exact_crop-0.2.0.tar.gz
Size 57.2 kB
Tags Source
SHA-256 checksum
How to use checksums
9ef5d7ea25efd958a371617b2202a9d3bad90bd049cbc383b304543dc5ae8f5c
BLAKE2b-256 checksum
How to use checksums
403ca512155acde4fecab2d34f6af81c169ae0a01b68c430f3c0a6fbaec4d9a4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / wagtail_exact_crop-0.2.0-py3-none-any.whl

Download URL wagtail_exact_crop-0.2.0-py3-none-any.whl
Size 14.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b960b77957ef02720404488bbb2027ec052fd6283f690876a45f304d47e24752
BLAKE2b-256 checksum
How to use checksums
22ad83270e18c649c7dae9ec175d1253447870a0718171449d6ef40f6f098331
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page