| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- # -*- coding: utf-8 -*-
- """裁掉配图四周的纯白边,避免插入 Word 后出现大片留白。
- 原图统一备份到 _bid_assets/_raw/,重复执行时从备份重新裁剪,不会越裁越小。
- """
- import os
- import shutil
- from PIL import Image, ImageChops
- HERE = os.path.dirname(os.path.abspath(__file__))
- ASSETS = os.path.join(HERE, "_bid_assets")
- RAW = os.path.join(ASSETS, "_raw")
- os.makedirs(RAW, exist_ok=True)
- PAD = 12 # 裁剪后保留的白边像素
- # 个别抽取图自带「图 xxx」标题行,与 Word 图题重复,按比例切掉顶部
- TOP_CROP_RATIO = {"s0_master_dataflow.png": 0.055}
- def trim_box(im, tol=8):
- bg = Image.new("RGB", im.size, (255, 255, 255))
- diff = ImageChops.difference(im, bg).convert("L")
- box = diff.point(lambda v: 255 if v > tol else 0).getbbox()
- if not box:
- return im
- l, t, r, b = box
- return im.crop((max(0, l - PAD), max(0, t - PAD),
- min(im.width, r + PAD), min(im.height, b + PAD)))
- def trim(path, tol=8):
- """tol:接近纯白(每通道差值 ≤ tol)的像素一律视为背景。
- 抽取自蓝图文档的图并非纯白底,直接与 #FFFFFF 比对会判定整幅都是内容。
- """
- im = Image.open(path).convert("RGB")
- bg = Image.new("RGB", im.size, (255, 255, 255))
- diff = ImageChops.difference(im, bg).convert("L")
- box = diff.point(lambda v: 255 if v > tol else 0).getbbox()
- if not box:
- return None
- l, t, r, b = box
- l, t = max(0, l - PAD), max(0, t - PAD)
- r, b = min(im.width, r + PAD), min(im.height, b + PAD)
- if (l, t, r, b) == (0, 0, im.width, im.height):
- return None
- return im.crop((l, t, r, b))
- def main():
- # ui_* 是系统真实界面截图,边缘留白属于界面本身,不做裁剪
- names = sorted(n for n in os.listdir(ASSETS)
- if n.lower().endswith(".png") and not n.startswith("ui_"))
- print(f"共 {len(names)} 张配图")
- for n in names:
- src = os.path.join(ASSETS, n)
- raw = os.path.join(RAW, n)
- if not os.path.exists(raw):
- shutil.copy2(src, raw)
- before = Image.open(raw).size
- out = trim(raw)
- ratio = TOP_CROP_RATIO.get(n)
- if ratio:
- im = out if out is not None else Image.open(raw).convert("RGB")
- cut = int(im.height * ratio)
- out = trim_box(im.crop((0, cut, im.width, im.height)))
- if out is None:
- print(f" {n:<28} {before[0]}x{before[1]} 无需裁剪")
- continue
- out.save(src)
- print(f" {n:<28} {before[0]}x{before[1]} → {out.width}x{out.height}")
- if __name__ == "__main__":
- main()
|