diff --git a/pelican/plugins/image_process/image_process.py b/pelican/plugins/image_process/image_process.py
index 82b7c93..9dac200 100644
--- a/pelican/plugins/image_process/image_process.py
+++ b/pelican/plugins/image_process/image_process.py
@@ -429,7 +429,12 @@ def process_img_tag(img, settings, derivative):
if not isinstance(process, list):
process = process["ops"]
- process_image((path.source, destination, process), settings)
+ image_size = process_image((path.source, destination, process), settings)
+ if image_size:
+ if "width" not in img.attrs:
+ img["width"] = image_size[0]
+ if "height" not in img.attrs:
+ img["height"] = image_size[1]
def format_srcset_element(path, condition):
@@ -695,6 +700,12 @@ def try_open_image(path):
def process_image(image, settings):
+ """Actually process the image.
+
+ Copies over the Exif tags, if ExifTool is available.
+
+ Returns (int, int): tuple of the width and height of the resulting image.
+ """
# remove URL encoding to get to physical filenames
image = list(image)
image[0] = unquote(image[0])
@@ -714,7 +725,7 @@ def process_image(image, settings):
try:
i = try_open_image(image[0])
except (UnidentifiedImageError, FileNotFoundError):
- return
+ return None
for step in image[2]:
if callable(step):
@@ -731,8 +742,11 @@ def process_image(image, settings):
i.save(image[1], progressive=True)
ExifTool.copy_tags(image[0], image[1])
- else:
- logger.debug(f"{LOG_PREFIX} Skipping {image[0]} -> {image[1]}")
+ return i.width, i.height
+
+ logger.debug(f"{LOG_PREFIX} Skipping {image[0]} -> {image[1]}")
+ i = Image.open(image[1])
+ return i.width, i.height
def dump_config(pelican):
diff --git a/pelican/plugins/image_process/test_image_process.py b/pelican/plugins/image_process/test_image_process.py
index d238363..f3cab2b 100644
--- a/pelican/plugins/image_process/test_image_process.py
+++ b/pelican/plugins/image_process/test_image_process.py
@@ -5,6 +5,7 @@
import subprocess
import warnings
+from bs4 import BeautifulSoup
from PIL import Image, UnidentifiedImageError
import pytest
@@ -196,9 +197,8 @@ def test_path_normalization(mocker, orig_src, orig_img, new_src, new_img):
img_tag_processed = harvest_images_in_fragment(img_tag_orig, settings)
- assert img_tag_processed == (
- f'
'
- )
+ soup = BeautifulSoup(img_tag_processed, "html.parser")
+ assert soup.img["src"] == new_src
process.assert_called_once_with(
(
@@ -299,8 +299,10 @@ def test_path_normalization(mocker, orig_src, orig_img, new_src, new_img):
"orig_tag, new_tag, call_args",
[
(
- '
',
- '
',
+ '
',
+ # Mock height and width added after processing.
+ '
',
[
(
"tmp/test.jpg",
@@ -310,9 +312,11 @@ def test_path_normalization(mocker, orig_src, orig_img, new_src, new_img):
],
),
(
- '
',
- '
',
+ '
',
+ # Pre-existing height and width unchanged after processing.
+ '
',
[
(
"tmp/test.jpg",
@@ -502,6 +506,7 @@ def test_path_normalization(mocker, orig_src, orig_img, new_src, new_img):
def test_html_and_pictures_generation(mocker, orig_tag, new_tag, call_args):
"""Tests that the generated html is as expected and the images are processed."""
process = mocker.patch("pelican.plugins.image_process.image_process.process_image")
+ process.return_value = (512, 384)
settings = get_settings(
IMAGE_PROCESS=COMPLEX_TRANSFORMS, IMAGE_PROCESS_DIR="derivs"
@@ -528,22 +533,23 @@ def test_html_and_pictures_generation(mocker, orig_tag, new_tag, call_args):
#
src attribute with no quotes, spaces or commas.
(
'
',
- '
',
+ '
',
),
#
src attribute with double quotes, spaces and commas.
(
'
',
- '
",
+ '
',
),
#
src attribute with single and double quotes, spaces and commas.
(
'
',
- '
',
+ '
',
),
#
srcset attribute with no quotes, spaces or commas.
(
@@ -647,7 +653,8 @@ def test_special_chars_in_image_path_are_handled_properly(mocker, orig_tag, new_
Related to issue #78 https://github.com/pelican-plugins/image-process/issues/78
"""
- mocker.patch("pelican.plugins.image_process.image_process.process_image")
+ process = mocker.patch("pelican.plugins.image_process.image_process.process_image")
+ process.return_value = (512, 384)
settings = get_settings(
IMAGE_PROCESS=COMPLEX_TRANSFORMS, IMAGE_PROCESS_DIR="derivs"
@@ -776,7 +783,8 @@ def test_try_open_image():
[
(
'
',
- '
',
+ '
',
[ # Default settings.
{},
{"IMAGE_PROCESS_ADD_CLASS": True},
@@ -789,7 +797,8 @@ def test_try_open_image():
),
(
'
',
- '
',
+ '
',
[ # Custom class prefix.
{"IMAGE_PROCESS_CLASS_PREFIX": "custom-prefix-"},
{
@@ -800,14 +809,15 @@ def test_try_open_image():
),
(
'
',
- '
',
+ '
',
[ # Special case: empty string as class prefix.
{"IMAGE_PROCESS_CLASS_PREFIX": ""},
],
),
(
'
',
- '
',
+ '
',
[ # No class added.
{"IMAGE_PROCESS_ADD_CLASS": False},
{"IMAGE_PROCESS_ADD_CLASS": False, "IMAGE_PROCESS_CLASS_PREFIX": ""},
@@ -818,7 +828,8 @@ def test_try_open_image():
def test_class_settings(mocker, orig_tag, new_tag, setting_overrides):
"""Test the IMAGE_PROCESS_ADD_CLASS and IMAGE_PROCESS_CLASS_PREFIX settings."""
# Silence image transforms.
- mocker.patch("pelican.plugins.image_process.image_process.process_image")
+ process = mocker.patch("pelican.plugins.image_process.image_process.process_image")
+ process.return_value = (512, 384)
for override in setting_overrides:
settings = get_settings(**override)