Skip to content

Commit 3a90b9e

Browse files
Merge pull request #72 from patrickfournier/pillow-lazy-check
Wait before we actually need to process the image for checking if Pillow can handle it.
2 parents 3822696 + 3518aca commit 3a90b9e

File tree

2 files changed

+36
-45
lines changed

2 files changed

+36
-45
lines changed

pelican/plugins/image_process/image_process.py

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -405,13 +405,6 @@ def compute_paths(img, settings, derivative):
405405

406406
def process_img_tag(img, settings, derivative):
407407
path = compute_paths(img, settings, derivative)
408-
if not is_img_identifiable(path.source):
409-
logger.warning(
410-
"%s Skipping image %s that could not be identified by Pillow",
411-
LOG_PREFIX,
412-
path.source,
413-
)
414-
return
415408
process = settings["IMAGE_PROCESS"][derivative]
416409

417410
img["src"] = posixpath.join(path.base_url, path.filename)
@@ -423,23 +416,8 @@ def process_img_tag(img, settings, derivative):
423416
process_image((path.source, destination, process), settings)
424417

425418

426-
def is_img_identifiable(img_filepath):
427-
try:
428-
Image.open(img_filepath)
429-
return True # noqa: TRY300
430-
except (FileNotFoundError, UnidentifiedImageError):
431-
return False
432-
433-
434419
def build_srcset(img, settings, derivative):
435420
path = compute_paths(img, settings, derivative)
436-
if not is_img_identifiable(path.source):
437-
logger.warning(
438-
"%s Skipping image %s that could not be identified by Pillow",
439-
LOG_PREFIX,
440-
path.source,
441-
)
442-
return
443421
process = settings["IMAGE_PROCESS"][derivative]
444422

445423
default = process["default"]
@@ -685,17 +663,28 @@ def process_picture(soup, img, group, settings, derivative):
685663
img.insert_before(s["element"])
686664

687665

666+
def try_open_image(path):
667+
try:
668+
i = Image.open(path)
669+
except UnidentifiedImageError:
670+
logger.warning(
671+
f'{LOG_PREFIX} Source image "{path}" is not supported by Pillow.'
672+
)
673+
raise
674+
except FileNotFoundError:
675+
logger.warning(f'{LOG_PREFIX} Source image "{path}" not found.')
676+
raise
677+
678+
return i
679+
680+
688681
def process_image(image, settings):
689682
# remove URL encoding to get to physical filenames
690683
image = list(image)
691684
image[0] = unquote(image[0])
692685
image[1] = unquote(image[1])
693686
# image[2] is the transformation
694687

695-
logger.debug(f"{LOG_PREFIX} {image[0]} -> {image[1]}")
696-
697-
os.makedirs(os.path.dirname(image[1]), exist_ok=True)
698-
699688
# If original image is older than existing derivative, skip
700689
# processing to save time, unless user explicitly forced
701690
# image generation.
@@ -704,7 +693,12 @@ def process_image(image, settings):
704693
or not os.path.exists(image[1])
705694
or os.path.getmtime(image[0]) > os.path.getmtime(image[1])
706695
):
707-
i = Image.open(image[0])
696+
logger.debug(f"{LOG_PREFIX} Processing {image[0]} -> {image[1]}")
697+
698+
try:
699+
i = try_open_image(image[0])
700+
except (UnidentifiedImageError, FileNotFoundError):
701+
return
708702

709703
for step in image[2]:
710704
if callable(step):
@@ -713,12 +707,16 @@ def process_image(image, settings):
713707
elems = step.split(" ")
714708
i = basic_ops[elems[0]](i, *(elems[1:]))
715709

710+
os.makedirs(os.path.dirname(image[1]), exist_ok=True)
711+
716712
# `save_all=True` will allow saving multi-page (aka animated) GIF's
717713
# however, turning it on seems to break PNG support, and doesn't seem
718714
# to work on GIF's either...
719715
i.save(image[1], progressive=True)
720716

721717
ExifTool.copy_tags(image[0], image[1])
718+
else:
719+
logger.debug(f"{LOG_PREFIX} Skipping {image[0]} -> {image[1]}")
722720

723721

724722
def dump_config(pelican):

pelican/plugins/image_process/test_image_process.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55
import subprocess
66
import warnings
77

8-
from PIL import Image
8+
from PIL import Image, UnidentifiedImageError
99
import pytest
1010

1111
from pelican.plugins.image_process import (
1212
ExifTool,
1313
compute_paths,
1414
harvest_images_in_fragment,
15-
is_img_identifiable,
1615
process_image,
1716
set_default_settings,
17+
try_open_image,
1818
)
1919

2020
# Prepare test image constants.
@@ -185,11 +185,6 @@ def test_image_formats(tmp_path, image_path):
185185
],
186186
)
187187
def test_path_normalization(mocker, orig_src, orig_img, new_src, new_img):
188-
# Allow non-existing images to be processed:
189-
mocker.patch(
190-
"pelican.plugins.image_process.image_process.is_img_identifiable",
191-
lambda img_filepath: True,
192-
)
193188
# Silence image transforms.
194189
process = mocker.patch("pelican.plugins.image_process.image_process.process_image")
195190

@@ -505,11 +500,6 @@ def test_path_normalization(mocker, orig_src, orig_img, new_src, new_img):
505500
],
506501
)
507502
def test_picture_generation(mocker, orig_tag, new_tag, call_args):
508-
# Allow non-existing images to be processed:
509-
mocker.patch(
510-
"pelican.plugins.image_process.image_process.is_img_identifiable",
511-
lambda img_filepath: True,
512-
)
513503
process = mocker.patch("pelican.plugins.image_process.image_process.process_image")
514504

515505
settings = get_settings(
@@ -626,19 +616,22 @@ def test_copy_exif_tags(tmp_path, image_path, copy_tags):
626616
assert tag not in actual_tags
627617

628618

629-
def test_is_img_identifiable():
619+
def test_try_open_image():
630620
for test_image in FILE_FORMAT_TEST_IMAGES:
631-
assert is_img_identifiable(test_image)
621+
assert try_open_image(test_image)
632622

633-
assert not is_img_identifiable("image/that/does/not/exist.png")
623+
with pytest.raises(FileNotFoundError):
624+
try_open_image("image/that/does/not/exist.png")
634625

635-
assert not is_img_identifiable(TEST_DATA.joinpath("folded_puzzle.png"))
636-
assert not is_img_identifiable(TEST_DATA.joinpath("minimal.svg"))
626+
with pytest.raises(UnidentifiedImageError):
627+
assert not try_open_image(TEST_DATA.joinpath("folded_puzzle.png"))
628+
assert not try_open_image(TEST_DATA.joinpath("minimal.svg"))
637629

638630
img = {"src": "https://upload.wikimedia.org/wikipedia/commons/3/34/Exemple.png"}
639631
settings = get_settings(IMAGE_PROCESS_DIR="derivatives")
640632
path = compute_paths(img, settings, derivative="thumb")
641-
assert not is_img_identifiable(path.source)
633+
with pytest.raises(FileNotFoundError):
634+
assert not try_open_image(path.source)
642635

643636

644637
def generate_test_images():

0 commit comments

Comments
 (0)