kopia lustrzana https://github.com/wagtail/wagtail
documentation - migrate advanced_topics/images/** to md
rodzic
52e87968e2
commit
4424d23fa4
|
|
@ -19,7 +19,7 @@ You can use any of the following methods to call the module:
|
|||
|
||||
Wagtail's default rich text editor has a "media" icon that allows embeds to be
|
||||
placed into rich text. You don't have to do anything to enable this; just make
|
||||
sure the rich text field's content is being passed through the ``|richtext``
|
||||
sure the rich text field's content is being passed through the `|richtext`
|
||||
filter in the template as this is what calls the embeds module to fetch and
|
||||
nest the embed code.
|
||||
|
||||
|
|
@ -182,7 +182,6 @@ perform the request.
|
|||
Wagtail will not try to run any other finder, even if the chosen one didn't
|
||||
return an embed.
|
||||
|
||||
|
||||
(facebook_and_instagram_embeds)=
|
||||
|
||||
### Facebook and Instagram
|
||||
|
|
@ -235,7 +234,6 @@ By passing `'omitscript': True` in the configuration, you can indicate that thes
|
|||
tags should be omitted from the embed HTML. Note that you will then have to take care of
|
||||
loading this script yourself.
|
||||
|
||||
|
||||
(Embedly)=
|
||||
|
||||
### Embed.ly
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
Animated GIF support
|
||||
====================
|
||||
# Animated GIF support
|
||||
|
||||
Pillow, Wagtail's default image library, doesn't support animated
|
||||
GIFs.
|
||||
|
||||
To get animated GIF support, you will have to
|
||||
`install Wand <https://docs.wand-py.org/en/0.6.7/guide/install.html>`_.
|
||||
[install Wand](https://docs.wand-py.org/en/0.6.7/guide/install.html).
|
||||
Wand is a binding to ImageMagick so make sure that has been installed as well.
|
||||
|
||||
When installed, Wagtail will automatically use Wand for resizing GIF
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
(changing_rich_text_representation)=
|
||||
|
||||
# Changing rich text representation
|
||||
|
||||
The HTML representation of an image in rich text can be customised - for example, to display captions or custom fields.
|
||||
|
||||
To do this requires subclassing `Format` (see [](rich_text_image_formats)), and overriding its `image_to_html` method.
|
||||
|
||||
You may then register formats of your subclass using `register_image_format` as usual.
|
||||
|
||||
```python
|
||||
# image_formats.py
|
||||
from wagtail.images.formats import Format, register_image_format
|
||||
|
||||
|
||||
class SubclassedImageFormat(Format):
|
||||
|
||||
def image_to_html(self, image, alt_text, extra_attributes=None):
|
||||
|
||||
custom_html = # the custom HTML representation of your image here
|
||||
# in Format, the image's rendition.img_tag(extra_attributes) is used to generate the HTML
|
||||
# representation
|
||||
|
||||
return custom_html
|
||||
|
||||
|
||||
register_image_format(
|
||||
SubclassedImageFormat('subclassed_format', 'Subclassed Format', classnames, filter_spec)
|
||||
)
|
||||
```
|
||||
|
||||
As an example, let's say you want the alt text to be displayed as a caption for the image as well:
|
||||
|
||||
```python
|
||||
# image_formats.py
|
||||
from django.utils.html import format_html
|
||||
from wagtail.images.formats import Format, register_image_format
|
||||
|
||||
|
||||
class CaptionedImageFormat(Format):
|
||||
|
||||
def image_to_html(self, image, alt_text, extra_attributes=None):
|
||||
|
||||
default_html = super().image_to_html(image, alt_text, extra_attributes)
|
||||
|
||||
return format_html("{}<figcaption>{}</figcaption>", default_html, alt_text)
|
||||
|
||||
|
||||
register_image_format(
|
||||
CaptionedImageFormat('captioned_fullwidth', 'Full width captioned', 'bodytext-image', 'width-750')
|
||||
)
|
||||
```
|
||||
|
||||
```{note}
|
||||
Any custom HTML image features will not be displayed in the Draftail editor, only on the published page.
|
||||
```
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
.. _changing_rich_text_representation:
|
||||
|
||||
=================================
|
||||
Changing rich text representation
|
||||
=================================
|
||||
|
||||
The HTML representation of an image in rich text can be customised - for example, to display captions or custom fields.
|
||||
|
||||
To do this requires subclassing ``Format`` (see :ref:`rich_text_image_formats`), and overriding its ``image_to_html`` method.
|
||||
|
||||
You may then register formats of your subclass using ``register_image_format`` as usual.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# image_formats.py
|
||||
from wagtail.images.formats import Format, register_image_format
|
||||
|
||||
|
||||
class SubclassedImageFormat(Format):
|
||||
|
||||
def image_to_html(self, image, alt_text, extra_attributes=None):
|
||||
|
||||
custom_html = # the custom HTML representation of your image here
|
||||
# in Format, the image's rendition.img_tag(extra_attributes) is used to generate the HTML
|
||||
# representation
|
||||
|
||||
return custom_html
|
||||
|
||||
|
||||
register_image_format(
|
||||
SubclassedImageFormat('subclassed_format', 'Subclassed Format', classnames, filter_spec)
|
||||
)
|
||||
|
||||
As an example, let's say you want the alt text to be displayed as a caption for the image as well:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# image_formats.py
|
||||
from django.utils.html import format_html
|
||||
from wagtail.images.formats import Format, register_image_format
|
||||
|
||||
|
||||
class CaptionedImageFormat(Format):
|
||||
|
||||
def image_to_html(self, image, alt_text, extra_attributes=None):
|
||||
|
||||
default_html = super().image_to_html(image, alt_text, extra_attributes)
|
||||
|
||||
return format_html("{}<figcaption>{}</figcaption>", default_html, alt_text)
|
||||
|
||||
|
||||
register_image_format(
|
||||
CaptionedImageFormat('captioned_fullwidth', 'Full width captioned', 'bodytext-image', 'width-750')
|
||||
)
|
||||
|
||||
.. note::
|
||||
Any custom HTML image features will not be displayed in the Draftail editor, only on the published page.
|
||||
|
|
@ -7,8 +7,8 @@ to images.
|
|||
|
||||
To do this, you need to add two models to your project:
|
||||
|
||||
- The image model itself that inherits from `wagtail.images.models.AbstractImage`. This is where you would add your additional fields
|
||||
- The renditions model that inherits from `wagtail.images.models.AbstractRendition`. This is used to store renditions for the new model.
|
||||
- The image model itself that inherits from `wagtail.images.models.AbstractImage`. This is where you would add your additional fields
|
||||
- The renditions model that inherits from `wagtail.images.models.AbstractRendition`. This is used to store renditions for the new model.
|
||||
|
||||
Here's an example:
|
||||
|
||||
|
|
@ -66,4 +66,4 @@ work as before but would need to be updated in order to see any new images.
|
|||
.. autofunction:: get_image_model
|
||||
|
||||
.. autofunction:: get_image_model_string
|
||||
```
|
||||
```
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
(image_feature_detection)=
|
||||
|
||||
# Feature Detection
|
||||
|
||||
Wagtail has the ability to automatically detect faces and features inside your images and crop the images to those features.
|
||||
|
||||
Feature detection uses third-party tools to detect faces/features in an image when the image is uploaded. The detected features are stored internally as a focal point in the `focal_point_{x, y, width, height}` fields on the `Image` model. These fields are used by the `fill` image filter when an image is rendered in a template to crop the image.
|
||||
|
||||
## Installation
|
||||
|
||||
Two third-party tools are known to work with Wagtail: One based on [OpenCV](https://opencv.org/) for general feature detection and one based on [Rustface](https://github.com/torchbox/rustface-py/) for face detection.
|
||||
|
||||
### OpenCV on Debian/Ubuntu
|
||||
|
||||
Feature detection requires [OpenCV](https://opencv.org/) which can be a bit tricky to install as it's not currently pip-installable.
|
||||
|
||||
There is more than one way to install these components, but in each case you will need to test that both OpenCV itself _and_ the Python interface have been correctly installed.
|
||||
|
||||
#### Install `opencv-python`
|
||||
|
||||
[opencv-python](https://pypi.org/project/opencv-python/) is available on PyPI.
|
||||
It includes a Python interface to OpenCV, as well as the statically-built OpenCV binaries themselves.
|
||||
|
||||
To install:
|
||||
|
||||
```console
|
||||
$ pip install opencv-python
|
||||
```
|
||||
|
||||
Depending on what else is installed on your system, this may be all that is required. On lighter-weight Linux systems, you may need to identify and install missing system libraries (for example, a slim version of Debian Stretch requires `libsm6 libxrender1 libxext6` to be installed with `apt`).
|
||||
|
||||
#### Install a system-level package
|
||||
|
||||
A system-level package can take care of all of the required components. Check what is available for your operating system. For example, [python-opencv](https://packages.debian.org/stretch/python-opencv) is available for Debian; it installs OpenCV itself, and sets up Python bindings.
|
||||
|
||||
However, it may make incorrect assumptions about how you're using Python (for example, which version you're using) - test as described below.
|
||||
|
||||
#### Testing the installation
|
||||
|
||||
Test the installation:
|
||||
|
||||
```python
|
||||
python3
|
||||
>>> import cv2
|
||||
```
|
||||
|
||||
An error such as:
|
||||
|
||||
```python
|
||||
ImportError: libSM.so.6: cannot open shared object file: No such file or directory
|
||||
```
|
||||
|
||||
indicates that a required system library (in this case `libsm6`) has not been installed.
|
||||
|
||||
On the other hand,
|
||||
|
||||
```python
|
||||
ModuleNotFoundError: No module named 'cv2'
|
||||
```
|
||||
|
||||
means that the Python components have not been set up correctly in your Python environment.
|
||||
|
||||
If you don't get an import error, installation has probably been successful.
|
||||
|
||||
### Rustface
|
||||
|
||||
[Rustface](https://github.com/torchbox/rustface-py/) is Python library with prebuilt wheel files provided for Linux and macOS. Although implemented in Rust it is pip-installable:
|
||||
|
||||
```console
|
||||
$ pip install wheel
|
||||
$ pip install rustface
|
||||
```
|
||||
|
||||
#### Registering with Willow
|
||||
|
||||
Rustface provides a plug-in that needs to be registered with [Willow](https://github.com/wagtail/Willow).
|
||||
|
||||
This should be done somewhere that gets run on application startup:
|
||||
|
||||
```python
|
||||
from willow.registry import registry
|
||||
import rustface.willow
|
||||
|
||||
registry.register_plugin(rustface.willow)
|
||||
```
|
||||
|
||||
For example, in an app's [AppConfig.ready](https://docs.djangoproject.com/en/2.2/ref/applications/#django.apps.AppConfig.ready).
|
||||
|
||||
## Cropping
|
||||
|
||||
The face detection algorithm produces a focal area that is tightly cropped to the face rather than the whole head.
|
||||
|
||||
For images with a single face this can be okay in some cases, e.g. thumbnails, it might be overly tight for "headshots".
|
||||
Image renditions can encompass more of the head by reducing the crop percentage (`-c<percentage>`), at the end of the resize-rule, down to as low as 0%:
|
||||
|
||||
```html+django
|
||||
{% image page.photo fill-200x200-c0 %}
|
||||
```
|
||||
|
||||
## Switching on feature detection in Wagtail
|
||||
|
||||
Once installed, you need to set the `WAGTAILIMAGES_FEATURE_DETECTION_ENABLED` setting to `True` to automatically detect faces/features whenever a new image is uploaded in to Wagtail or when an image without a focal point is saved (this is done via a pre-save signal handler):
|
||||
|
||||
```python
|
||||
# settings.py
|
||||
|
||||
WAGTAILIMAGES_FEATURE_DETECTION_ENABLED = True
|
||||
```
|
||||
|
||||
## Manually running feature detection
|
||||
|
||||
If you already have images in your Wagtail site and would like to run feature detection on them, or you want to apply feature detection selectively when the `WAGTAILIMAGES_FEATURE_DETECTION_ENABLED` is set to `False` you can run it manually using the `get_suggested_focal_point()` method on the `Image` model.
|
||||
|
||||
For example, you can manually run feature detection on all images by running the following code in the python shell:
|
||||
|
||||
```python
|
||||
from wagtail.images import get_image_model
|
||||
|
||||
Image = get_image_model()
|
||||
|
||||
for image in Image.objects.all():
|
||||
if not image.has_focal_point():
|
||||
image.set_focal_point(image.get_suggested_focal_point())
|
||||
image.save()
|
||||
```
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
.. _image_feature_detection:
|
||||
|
||||
Feature Detection
|
||||
=================
|
||||
|
||||
Wagtail has the ability to automatically detect faces and features inside your images and crop the images to those features.
|
||||
|
||||
Feature detection uses third-party tools to detect faces/features in an image when the image is uploaded. The detected features are stored internally as a focal point in the ``focal_point_{x, y, width, height}`` fields on the ``Image`` model. These fields are used by the ``fill`` image filter when an image is rendered in a template to crop the image.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Two third-party tools are known to work with Wagtail: One based on OpenCV_ for general feature detection and one based on Rustface_ for face detection.
|
||||
|
||||
.. _OpenCV: https://opencv.org/
|
||||
|
||||
.. _Rustface: https://github.com/torchbox/rustface-py/
|
||||
|
||||
OpenCV on Debian/Ubuntu
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Feature detection requires OpenCV_ which can be a bit tricky to install as it's not currently pip-installable.
|
||||
|
||||
There is more than one way to install these components, but in each case you will need to test that both OpenCV itself *and* the Python interface have been correctly installed.
|
||||
|
||||
|
||||
Install ``opencv-python``
|
||||
`````````````````````````
|
||||
|
||||
`opencv-python <https://pypi.org/project/opencv-python/>`_ is available on PyPI.
|
||||
It includes a Python interface to OpenCV, as well as the statically-built OpenCV binaries themselves.
|
||||
|
||||
To install:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install opencv-python
|
||||
|
||||
Depending on what else is installed on your system, this may be all that is required. On lighter-weight Linux systems, you may need to identify and install missing system libraries (for example, a slim version of Debian Stretch requires ``libsm6 libxrender1 libxext6`` to be installed with ``apt``).
|
||||
|
||||
|
||||
Install a system-level package
|
||||
``````````````````````````````
|
||||
|
||||
A system-level package can take care of all of the required components. Check what is available for your operating system. For example, `python-opencv <https://packages.debian.org/stretch/python-opencv>`_ is available for Debian; it installs OpenCV itself, and sets up Python bindings.
|
||||
|
||||
However, it may make incorrect assumptions about how you're using Python (for example, which version you're using) - test as described below.
|
||||
|
||||
|
||||
Testing the installation
|
||||
````````````````````````
|
||||
|
||||
Test the installation::
|
||||
|
||||
python3
|
||||
>>> import cv2
|
||||
|
||||
An error such as::
|
||||
|
||||
ImportError: libSM.so.6: cannot open shared object file: No such file or directory
|
||||
|
||||
indicates that a required system library (in this case ``libsm6``) has not been installed.
|
||||
|
||||
On the other hand,
|
||||
|
||||
::
|
||||
|
||||
ModuleNotFoundError: No module named 'cv2'
|
||||
|
||||
means that the Python components have not been set up correctly in your Python environment.
|
||||
|
||||
If you don't get an import error, installation has probably been successful.
|
||||
|
||||
|
||||
Rustface
|
||||
^^^^^^^^
|
||||
|
||||
Rustface_ is Python library with prebuilt wheel files provided for Linux and macOS. Although implemented in Rust it is pip-installable:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install wheel
|
||||
$ pip install rustface
|
||||
|
||||
|
||||
Registering with Willow
|
||||
```````````````````````
|
||||
|
||||
Rustface provides a plug-in that needs to be registered with Willow_.
|
||||
|
||||
This should be done somewhere that gets run on application startup:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from willow.registry import registry
|
||||
import rustface.willow
|
||||
|
||||
registry.register_plugin(rustface.willow)
|
||||
|
||||
For example, in an app's AppConfig.ready_.
|
||||
|
||||
.. _Willow: https://github.com/wagtail/Willow
|
||||
|
||||
.. _AppConfig.ready: https://docs.djangoproject.com/en/2.2/ref/applications/#django.apps.AppConfig.ready
|
||||
|
||||
|
||||
Cropping
|
||||
--------
|
||||
|
||||
The face detection algorithm produces a focal area that is tightly cropped to the face rather than the whole head.
|
||||
|
||||
For images with a single face this can be okay in some cases, e.g. thumbnails, it might be overly tight for "headshots".
|
||||
Image renditions can encompass more of the head by reducing the crop percentage (``-c<percentage>``), at the end of the resize-rule, down to as low as 0%:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% image page.photo fill-200x200-c0 %}
|
||||
|
||||
|
||||
Switching on feature detection in Wagtail
|
||||
-----------------------------------------
|
||||
|
||||
Once installed, you need to set the ``WAGTAILIMAGES_FEATURE_DETECTION_ENABLED`` setting to ``True`` to automatically detect faces/features whenever a new image is uploaded in to Wagtail or when an image without a focal point is saved (this is done via a pre-save signal handler):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# settings.py
|
||||
|
||||
WAGTAILIMAGES_FEATURE_DETECTION_ENABLED = True
|
||||
|
||||
|
||||
Manually running feature detection
|
||||
----------------------------------
|
||||
|
||||
If you already have images in your Wagtail site and would like to run feature detection on them, or you want to apply feature detection selectively when the ``WAGTAILIMAGES_FEATURE_DETECTION_ENABLED`` is set to ``False`` you can run it manually using the `get_suggested_focal_point()` method on the ``Image`` model.
|
||||
|
||||
For example, you can manually run feature detection on all images by running the following code in the python shell:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.images import get_image_model
|
||||
|
||||
Image = get_image_model()
|
||||
|
||||
for image in Image.objects.all():
|
||||
if not image.has_focal_point():
|
||||
image.set_focal_point(image.get_suggested_focal_point())
|
||||
image.save()
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
# Focal points
|
||||
|
||||
Focal points are used to indicate to Wagtail the area of an image that contains the subject.
|
||||
This is used by the `fill` filter to focus the cropping on the subject, and avoid cropping into it.
|
||||
|
||||
Focal points can be defined manually by a Wagtail user, or automatically by using face or feature detection.
|
||||
|
||||
(rendition_background_position_style)=
|
||||
|
||||
## Setting the `background-position` inline style based on the focal point
|
||||
|
||||
When using a Wagtail image as the background of an element, you can use the `.background_position_style`
|
||||
attribute on the rendition to position the rendition based on the focal point in the image:
|
||||
|
||||
```html+django
|
||||
{% image page.image width-1024 as image %}
|
||||
|
||||
<div style="background-image: url('{{ image.url }}'); {{ image.background_position_style }}">
|
||||
</div>
|
||||
```
|
||||
|
||||
## Accessing the focal point in templates
|
||||
|
||||
You can access the focal point in the template by accessing the `.focal_point` attribute of a rendition:
|
||||
|
||||
```html+django
|
||||
{% load wagtailimages %}
|
||||
|
||||
{% image myimage width-800 as myrendition %}
|
||||
|
||||
<img
|
||||
src="{{ myrendition.url }}"
|
||||
alt="{{ myimage.title }}"
|
||||
{% if myrendition.focal_point %}
|
||||
data-focus-x="{{ myrendition.focal_point.centroid.x }}"
|
||||
data-focus-y="{{ myrendition.focal_point.centroid.y }}"
|
||||
data-focus-width="{{ myrendition.focal_point.width }}"
|
||||
data-focus-height="{{ myrendition.focal_point.height }}"
|
||||
{% endif %}
|
||||
/>
|
||||
```
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
Focal points
|
||||
============
|
||||
|
||||
Focal points are used to indicate to Wagtail the area of an image that contains the subject.
|
||||
This is used by the ``fill`` filter to focus the cropping on the subject, and avoid cropping into it.
|
||||
|
||||
Focal points can be defined manually by a Wagtail user, or automatically by using face or feature detection.
|
||||
|
||||
.. _rendition_background_position_style:
|
||||
|
||||
Setting the ``background-position`` inline style based on the focal point
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
When using a Wagtail image as the background of an element, you can use the ``.background_position_style``
|
||||
attribute on the rendition to position the rendition based on the focal point in the image:
|
||||
|
||||
.. code-block:: html+Django
|
||||
|
||||
{% image page.image width-1024 as image %}
|
||||
|
||||
<div style="background-image: url('{{ image.url }}'); {{ image.background_position_style }}">
|
||||
</div>
|
||||
|
||||
Accessing the focal point in templates
|
||||
--------------------------------------
|
||||
|
||||
You can access the focal point in the template by accessing the ``.focal_point`` attribute of a rendition:
|
||||
|
||||
.. code-block:: html+Django
|
||||
|
||||
{% load wagtailimages %}
|
||||
|
||||
{% image myimage width-800 as myrendition %}
|
||||
|
||||
<img
|
||||
src="{{ myrendition.url }}"
|
||||
alt="{{ myimage.title }}"
|
||||
{% if myrendition.focal_point %}
|
||||
data-focus-x="{{ myrendition.focal_point.centroid.x }}"
|
||||
data-focus-y="{{ myrendition.focal_point.centroid.y }}"
|
||||
data-focus-width="{{ myrendition.focal_point.width }}"
|
||||
data-focus-height="{{ myrendition.focal_point.height }}"
|
||||
{% endif %}
|
||||
/>
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
(image_file_formats)=
|
||||
|
||||
# Image file formats
|
||||
|
||||
## Using the picture element
|
||||
|
||||
The [picture element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture)
|
||||
can be used with the `format-<type>` image operation to specify different
|
||||
image formats and let the browser choose the one it prefers. For example:
|
||||
|
||||
```python
|
||||
{% load wagtailimages_tags %}
|
||||
|
||||
<picture>
|
||||
{% image myimage width-1000 format-webp as image_webp %}
|
||||
<source srcset="{{ image_webp.url }}" type="image/webp">
|
||||
|
||||
{% image myimage width-1000 format-png as image_png %}
|
||||
<source srcset="{{ image_png.url }}" type="image/png">
|
||||
|
||||
{% image myimage width-1000 format-png %}
|
||||
</picture>
|
||||
```
|
||||
|
||||
### Customising output formats
|
||||
|
||||
By default all `bmp` and `webp` images are converted to the `png` format
|
||||
when no image output format is given.
|
||||
|
||||
The default conversion mapping can be changed by setting the
|
||||
`WAGTAILIMAGES_FORMAT_CONVERSIONS` to a dictionary which maps the input type
|
||||
to an output type.
|
||||
|
||||
For example:
|
||||
|
||||
```python
|
||||
WAGTAILIMAGES_FORMAT_CONVERSIONS = {
|
||||
'bmp': 'jpeg',
|
||||
'webp': 'webp',
|
||||
}
|
||||
```
|
||||
|
||||
will convert `bmp` images to `jpeg` and disable the default `webp`
|
||||
to `png` conversion.
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
.. _image_file_formats:
|
||||
|
||||
Image file formats
|
||||
==================
|
||||
|
||||
Using the picture element
|
||||
-------------------------
|
||||
|
||||
The `picture element <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture>`_
|
||||
can be used with the ``format-<type>`` image operation to specify different
|
||||
image formats and let the browser choose the one it prefers. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
{% load wagtailimages_tags %}
|
||||
|
||||
<picture>
|
||||
{% image myimage width-1000 format-webp as image_webp %}
|
||||
<source srcset="{{ image_webp.url }}" type="image/webp">
|
||||
|
||||
{% image myimage width-1000 format-png as image_png %}
|
||||
<source srcset="{{ image_png.url }}" type="image/png">
|
||||
|
||||
{% image myimage width-1000 format-png %}
|
||||
</picture>
|
||||
|
||||
Customising output formats
|
||||
--------------------------
|
||||
|
||||
By default all ``bmp`` and ``webp`` images are converted to the ``png`` format
|
||||
when no image output format is given.
|
||||
|
||||
The default conversion mapping can be changed by setting the
|
||||
``WAGTAILIMAGES_FORMAT_CONVERSIONS`` to a dictionary which maps the input type
|
||||
to an output type.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
WAGTAILIMAGES_FORMAT_CONVERSIONS = {
|
||||
'bmp': 'jpeg',
|
||||
'webp': 'webp',
|
||||
}
|
||||
|
||||
will convert ``bmp`` images to ``jpeg`` and disable the default ``webp``
|
||||
to ``png`` conversion.
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
(using_images_outside_wagtail)=
|
||||
|
||||
# Dynamic image serve view
|
||||
|
||||
In most cases, developers wanting to generate image renditions in Python should use the `get_rendition()`
|
||||
method. See [](image_renditions).
|
||||
|
||||
If you need to be able to generate image versions for an _external_ system such as a blog or mobile app,
|
||||
Wagtail provides a view for dynamically generating renditions of images by calling a unique URL.
|
||||
|
||||
The view takes an image id, filter spec and security signature in the URL. If
|
||||
these parameters are valid, it serves an image file matching that criteria.
|
||||
|
||||
Like the `{% image %}` tag, the rendition is generated on the first call and
|
||||
subsequent calls are served from a cache.
|
||||
|
||||
## Setup
|
||||
|
||||
Add an entry for the view into your URLs configuration:
|
||||
|
||||
```python
|
||||
from wagtail.images.views.serve import ServeView
|
||||
|
||||
urlpatterns = [
|
||||
...
|
||||
|
||||
re_path(r'^images/([^/]*)/(\d*)/([^/]*)/[^/]*$', ServeView.as_view(), name='wagtailimages_serve'),
|
||||
|
||||
...
|
||||
|
||||
# Ensure that the wagtailimages_serve line appears above the default Wagtail page serving route
|
||||
re_path(r'', include(wagtail_urls)),
|
||||
]
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Image URL generator UI
|
||||
|
||||
When the dynamic serve view is enabled, an image URL generator in the admin
|
||||
interface becomes available automatically. This can be accessed through the edit
|
||||
page of any image by clicking the "URL generator" button on the right hand side.
|
||||
|
||||
This interface allows editors to generate URLs to cropped versions of the image.
|
||||
|
||||
### Generating dynamic image URLs in Python
|
||||
|
||||
Dynamic image URLs can also be generated using Python code and served to a
|
||||
client over an API or used directly in the template.
|
||||
|
||||
One advantage of using dynamic image URLs in the template is that they do not
|
||||
block the initial response while rendering like the `{% image %}` tag does.
|
||||
|
||||
The `generate_image_url` function in `wagtail.images.views.serve` is a convenience
|
||||
method to generate a dynamic image URL.
|
||||
|
||||
Here's an example of this being used in a view:
|
||||
|
||||
```python
|
||||
def display_image(request, image_id):
|
||||
image = get_object_or_404(Image, id=image_id)
|
||||
|
||||
return render(request, 'display_image.html', {
|
||||
'image_url': generate_image_url(image, 'fill-100x100')
|
||||
})
|
||||
```
|
||||
|
||||
Image operations can be chained by joining them with a `|` character:
|
||||
|
||||
```python
|
||||
return render(request, 'display_image.html', {
|
||||
'image_url': generate_image_url(image, 'fill-100x100|jpegquality-40')
|
||||
})
|
||||
```
|
||||
|
||||
In your templates:
|
||||
|
||||
```html+django
|
||||
{% load wagtailimages_tags %}
|
||||
...
|
||||
|
||||
<!-- Get the url for the image scaled to a width of 400 pixels: -->
|
||||
{% image_url page.photo "width-400" %}
|
||||
|
||||
<!-- Again, but this time as a square thumbnail: -->
|
||||
{% image_url page.photo "fill-100x100|jpegquality-40" %}
|
||||
|
||||
<!-- This time using our custom image serve view: -->
|
||||
{% image_url page.photo "width-400" "mycustomview_serve" %}
|
||||
```
|
||||
|
||||
You can pass an optional view name that will be used to serve the image through. The default is `wagtailimages_serve`
|
||||
|
||||
## Advanced configuration
|
||||
|
||||
(image_serve_view_redirect_action)=
|
||||
|
||||
### Making the view redirect instead of serve
|
||||
|
||||
By default, the view will serve the image file directly. This behaviour can be
|
||||
changed to a 301 redirect instead which may be useful if you host your images
|
||||
externally.
|
||||
|
||||
To enable this, pass `action='redirect'` into the `ServeView.as_view()`
|
||||
method in your urls configuration:
|
||||
|
||||
```python
|
||||
from wagtail.images.views.serve import ServeView
|
||||
|
||||
urlpatterns = [
|
||||
...
|
||||
|
||||
re_path(r'^images/([^/]*)/(\d*)/([^/]*)/[^/]*$', ServeView.as_view(action='redirect'), name='wagtailimages_serve'),
|
||||
]
|
||||
```
|
||||
|
||||
(image_serve_view_sendfile)=
|
||||
|
||||
## Integration with django-sendfile
|
||||
|
||||
[django-sendfile](https://github.com/johnsensible/django-sendfile) offloads the job of transferring the image data to the web
|
||||
server instead of serving it directly from the Django application. This could
|
||||
greatly reduce server load in situations where your site has many images being
|
||||
downloaded but you're unable to use a [](caching_proxy) or a CDN.
|
||||
|
||||
You firstly need to install and configure django-sendfile and configure your
|
||||
web server to use it. If you haven't done this already, please refer to the
|
||||
[installation docs](https://github.com/johnsensible/django-sendfile#django-sendfile).
|
||||
|
||||
To serve images with django-sendfile, you can use the `SendFileView` class.
|
||||
This view can be used out of the box:
|
||||
|
||||
```python
|
||||
from wagtail.images.views.serve import SendFileView
|
||||
|
||||
urlpatterns = [
|
||||
...
|
||||
|
||||
re_path(r'^images/([^/]*)/(\d*)/([^/]*)/[^/]*$', SendFileView.as_view(), name='wagtailimages_serve'),
|
||||
]
|
||||
```
|
||||
|
||||
You can customise it to override the backend defined in the `SENDFILE_BACKEND`
|
||||
setting:
|
||||
|
||||
```python
|
||||
from wagtail.images.views.serve import SendFileView
|
||||
from project.sendfile_backends import MyCustomBackend
|
||||
|
||||
class MySendFileView(SendFileView):
|
||||
backend = MyCustomBackend
|
||||
```
|
||||
|
||||
You can also customise it to serve private files. For example, if the only need
|
||||
is to be authenticated (e.g. for Django >= 1.9):
|
||||
|
||||
```python
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from wagtail.images.views.serve import SendFileView
|
||||
|
||||
class PrivateSendFileView(LoginRequiredMixin, SendFileView):
|
||||
raise_exception = True
|
||||
```
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
.. _using_images_outside_wagtail:
|
||||
|
||||
========================
|
||||
Dynamic image serve view
|
||||
========================
|
||||
|
||||
In most cases, developers wanting to generate image renditions in Python should use the ``get_rendition()``
|
||||
method. See :ref:`image_renditions`.
|
||||
|
||||
If you need to be able to generate image versions for an *external* system such as a blog or mobile app,
|
||||
Wagtail provides a view for dynamically generating renditions of images by calling a unique URL.
|
||||
|
||||
The view takes an image id, filter spec and security signature in the URL. If
|
||||
these parameters are valid, it serves an image file matching that criteria.
|
||||
|
||||
Like the ``{% image %}`` tag, the rendition is generated on the first call and
|
||||
subsequent calls are served from a cache.
|
||||
|
||||
Setup
|
||||
=====
|
||||
|
||||
Add an entry for the view into your URLs configuration:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.images.views.serve import ServeView
|
||||
|
||||
urlpatterns = [
|
||||
...
|
||||
|
||||
re_path(r'^images/([^/]*)/(\d*)/([^/]*)/[^/]*$', ServeView.as_view(), name='wagtailimages_serve'),
|
||||
|
||||
...
|
||||
|
||||
# Ensure that the wagtailimages_serve line appears above the default Wagtail page serving route
|
||||
re_path(r'', include(wagtail_urls)),
|
||||
]
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Image URL generator UI
|
||||
----------------------
|
||||
|
||||
When the dynamic serve view is enabled, an image URL generator in the admin
|
||||
interface becomes available automatically. This can be accessed through the edit
|
||||
page of any image by clicking the "URL generator" button on the right hand side.
|
||||
|
||||
This interface allows editors to generate URLs to cropped versions of the image.
|
||||
|
||||
Generating dynamic image URLs in Python
|
||||
---------------------------------------
|
||||
|
||||
Dynamic image URLs can also be generated using Python code and served to a
|
||||
client over an API or used directly in the template.
|
||||
|
||||
One advantage of using dynamic image URLs in the template is that they do not
|
||||
block the initial response while rendering like the ``{% image %}`` tag does.
|
||||
|
||||
The ``generate_image_url`` function in ``wagtail.images.views.serve`` is a convenience
|
||||
method to generate a dynamic image URL.
|
||||
|
||||
Here's an example of this being used in a view:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def display_image(request, image_id):
|
||||
image = get_object_or_404(Image, id=image_id)
|
||||
|
||||
return render(request, 'display_image.html', {
|
||||
'image_url': generate_image_url(image, 'fill-100x100')
|
||||
})
|
||||
|
||||
|
||||
Image operations can be chained by joining them with a ``|`` character:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
return render(request, 'display_image.html', {
|
||||
'image_url': generate_image_url(image, 'fill-100x100|jpegquality-40')
|
||||
})
|
||||
|
||||
|
||||
In your templates:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% load wagtailimages_tags %}
|
||||
...
|
||||
|
||||
<!-- Get the url for the image scaled to a width of 400 pixels: -->
|
||||
{% image_url page.photo "width-400" %}
|
||||
|
||||
<!-- Again, but this time as a square thumbnail: -->
|
||||
{% image_url page.photo "fill-100x100|jpegquality-40" %}
|
||||
|
||||
<!-- This time using our custom image serve view: -->
|
||||
{% image_url page.photo "width-400" "mycustomview_serve" %}
|
||||
|
||||
You can pass an optional view name that will be used to serve the image through. The default is ``wagtailimages_serve``
|
||||
|
||||
Advanced configuration
|
||||
======================
|
||||
|
||||
.. _image_serve_view_redirect_action:
|
||||
|
||||
Making the view redirect instead of serve
|
||||
-----------------------------------------
|
||||
|
||||
By default, the view will serve the image file directly. This behaviour can be
|
||||
changed to a 301 redirect instead which may be useful if you host your images
|
||||
externally.
|
||||
|
||||
To enable this, pass ``action='redirect'`` into the ``ServeView.as_view()``
|
||||
method in your urls configuration:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.images.views.serve import ServeView
|
||||
|
||||
urlpatterns = [
|
||||
...
|
||||
|
||||
re_path(r'^images/([^/]*)/(\d*)/([^/]*)/[^/]*$', ServeView.as_view(action='redirect'), name='wagtailimages_serve'),
|
||||
]
|
||||
|
||||
.. _image_serve_view_sendfile:
|
||||
|
||||
Integration with django-sendfile
|
||||
--------------------------------
|
||||
|
||||
`django-sendfile`_ offloads the job of transferring the image data to the web
|
||||
server instead of serving it directly from the Django application. This could
|
||||
greatly reduce server load in situations where your site has many images being
|
||||
downloaded but you're unable to use a :ref:`caching_proxy` or a CDN.
|
||||
|
||||
.. _django-sendfile: https://github.com/johnsensible/django-sendfile
|
||||
|
||||
You firstly need to install and configure django-sendfile and configure your
|
||||
web server to use it. If you haven't done this already, please refer to the
|
||||
`installation docs <https://github.com/johnsensible/django-sendfile#django-sendfile>`_.
|
||||
|
||||
To serve images with django-sendfile, you can use the ``SendFileView`` class.
|
||||
This view can be used out of the box:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.images.views.serve import SendFileView
|
||||
|
||||
urlpatterns = [
|
||||
...
|
||||
|
||||
re_path(r'^images/([^/]*)/(\d*)/([^/]*)/[^/]*$', SendFileView.as_view(), name='wagtailimages_serve'),
|
||||
]
|
||||
|
||||
You can customise it to override the backend defined in the ``SENDFILE_BACKEND``
|
||||
setting:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.images.views.serve import SendFileView
|
||||
from project.sendfile_backends import MyCustomBackend
|
||||
|
||||
class MySendFileView(SendFileView):
|
||||
backend = MyCustomBackend
|
||||
|
||||
You can also customise it to serve private files. For example, if the only need
|
||||
is to be authenticated (e.g. for Django >= 1.9):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from wagtail.images.views.serve import SendFileView
|
||||
|
||||
class PrivateSendFileView(LoginRequiredMixin, SendFileView):
|
||||
raise_exception = True
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# Images
|
||||
|
||||
```{toctree}
|
||||
---
|
||||
maxdepth: 2
|
||||
---
|
||||
renditions
|
||||
animated_gifs
|
||||
image_file_formats
|
||||
custom_image_model
|
||||
changing_rich_text_representation
|
||||
feature_detection
|
||||
image_serve_view
|
||||
focal_points
|
||||
title_generation_on_upload
|
||||
```
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
Images
|
||||
======
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
renditions
|
||||
animated_gifs
|
||||
image_file_formats
|
||||
custom_image_model
|
||||
changing_rich_text_representation
|
||||
feature_detection
|
||||
image_serve_view
|
||||
focal_points
|
||||
title_generation_on_upload
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
(image_renditions)=
|
||||
|
||||
# Generating renditions in Python
|
||||
|
||||
Rendered versions of original images generated by the Wagtail `{% image %}` template tag are called "renditions",
|
||||
and are stored as new image files in the site's `[media]/images` directory on the first invocation.
|
||||
|
||||
Image renditions can also be generated dynamically from Python via the native `get_rendition()` method, for example:
|
||||
|
||||
```python
|
||||
newimage = myimage.get_rendition('fill-300x150|jpegquality-60')
|
||||
```
|
||||
|
||||
If `myimage` had a filename of `foo.jpg`, a new rendition of the image file called
|
||||
`foo.fill-300x150.jpegquality-60.jpg` would be generated and saved into the site's `[media]/images` directory.
|
||||
Argument options are identical to the `{% image %}` template tag's filter spec, and should be separated with `|`.
|
||||
|
||||
The generated `Rendition` object will have properties specific to that version of the image, such as
|
||||
`url`, `width` and `height`, so something like this could be used in an API generator, for example:
|
||||
|
||||
```python
|
||||
url = myimage.get_rendition('fill-300x186|jpegquality-60').url
|
||||
```
|
||||
|
||||
Properties belonging to the original image from which the generated Rendition was created, such as `title`, can
|
||||
be accessed through the Rendition's `image` property:
|
||||
|
||||
```python
|
||||
>>> newimage.image.title
|
||||
'Blue Sky'
|
||||
>>> newimage.image.is_landscape()
|
||||
True
|
||||
```
|
||||
|
||||
See also: [](image_tag)
|
||||
|
||||
(prefetching_image_renditions)=
|
||||
|
||||
## Prefetching image renditions
|
||||
|
||||
```{versionadded} 3.0
|
||||
This following guidance is only applicable in Wagtail versions 3.0 and above.
|
||||
```
|
||||
|
||||
When using a queryset to render a list of objects with images, you can make use of Django's built-in `prefetch_related()` queryset method to prefetch the renditions needed for rendering with a single additional query. For long lists of items, or where multiple renditions are used for each item, this can provide a significant boost to performance.
|
||||
|
||||
For example, say you were rendering a list of events (with thumbnail images for each). Your code might look something like this:
|
||||
|
||||
```python
|
||||
def get_events():
|
||||
return EventPage.objects.live().select_related("listing_image")
|
||||
```
|
||||
|
||||
The above can be modified slightly to prefetch the renditions for listing images:
|
||||
|
||||
```python
|
||||
def get_events():
|
||||
return EventPage.objects.live().select_related("listing_image").prefetch_related("listing_image__renditions")
|
||||
```
|
||||
|
||||
If images in your project tend to have very large numbers of renditions, and you know in advance the ones you need, you might want to consider using a `Prefetch` object to select only the renditions you need for rendering. For example:
|
||||
|
||||
```python
|
||||
from django.db.models import Prefetch
|
||||
from wagtail.images import get_image_model
|
||||
|
||||
|
||||
def get_events():
|
||||
# These are the renditions required for rendering
|
||||
renditions_queryset = get_image_model().get_rendition_model().objects.filter(
|
||||
filter_spec__in=["fill-300x186", "fill-600x400", "fill-940x680"]
|
||||
)
|
||||
|
||||
# `Prefetch` is used to fetch only the required renditions
|
||||
return EventPage.objects.live().select_related("listing_image").prefetch_related(
|
||||
Prefetch("listing_image__renditions", queryset=renditions_queryset)
|
||||
)
|
||||
```
|
||||
|
||||
(image_rendition_methods)=
|
||||
|
||||
## Model methods involved in rendition generation
|
||||
|
||||
```{versionadded} 3.0
|
||||
The following method references are only applicable to Wagtail versions 3.0 and above.
|
||||
```
|
||||
|
||||
The following `AbstractImage` model methods are involved in finding and generating a renditions. If using a custom image model, you can customise the behaviour of either of these methods by overriding them on your model:
|
||||
|
||||
```{eval-rst}
|
||||
.. automodule:: wagtail.images.models
|
||||
|
||||
.. class:: AbstractImage
|
||||
:noindex:
|
||||
|
||||
.. automethod:: get_rendition
|
||||
|
||||
.. automethod:: find_existing_rendition
|
||||
|
||||
.. automethod:: create_rendition
|
||||
|
||||
.. automethod:: generate_rendition_file
|
||||
```
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
.. _image_renditions:
|
||||
|
||||
Generating renditions in Python
|
||||
=====================================
|
||||
|
||||
Rendered versions of original images generated by the Wagtail ``{% image %}`` template tag are called "renditions",
|
||||
and are stored as new image files in the site's ``[media]/images`` directory on the first invocation.
|
||||
|
||||
Image renditions can also be generated dynamically from Python via the native ``get_rendition()`` method, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
newimage = myimage.get_rendition('fill-300x150|jpegquality-60')
|
||||
|
||||
If ``myimage`` had a filename of ``foo.jpg``, a new rendition of the image file called
|
||||
``foo.fill-300x150.jpegquality-60.jpg`` would be generated and saved into the site's ``[media]/images`` directory.
|
||||
Argument options are identical to the ``{% image %}`` template tag's filter spec, and should be separated with ``|``.
|
||||
|
||||
The generated ``Rendition`` object will have properties specific to that version of the image, such as
|
||||
``url``, ``width`` and ``height``, so something like this could be used in an API generator, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
url = myimage.get_rendition('fill-300x186|jpegquality-60').url
|
||||
|
||||
Properties belonging to the original image from which the generated Rendition was created, such as ``title``, can
|
||||
be accessed through the Rendition's ``image`` property:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> newimage.image.title
|
||||
'Blue Sky'
|
||||
>>> newimage.image.is_landscape()
|
||||
True
|
||||
|
||||
See also: :ref:`image_tag`
|
||||
|
||||
.. _prefetching_image_renditions:
|
||||
|
||||
Prefetching image renditions
|
||||
----------------------------
|
||||
|
||||
.. versionadded:: 3.0
|
||||
This following guidance is only applicable in Wagtail versions 3.0 and above.
|
||||
|
||||
When using a queryset to render a list of objects with images, you can make use of Django's built-in ``prefetch_related()`` queryset method to prefetch the renditions needed for rendering with a single additional query. For long lists of items, or where multiple renditions are used for each item, this can provide a significant boost to performance.
|
||||
|
||||
For example, say you were rendering a list of events (with thumbnail images for each). Your code might look something like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def get_events():
|
||||
return EventPage.objects.live().select_related("listing_image")
|
||||
|
||||
The above can be modified slightly to prefetch the renditions for listing images:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def get_events():
|
||||
return EventPage.objects.live().select_related("listing_image").prefetch_related("listing_image__renditions")
|
||||
|
||||
If images in your project tend to have very large numbers of renditions, and you know in advance the ones you need, you might want to consider using a ``Prefetch`` object to select only the renditions you need for rendering. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.db.models import Prefetch
|
||||
from wagtail.images import get_image_model
|
||||
|
||||
|
||||
def get_events():
|
||||
# These are the renditions required for rendering
|
||||
renditions_queryset = get_image_model().get_rendition_model().objects.filter(
|
||||
filter_spec__in=["fill-300x186", "fill-600x400", "fill-940x680"]
|
||||
)
|
||||
|
||||
# `Prefetch` is used to fetch only the required renditions
|
||||
return EventPage.objects.live().select_related("listing_image").prefetch_related(
|
||||
Prefetch("listing_image__renditions", queryset=renditions_queryset)
|
||||
)
|
||||
|
||||
.. _image_rendition_methods:
|
||||
|
||||
Model methods involved in rendition generation
|
||||
----------------------------------------------
|
||||
|
||||
.. versionadded:: 3.0
|
||||
The following method references are only applicable to Wagtail versions 3.0 and above.
|
||||
|
||||
The following ``AbstractImage`` model methods are involved in finding and generating a renditions. If using a custom image model, you can customise the behaviour of either of these methods by overriding them on your model:
|
||||
|
||||
.. automodule:: wagtail.images.models
|
||||
|
||||
.. class:: AbstractImage
|
||||
:noindex:
|
||||
|
||||
.. automethod:: get_rendition
|
||||
|
||||
.. automethod:: find_existing_rendition
|
||||
|
||||
.. automethod:: create_rendition
|
||||
|
||||
.. automethod:: generate_rendition_file
|
||||
Ładowanie…
Reference in New Issue