|
6 | 6 | import logging
|
7 | 7 | import os
|
8 | 8 | import posixpath
|
| 9 | +import struct |
9 | 10 | from pathlib import Path
|
10 | 11 | from typing import TYPE_CHECKING
|
11 | 12 | from urllib.parse import urljoin, urlparse, urlsplit, urlunsplit
|
@@ -64,6 +65,20 @@ def get_file_contents_hash(file_path: Path) -> str:
|
64 | 65 | return hasher.hexdigest()[:8]
|
65 | 66 |
|
66 | 67 |
|
| 68 | +class PNGFormatError(Exception): |
| 69 | + pass |
| 70 | + |
| 71 | + |
| 72 | +def get_png_dimensions(png_bytes: bytes) -> tuple[int, int]: |
| 73 | + try: |
| 74 | + w, h = struct.unpack('>LL', png_bytes[16:24]) |
| 75 | + width = int(w) |
| 76 | + height = int(h) |
| 77 | + except struct.error as exc: |
| 78 | + raise PNGFormatError('Invalid PNG file') from exc |
| 79 | + return width, height |
| 80 | + |
| 81 | + |
67 | 82 | @dataclasses.dataclass
|
68 | 83 | class SocialCardContents:
|
69 | 84 | """Parameters for generating a social card.
|
@@ -213,20 +228,22 @@ def get_tags(
|
213 | 228 | if image_path:
|
214 | 229 | image_url = posixpath.join(ogp_site_url, image_path.as_posix())
|
215 | 230 |
|
216 |
| - ogp_use_first_image = False |
217 |
| - |
218 |
| - # Alt text is taken from description unless given |
219 |
| - if 'og:image:alt' in fields: |
220 |
| - ogp_image_alt = fields.get('og:image:alt') |
221 |
| - else: |
222 |
| - ogp_image_alt = description |
223 |
| - |
224 |
| - # If the social card objects have been added we add special metadata for them |
225 |
| - # These are the dimensions *in pixels* of the card |
226 |
| - # They were chosen by looking at the image pixel dimensions on disk |
227 |
| - tags['og:image:width'] = '1146' |
228 |
| - tags['og:image:height'] = '600' |
229 |
| - meta_tags['twitter:card'] = 'summary_large_image' |
| 231 | + ogp_use_first_image = False |
| 232 | + |
| 233 | + # Alt text is taken from description unless given |
| 234 | + if 'og:image:alt' in fields: |
| 235 | + ogp_image_alt = fields.get('og:image:alt') |
| 236 | + else: |
| 237 | + ogp_image_alt = description |
| 238 | + |
| 239 | + try: |
| 240 | + width, height = get_png_dimensions((outdir / image_path).read_bytes()) |
| 241 | + except PNGFormatError as exc: |
| 242 | + LOGGER.warning('Could not get dimensions of social card: %s', exc) |
| 243 | + else: |
| 244 | + tags['og:image:width'] = f'{width}' |
| 245 | + tags['og:image:height'] = f'{height}' |
| 246 | + meta_tags['twitter:card'] = 'summary_large_image' |
230 | 247 |
|
231 | 248 | fields.pop('og:image:alt', None)
|
232 | 249 |
|
|
0 commit comments