Skip to content

Commit 046d091

Browse files
gounuxGuts
andauthored
Fix unnecessary pillow import by using image size from CDN endpoint (#218)
Co-authored-by: gounux <[email protected]> Co-authored-by: Julien <[email protected]>
1 parent 30ce4e4 commit 046d091

File tree

2 files changed

+131
-39
lines changed

2 files changed

+131
-39
lines changed

geotribu_cli/content/header_check.py

+121-37
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@
44
from pathlib import Path
55

66
import frontmatter
7+
import orjson
78

89
from geotribu_cli.constants import (
910
GeotribuDefaults,
1011
YamlHeaderAvailableLicense,
1112
YamlHeaderMandatoryKeys,
1213
)
1314
from geotribu_cli.json.json_client import JsonFeedClient
14-
from geotribu_cli.utils.check_image_size import get_image_dimensions_by_url
1515
from geotribu_cli.utils.check_path import check_path
16+
from geotribu_cli.utils.file_downloader import download_remote_file_to_local
1617
from geotribu_cli.utils.slugger import sluggy
1718

1819
logger = logging.getLogger(__name__)
@@ -49,14 +50,6 @@ def parser_header_check(
4950
type=Path,
5051
help="Chemin qui contient les presentations markdown des auteurs/autrices",
5152
)
52-
subparser.add_argument(
53-
"-minw",
54-
"--min-width",
55-
dest="min_image_width",
56-
default=400,
57-
type=int,
58-
help="Largeur minimum de l'image à vérifier",
59-
)
6053
subparser.add_argument(
6154
"-maxw",
6255
"--max-width",
@@ -65,14 +58,6 @@ def parser_header_check(
6558
type=int,
6659
help="Largeur maximum de l'image à vérifier",
6760
)
68-
subparser.add_argument(
69-
"-minh",
70-
"--min-height",
71-
dest="min_image_height",
72-
default=400,
73-
type=int,
74-
help="Hauteur minimum de l'image à vérifier",
75-
)
7661
subparser.add_argument(
7762
"-maxh",
7863
"--max-height",
@@ -81,6 +66,22 @@ def parser_header_check(
8166
type=int,
8267
help="Hauteur maximum de l'image à vérifier",
8368
)
69+
subparser.add_argument(
70+
"-minr",
71+
"--min-ratio",
72+
dest="min_image_ratio",
73+
default=1.45,
74+
type=float,
75+
help="Ratio largeur / hauteur minimum de l'image à vérifier",
76+
)
77+
subparser.add_argument(
78+
"-maxr",
79+
"--max-ratio",
80+
dest="max_image_ratio",
81+
default=1.55,
82+
type=float,
83+
help="Ratio largeur / hauteur maximum de l'image à vérifier",
84+
)
8485
subparser.add_argument(
8586
"-r",
8687
"--raise",
@@ -105,11 +106,64 @@ def check_author_md(author: str, folder: Path) -> bool:
105106
return os.path.exists(p)
106107

107108

109+
def download_image_sizes() -> dict:
110+
"""Downloads image dimensions file from CDN
111+
112+
Returns:
113+
Dict of image dimensions
114+
"""
115+
# download images sizes and indexes
116+
local_dims = download_remote_file_to_local(
117+
remote_url_to_download=f"{defaults_settings.cdn_base_url}img/search-index.json",
118+
local_file_path=defaults_settings.geotribu_working_folder.joinpath(
119+
"img/search-index.json"
120+
),
121+
expiration_rotating_hours=24,
122+
)
123+
with local_dims.open("rb") as fd:
124+
img_dims = orjson.loads(fd.read())
125+
return img_dims["images"]
126+
127+
108128
def check_image_size(
109-
image_url: str, minw: int, maxw: int, minh: int, maxh: int
129+
image_url: str, images: dict, max_width: int, max_height: int
110130
) -> bool:
111-
width, height = get_image_dimensions_by_url(image_url)
112-
return minw <= width <= maxw and minh <= height <= maxh
131+
"""Checks if an image respects provided max dimensions using CDN index file
132+
133+
Args:
134+
image_url: HTTP url of the image to check
135+
images: Dictionary of image dimensions (see download_image_sizes())
136+
max_width: maximum width of the image
137+
max_height: maximum height of the image
138+
139+
Returns:
140+
True if image max dimensions are respected
141+
False if not
142+
"""
143+
key = image_url.replace(f"{defaults_settings.cdn_base_url}img/", "")
144+
if key not in images:
145+
return False
146+
width, height = images[key]
147+
return width <= max_width and height <= max_height
148+
149+
150+
def check_image_ratio(
151+
image_url: str, images: dict, min_ratio: int, max_ratio: int
152+
) -> bool:
153+
key = image_url.replace(f"{defaults_settings.cdn_base_url}img/", "")
154+
if key not in images:
155+
return False
156+
width, height = images[key]
157+
ratio = width / height
158+
return min_ratio <= ratio <= max_ratio
159+
160+
161+
def check_image_extension(
162+
image_url: str,
163+
allowed_extensions: tuple[str] = defaults_settings.images_header_extensions,
164+
) -> bool:
165+
ext = image_url.split(".")[-1]
166+
return ext in allowed_extensions
113167

114168

115169
def get_existing_tags() -> list[str]:
@@ -190,24 +244,54 @@ def run(args: argparse.Namespace) -> None:
190244
# check that image size is okay
191245
if "image" in yaml_meta:
192246
if not yaml_meta["image"]:
193-
logger.error("Pas d'URL pour l'image")
194-
elif not check_image_size(
195-
yaml_meta["image"],
196-
args.min_image_width,
197-
args.max_image_width,
198-
args.min_image_height,
199-
args.max_image_height,
200-
):
201-
msg = (
202-
f"Les dimensions de l'image ne sont pas dans l'intervalle autorisé "
203-
f"(w:{args.min_image_width}-{args.max_image_width},"
204-
f"h:{args.min_image_height}-{args.max_image_height})"
205-
)
206-
logger.error(msg)
207-
if args.raise_exceptions:
208-
raise ValueError(msg)
247+
logger.warning("Pas d'URL pour l'image")
209248
else:
210-
logger.info("Dimensions de l'image ok")
249+
# check image max size
250+
if not check_image_size(
251+
yaml_meta["image"],
252+
download_image_sizes(),
253+
args.max_image_width,
254+
args.max_image_height,
255+
):
256+
msg = (
257+
f"Les dimensions de l'image ne sont pas dans l'intervalle autorisé "
258+
f"(w:{args.min_image_width}-{args.max_image_width},"
259+
f"h:{args.min_image_height}-{args.max_image_height})"
260+
)
261+
logger.error(msg)
262+
if args.raise_exceptions:
263+
raise ValueError(msg)
264+
else:
265+
logger.info("Dimensions de l'image ok")
266+
267+
# check image max ratio
268+
if not check_image_ratio(
269+
yaml_meta["image"],
270+
download_image_sizes(),
271+
args.min_image_ratio,
272+
args.max_image_ratio,
273+
):
274+
msg = (
275+
f"Le ratio largeur / hauteur de l'image n'est pas dans l'intervalle autorisé "
276+
f"(min:{args.min_image_ratio},"
277+
f"max:{args.max_image_ratio})"
278+
)
279+
logger.error(msg)
280+
if args.raise_exceptions:
281+
raise ValueError(msg)
282+
else:
283+
logger.info("Ratio de l'image ok")
284+
285+
# check image extension
286+
if not check_image_extension(
287+
yaml_meta["image"],
288+
):
289+
msg = f"L'extension de l'image n'est pas autorisée, doit être parmi : {','.join(defaults_settings.images_header_extensions)}"
290+
logger.error(msg)
291+
if args.raise_exceptions:
292+
raise ValueError(msg)
293+
else:
294+
logger.info("Extension de l'image ok")
211295

212296
# check that author md file is present
213297
if args.authors_folder:

tests/test_utils_images_size.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,16 @@ def test_check_image_dimensions(self):
126126

127127
def test_image_url_dimensions(self):
128128
for url, width, height in [
129-
("https://cdn.geotribu.fr/img/coup_de_gueule.jpg", 74, 64),
130-
("https://cdn.geotribu.fr/img/pytroll.png", 100, 100),
129+
(
130+
"https://cdn.geotribu.fr/img/articles-blog-rdp/articles/2024/lidarhd_pdal/lidar_zoom.png",
131+
1380,
132+
763,
133+
),
134+
(
135+
"https://cdn.geotribu.fr/img/articles-blog-rdp/articles/2024/lidarhd_pdal/sol.png",
136+
1000,
137+
557,
138+
),
131139
]:
132140
w, h = get_image_dimensions_by_url(url)
133141
self.assertEqual(w, width)

0 commit comments

Comments
 (0)