Files
sigal/tests/test_image.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

323 lines
10 KiB
Python
Raw Permalink Normal View History

2012-11-27 23:31:12 +01:00
import os
from unittest.mock import patch
2020-03-15 22:58:03 -03:00
import pytest
2021-02-07 17:58:08 -03:00
from PIL import Image as PILImage
2012-11-27 23:31:12 +01:00
2021-07-06 22:44:19 +02:00
from sigal.gallery import Image
2020-03-15 22:58:03 -03:00
from sigal.image import (
generate_image,
generate_thumbnail,
get_exif_data,
get_exif_tags,
2022-01-28 15:49:25 -06:00
get_image_metadata,
2022-04-08 20:05:51 +02:00
get_iptc_data,
2020-03-15 22:58:03 -03:00
get_size,
process_image,
)
2023-07-15 12:58:10 +02:00
from sigal.log import init_logging
2020-03-15 22:58:03 -03:00
from sigal.settings import Status, create_settings
2012-11-27 23:31:12 +01:00
CURRENT_DIR = os.path.dirname(__file__)
2023-02-12 17:31:08 +01:00
SRCDIR = os.path.join(CURRENT_DIR, "sample", "pictures")
TEST_IMAGE = "KeckObservatory20071020.jpg"
SRCFILE = os.path.join(SRCDIR, "dir2", TEST_IMAGE)
2012-11-27 23:47:16 +01:00
2023-02-12 17:31:08 +01:00
TEST_GIF_IMAGE = "example.gif"
SRC_GIF_FILE = os.path.join(SRCDIR, "dir1", "test1", TEST_GIF_IMAGE)
2012-11-27 23:47:16 +01:00
def test_process_image(tmpdir):
"Test the process_image function."
2023-02-12 17:31:08 +01:00
status = process_image(Image("foo.txt", "bar", create_settings()))
assert status == Status.FAILURE
2021-02-07 17:58:08 -03:00
settings = create_settings(
2023-02-12 17:31:08 +01:00
img_processor="ResizeToFill",
2021-02-07 17:58:08 -03:00
make_thumbs=False,
2023-02-12 17:31:08 +01:00
source=os.path.join(SRCDIR, "dir2"),
2021-02-07 17:58:08 -03:00
destination=str(tmpdir),
)
2023-02-12 17:31:08 +01:00
image = Image(TEST_IMAGE, ".", settings)
2021-02-07 17:58:08 -03:00
status = process_image(image)
assert status == Status.SUCCESS
2023-07-15 15:30:28 +02:00
with PILImage.open(os.path.join(str(tmpdir), TEST_IMAGE)) as im:
assert im.size == settings["img_size"]
2013-05-15 00:15:28 +02:00
def test_generate_image(tmpdir):
"Test the generate_image function."
2012-11-27 23:47:16 +01:00
dstfile = str(tmpdir.join(TEST_IMAGE))
for i, size in enumerate([(600, 600), (300, 200)]):
settings = create_settings(
2023-02-12 17:31:08 +01:00
img_size=size, img_processor="ResizeToFill", copy_exif_data=True
)
2023-02-12 17:31:08 +01:00
options = None if i == 0 else {"quality": 85}
generate_image(SRCFILE, dstfile, settings, options=options)
2023-07-15 15:30:28 +02:00
with PILImage.open(dstfile) as im:
assert im.size == size
2012-11-27 23:47:16 +01:00
def test_generate_image_imgformat(tmpdir):
"Test the effects of the img_format setting on generate_image."
dstfile = str(tmpdir.join(TEST_IMAGE))
for i, outfmt in enumerate(["JPEG", "PNG", "TIFF"]):
settings = create_settings(
img_size=(300, 300),
2023-02-12 17:31:08 +01:00
img_processor="ResizeToFill",
copy_exif_data=True,
img_format=outfmt,
)
2023-02-12 17:31:08 +01:00
options = {"quality": 85}
generate_image(SRCFILE, dstfile, settings, options=options)
2023-07-15 15:30:28 +02:00
with PILImage.open(dstfile) as im:
assert im.format == outfmt
2013-05-15 00:15:28 +02:00
2021-02-07 18:47:52 -03:00
def test_resize_image_portrait(tmpdir):
"""Test that the area is the same regardless of aspect ratio."""
size = (300, 200)
settings = create_settings(img_size=size)
2023-02-12 17:31:08 +01:00
portrait_image = "m57_the_ring_nebula-587px.jpg"
portrait_src = os.path.join(
2023-02-12 17:31:08 +01:00
CURRENT_DIR, "sample", "pictures", "dir2", portrait_image
)
portrait_dst = str(tmpdir.join(portrait_image))
generate_image(portrait_src, portrait_dst, settings)
2023-07-15 15:30:28 +02:00
with PILImage.open(portrait_dst) as im:
# In the default mode, PILKit resizes in a way to never make an image
# smaller than either of the lengths, the other is scaled accordingly.
# Hence we test that the shorter side has the smallest length.
assert im.size[0] == 200
2023-02-12 17:31:08 +01:00
landscape_image = "KeckObservatory20071020.jpg"
landscape_src = os.path.join(
2023-02-12 17:31:08 +01:00
CURRENT_DIR, "sample", "pictures", "dir2", landscape_image
)
landscape_dst = str(tmpdir.join(landscape_image))
generate_image(landscape_src, landscape_dst, settings)
2023-07-15 15:30:28 +02:00
with PILImage.open(landscape_dst) as im:
assert im.size[1] == 200
2016-01-08 12:23:23 +01:00
@pytest.mark.parametrize(
("image", "path"), [(TEST_IMAGE, SRCFILE), (TEST_GIF_IMAGE, SRC_GIF_FILE)]
)
def test_generate_image_passthrough(tmpdir, image, path):
"Test the generate_image function with use_orig=True."
2016-01-08 12:23:23 +01:00
dstfile = str(tmpdir.join(image))
settings = create_settings(use_orig=True)
2016-01-08 12:23:23 +01:00
generate_image(path, dstfile, settings)
# Check the file was copied, not (sym)linked
2016-01-08 12:23:23 +01:00
st_src = os.stat(path)
st_dst = os.stat(dstfile)
assert st_src.st_size == st_dst.st_size
assert not os.path.samestat(st_src, st_dst)
def test_generate_image_passthrough_symlink(tmpdir):
"Test the generate_image function with use_orig=True and orig_link=True."
dstfile = str(tmpdir.join(TEST_IMAGE))
settings = create_settings(use_orig=True, orig_link=True)
generate_image(SRCFILE, dstfile, settings)
# Check the file was symlinked
assert os.path.islink(dstfile)
assert os.path.samefile(SRCFILE, dstfile)
2013-05-15 00:15:28 +02:00
def test_generate_image_processor(tmpdir):
"Test generate_image with a wrong processor name."
2023-02-12 17:31:08 +01:00
init_logging("sigal")
2013-05-15 00:15:28 +02:00
dstfile = str(tmpdir.join(TEST_IMAGE))
2023-02-12 17:31:08 +01:00
settings = create_settings(img_size=(200, 200), img_processor="WrongMethod")
2013-09-23 00:32:32 +02:00
2013-05-15 00:15:28 +02:00
with pytest.raises(SystemExit):
generate_image(SRCFILE, dstfile, settings)
2013-05-15 00:15:28 +02:00
2016-01-08 12:23:23 +01:00
@pytest.mark.parametrize(
("image", "path", "wide_size", "high_size"),
[
(TEST_IMAGE, SRCFILE, (200, 133), (150, 100)),
2020-01-04 00:51:44 -03:00
(TEST_GIF_IMAGE, SRC_GIF_FILE, (134, 150), (150, 168)),
2021-07-07 00:12:08 +02:00
],
2020-01-04 00:51:44 -03:00
)
2016-01-08 12:23:23 +01:00
def test_generate_thumbnail(tmpdir, image, path, wide_size, high_size):
"Test the generate_thumbnail function."
2016-01-08 12:23:23 +01:00
dstfile = str(tmpdir.join(image))
for size in [(200, 150), (150, 200)]:
generate_thumbnail(path, dstfile, size)
2023-07-15 15:30:28 +02:00
with PILImage.open(dstfile) as im:
assert im.size == size
2016-01-08 12:23:23 +01:00
for size, thumb_size in [((200, 150), wide_size), ((150, 200), high_size)]:
generate_thumbnail(path, dstfile, size, fit=False)
2023-07-15 15:30:28 +02:00
with PILImage.open(dstfile) as im:
assert im.size == thumb_size
def test_get_exif_tags():
2023-02-12 17:31:08 +01:00
test_image = "11.jpg"
src_file = os.path.join(
2023-02-12 17:31:08 +01:00
CURRENT_DIR, "sample", "pictures", "dir1", "test1", test_image
)
data = get_exif_data(src_file)
2023-02-12 17:31:08 +01:00
simple = get_exif_tags(data, datetime_format="%d/%m/%Y")
assert simple["fstop"] == 3.9
assert simple["focal"] == 12.0
assert simple["iso"] == 50
assert simple["Make"] == "NIKON"
assert simple["datetime"] == "22/01/2006"
assert simple["exposure"] == "100603/100000000"
2023-02-12 17:31:08 +01:00
data = {"FNumber": [1, 0], "FocalLength": [1, 0], "ExposureTime": 10}
simple = get_exif_tags(data)
2023-02-12 17:31:08 +01:00
assert "fstop" not in simple
assert "focal" not in simple
assert simple["exposure"] == "10"
data = {
2023-02-12 17:31:08 +01:00
"ExposureTime": "--",
"DateTimeOriginal": "---",
"GPSInfo": {
"GPSLatitude": ((34, 0), (1, 0), (4500, 100)),
"GPSLatitudeRef": "N",
"GPSLongitude": ((116, 0), (8, 0), (3900, 100)),
"GPSLongitudeRef": "W",
2021-07-07 00:12:08 +02:00
},
}
simple = get_exif_tags(data)
2023-02-12 17:31:08 +01:00
assert "exposure" not in simple
assert "datetime" not in simple
assert "gps" not in simple
def test_get_iptc_data(caplog):
2023-02-12 17:31:08 +01:00
test_image = "1.jpg"
src_file = os.path.join(CURRENT_DIR, "sample", "pictures", "iptcTest", test_image)
data = get_iptc_data(src_file)
# Title
2018-02-15 17:14:37 +11:00
assert (
data["title"]
2023-02-12 17:31:08 +01:00
== "Haemostratulus clouds over Canberra - " + "2005-12-28 at 03-25-07"
2021-07-07 00:12:08 +02:00
)
# Description
2018-02-15 17:14:37 +11:00
assert (
data["description"]
== '"Haemo" because they look like haemoglobin '
+ 'cells and "stratulus" because I can\'t work out whether '
2023-02-12 17:31:08 +01:00
+ "they're Stratus or Cumulus clouds.\nWe're driving down "
+ "the main drag in Canberra so it's Parliament House that "
+ "you can see at the end of the road."
2021-07-07 00:12:08 +02:00
)
# This file has no IPTC data
2023-02-12 17:31:08 +01:00
test_image = "21.jpg"
src_file = os.path.join(CURRENT_DIR, "sample", "pictures", "exifTest", test_image)
2018-02-15 17:14:37 +11:00
assert get_iptc_data(src_file) == {}
2018-12-19 18:59:32 +01:00
# Headline
2023-02-12 17:31:08 +01:00
test_image = "3.jpg"
src_file = os.path.join(CURRENT_DIR, "sample", "pictures", "iptcTest", test_image)
2018-12-19 18:59:32 +01:00
data = get_iptc_data(src_file)
2023-02-12 17:31:08 +01:00
assert data["headline"] == "Ring Nebula, M57"
2018-12-19 18:59:32 +01:00
# Test catching the SyntaxError -- assert output
2023-02-12 17:31:08 +01:00
with patch("sigal.image.IptcImagePlugin.getiptcinfo", side_effect=SyntaxError):
get_iptc_data(src_file)
2023-02-12 17:31:08 +01:00
assert ["IPTC Error in"] == [log.message[:13] for log in caplog.records]
2022-01-28 16:51:03 -06:00
def test_get_image_metadata_exceptions():
# image does not exist
2023-02-12 17:31:08 +01:00
test_image = "bad_image.jpg"
src_file = os.path.join(CURRENT_DIR, "sample", test_image)
2022-01-28 15:49:25 -06:00
data = get_image_metadata(src_file)
2023-02-12 17:31:08 +01:00
assert data == {"exif": {}, "iptc": {}, "size": {}}
2022-01-28 15:49:25 -06:00
def test_iso_speed_ratings():
2023-02-12 17:31:08 +01:00
data = {"ISOSpeedRatings": ()}
simple = get_exif_tags(data)
2023-02-12 17:31:08 +01:00
assert "iso" not in simple
2023-02-12 17:31:08 +01:00
data = {"ISOSpeedRatings": None}
simple = get_exif_tags(data)
2023-02-12 17:31:08 +01:00
assert "iso" not in simple
2023-02-12 17:31:08 +01:00
data = {"ISOSpeedRatings": 125}
simple = get_exif_tags(data)
2023-02-12 17:31:08 +01:00
assert "iso" in simple
2013-07-31 08:33:26 +02:00
def test_exif_copy(tmpdir):
2017-10-23 08:18:08 +01:00
"Test if EXIF data can transferred copied to the resized image."
2013-07-31 08:33:26 +02:00
2023-02-12 17:31:08 +01:00
test_image = "11.jpg"
2013-07-31 08:33:26 +02:00
src_file = os.path.join(
2023-02-12 17:31:08 +01:00
CURRENT_DIR, "sample", "pictures", "dir1", "test1", test_image
2013-07-31 08:33:26 +02:00
)
dst_file = str(tmpdir.join(test_image))
settings = create_settings(img_size=(300, 400), copy_exif_data=True)
generate_image(src_file, dst_file, settings)
simple = get_exif_tags(get_exif_data(dst_file))
2023-02-12 17:31:08 +01:00
assert simple["iso"] == 50
2013-07-31 08:33:26 +02:00
2023-02-12 17:31:08 +01:00
settings["copy_exif_data"] = False
generate_image(src_file, dst_file, settings)
simple = get_exif_tags(get_exif_data(dst_file))
assert not simple
def test_exif_gps(tmpdir):
"""Test reading out correct geo tags"""
2013-09-23 00:32:32 +02:00
2023-02-12 17:31:08 +01:00
test_image = "flickr_jerquiaga_2394751088_cc-by-nc.jpg"
src_file = os.path.join(
2023-02-12 17:31:08 +01:00
CURRENT_DIR, "sample", "pictures", "dir1", "test1", test_image
)
dst_file = str(tmpdir.join(test_image))
settings = create_settings(img_size=(400, 300), copy_exif_data=True)
generate_image(src_file, dst_file, settings)
simple = get_exif_tags(get_exif_data(dst_file))
2023-02-12 17:31:08 +01:00
assert "gps" in simple
lat = 34.029167
lon = -116.144167
2023-02-12 17:31:08 +01:00
assert abs(simple["gps"]["lat"] - lat) < 0.0001
assert abs(simple["gps"]["lon"] - lon) < 0.0001
def test_get_size(tmpdir):
"""Test reading out image size"""
2023-02-12 17:31:08 +01:00
test_image = "flickr_jerquiaga_2394751088_cc-by-nc.jpg"
src_file = os.path.join(
2023-02-12 17:31:08 +01:00
CURRENT_DIR, "sample", "pictures", "dir1", "test1", test_image
)
result = get_size(src_file)
2023-02-12 17:31:08 +01:00
assert result == {"height": 800, "width": 600}
def test_get_size_with_invalid_path(tmpdir):
"""Test reading out image size with a missing file"""
2023-02-12 17:31:08 +01:00
test_image = "missing-file.jpg"
src_file = os.path.join(CURRENT_DIR, test_image)
result = get_size(src_file)
assert result is None