diff --git a/content/photos/1766156992123.jpg b/content/photos/1766156992123.jpg index 6d17311..b612575 100644 Binary files a/content/photos/1766156992123.jpg and b/content/photos/1766156992123.jpg differ diff --git a/content/photos/1766156992265.jpg b/content/photos/1766156992265.jpg index e3a7373..f46722b 100644 Binary files a/content/photos/1766156992265.jpg and b/content/photos/1766156992265.jpg differ diff --git a/content/photos/1766156992559.jpg b/content/photos/1766156992559.jpg index f0a0b59..8c0111f 100644 Binary files a/content/photos/1766156992559.jpg and b/content/photos/1766156992559.jpg differ diff --git a/content/photos/1766156992840.jpg b/content/photos/1766156992840.jpg index f542841..7cd9407 100644 Binary files a/content/photos/1766156992840.jpg and b/content/photos/1766156992840.jpg differ diff --git a/content/photos/1766156997939.jpg b/content/photos/1766156997939.jpg index b6dfd7c..eb8e44f 100644 Binary files a/content/photos/1766156997939.jpg and b/content/photos/1766156997939.jpg differ diff --git a/content/photos/1766156998072.jpg b/content/photos/1766156998072.jpg index 5deac5b..6337518 100644 Binary files a/content/photos/1766156998072.jpg and b/content/photos/1766156998072.jpg differ diff --git a/content/photos/1766156998205.jpg b/content/photos/1766156998205.jpg index 3a88377..2c03cb6 100644 Binary files a/content/photos/1766156998205.jpg and b/content/photos/1766156998205.jpg differ diff --git a/content/photos/1766156998344.jpg b/content/photos/1766156998344.jpg index db73cb0..7e17265 100644 Binary files a/content/photos/1766156998344.jpg and b/content/photos/1766156998344.jpg differ diff --git a/content/photos/1766156998590.jpg b/content/photos/1766156998590.jpg index 74b59ee..6af9e6f 100644 Binary files a/content/photos/1766156998590.jpg and b/content/photos/1766156998590.jpg differ diff --git a/content/photos/1766157003595.jpg b/content/photos/1766157003595.jpg index 4ec7ec5..071bd81 100644 Binary files a/content/photos/1766157003595.jpg and b/content/photos/1766157003595.jpg differ diff --git a/content/photos/1766157003732.jpg b/content/photos/1766157003732.jpg index c198726..fe9b70c 100644 Binary files a/content/photos/1766157003732.jpg and b/content/photos/1766157003732.jpg differ diff --git a/content/photos/1766157003865.jpg b/content/photos/1766157003865.jpg index 72b0807..58c4e09 100644 Binary files a/content/photos/1766157003865.jpg and b/content/photos/1766157003865.jpg differ diff --git a/content/photos/1766157003992.jpg b/content/photos/1766157003992.jpg index 763a549..b88dafa 100644 Binary files a/content/photos/1766157003992.jpg and b/content/photos/1766157003992.jpg differ diff --git a/content/photos/1766157004116.jpg b/content/photos/1766157004116.jpg index b5aa470..ce00388 100644 Binary files a/content/photos/1766157004116.jpg and b/content/photos/1766157004116.jpg differ diff --git a/content/photos/1766157012003.jpg b/content/photos/1766157012003.jpg index 47db144..193984d 100644 Binary files a/content/photos/1766157012003.jpg and b/content/photos/1766157012003.jpg differ diff --git a/content/photos/mmexport1771816358254.jpg b/content/photos/mmexport1771816358254.jpg index e0ecab9..9c748da 100644 Binary files a/content/photos/mmexport1771816358254.jpg and b/content/photos/mmexport1771816358254.jpg differ diff --git a/content/photos/mmexport1771816377628.jpg b/content/photos/mmexport1771816377628.jpg index afce204..fe28580 100644 Binary files a/content/photos/mmexport1771816377628.jpg and b/content/photos/mmexport1771816377628.jpg differ diff --git a/content/photos/mmexport1771816382115.jpg b/content/photos/mmexport1771816382115.jpg index fe786a9..8d5668e 100644 Binary files a/content/photos/mmexport1771816382115.jpg and b/content/photos/mmexport1771816382115.jpg differ diff --git a/content/photos/mmexport1776564092433.jpg b/content/photos/mmexport1776564092433.jpg index 7aca726..393ac12 100644 Binary files a/content/photos/mmexport1776564092433.jpg and b/content/photos/mmexport1776564092433.jpg differ diff --git a/scripts/migrate/photos_migrate.py b/scripts/migrate/photos_migrate.py index 4bc473f..be3fad8 100644 --- a/scripts/migrate/photos_migrate.py +++ b/scripts/migrate/photos_migrate.py @@ -32,11 +32,15 @@ def compress(data: bytes) -> bytes: from PIL import Image img = Image.open(BytesIO(data)) + # EXIF 必须显式带上:PIL 重存默认剥离,而构建期 exifr 正是从文件提 EXIF + exif = img.info.get("exif") if img.mode not in ("RGB", "L"): img = img.convert("RGB") img.thumbnail((2400, 2400)) buf = BytesIO() - img.save(buf, "JPEG", quality=86, optimize=True) + # PIL 的 JPEG 保存不接受 exif=None(len(None) 崩),仅在确有 EXIF 时传参 + kwargs = {"exif": exif} if exif else {} + img.save(buf, "JPEG", quality=86, optimize=True, **kwargs) return buf.getvalue() diff --git a/scripts/photos_ingest.py b/scripts/photos_ingest.py new file mode 100644 index 0000000..dd86e3f --- /dev/null +++ b/scripts/photos_ingest.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +"""照片入库处理器:把 content/photos/ 下超限图片压缩到站内规范。 + +为什么存在:gitea web/本地上传的是原图(曾发生 196M/21 张入仓事故, +见 git log aea21c8 的重写说明);sharp 只派生 dist 缩略图不管仓内体积。 +工作流:上传照片到 content/photos/(顺带跑一次 sidecar 生成或手写)后、 +git commit 前执行本脚本;幂等,已在规范内的文件原样跳过(零 diff)。 + +规范与迁移器一致:长边 ≤2400px、JPEG q86(scripts/migrate/photos_migrate.py)。 +""" +import sys +from pathlib import Path + +PHOTOS = Path("content/photos") +MAX_EDGE = 2400 +QUALITY = 86 +# 跳过阈值:小于此字节数的 jpg 视为已处理过(2400px q86 成片通常 200KB-1MB) +SKIP_BELOW_BYTES = 1_500_000 + + +def main() -> int: + from PIL import Image + + changed, skipped = [], 0 + for jpg in sorted(PHOTOS.glob("*.jpg")): + size = jpg.stat().st_size + if size < SKIP_BELOW_BYTES: + skipped += 1 + continue + img = Image.open(jpg) + # EXIF 显式保留:重存默认剥离会抽走图库参数条的构建期数据源 + exif = img.info.get("exif") + if img.mode not in ("RGB", "L"): + img = img.convert("RGB") + img.thumbnail((MAX_EDGE, MAX_EDGE)) + kwargs = {"exif": exif} if exif else {} + img.save(jpg, "JPEG", quality=QUALITY, optimize=True, **kwargs) + changed.append((jpg.name, size, jpg.stat().st_size)) + + for name, before, after in changed: + print(f" compressed: {name} {before/1e6:.1f}M -> {after/1e6:.2f}M") + print(f"photos ingest: {len(changed)} compressed, {skipped} skipped (within spec)") + return 0 + + +if __name__ == "__main__": + sys.exit(main())