#!/usr/bin/env python3 """将「关于暂缓下月工资发放事宜的通知」正文叠到扫描件上,输出 工资通知-暂缓下月.png""" from __future__ import annotations import re import textwrap from pathlib import Path from PIL import Image, ImageDraw, ImageFont ROOT = Path(__file__).resolve().parent SRC_PNG = ROOT / "工资通知-原图.png" TXT = ROOT / "关于暂缓下月工资发放事宜的通知.txt" OUT = ROOT / "工资通知-暂缓下月.png" SONGTI = "/System/Library/Fonts/Supplemental/Songti.ttc" MARGIN_L = 72 MARGIN_R = 72 LINE_H = 34 TITLE_Y = 128 CHARS_PER_LINE = 24 def load_font(size: int, bold: bool = False) -> ImageFont.FreeTypeFont: idx = 1 if bold else 7 return ImageFont.truetype(SONGTI, size, encoding="utf-8", index=idx) def text_width(s: str, font: ImageFont.FreeTypeFont, draw: ImageDraw.ImageDraw) -> int: bbox = draw.textbbox((0, 0), s, font=font) return bbox[2] - bbox[0] def wrap_line_to_chars(s: str, width: int) -> list[str]: s = s.strip() if not s: return [] return textwrap.wrap(s, width=width, break_long_words=False, break_on_hyphens=False) def draw_body_paragraph( draw: ImageDraw.ImageDraw, y: int, text: str, font: ImageFont.FreeTypeFont, x0: int, line_h: int, first_indent: bool, ) -> int: max_chars = CHARS_PER_LINE - (2 if first_indent else 0) parts = wrap_line_to_chars(text, max_chars) for part in parts: line = ("  " + part) if first_indent else part draw.text((x0, y), line, font=font, fill=(30, 30, 30)) y += line_h return y def main() -> None: im = Image.open(SRC_PNG).convert("RGB") draw = ImageDraw.Draw(im) w, _h = im.size paper = (255, 255, 255) # 覆盖标题与正文,下缘略低于原「正文末行」留白,整块至公章上沿(公章约自 y≥708) draw.rectangle([32, 114, w - 34, 706], fill=paper) # y=706–716 狭长带:盖住正文与公章之间的浅灰水印,仅涂左侧留白,不压住公章顶边圆弧 draw.rectangle([36, 706, 446, 716], fill=paper) # 清空左下角旧署名/日期笔迹(不覆盖右下角公章 x≈453–596) draw.rectangle([120, 716, 446, 832], fill=paper) raw = TXT.read_text(encoding="utf-8") lines = [ln.rstrip() for ln in raw.splitlines()] title = lines[0].strip() i = 1 while i < len(lines) and not lines[i].strip(): i += 1 font_title = load_font(26, bold=True) font_body = load_font(22, bold=False) x0 = MARGIN_L max_px = w - MARGIN_L - MARGIN_R y = TITLE_Y tw = text_width(title, font_title, draw) draw.text(((w - tw) // 2, y), title, font=font_title, fill=(30, 30, 30)) y += 54 while i < len(lines): line = lines[i].strip() i += 1 if not line: y += LINE_H // 2 continue if line == "全体员工:": draw.text((x0, y), line, font=font_body, fill=(30, 30, 30)) y += LINE_H continue if line == "特此通知。": twl = text_width(line, font_body, draw) draw.text((x0 + max_px - twl, y), line, font=font_body, fill=(30, 30, 30)) y += LINE_H * 2 continue if line.startswith("浙江羚牛"): twl = text_width(line, font_body, draw) draw.text((x0 + max_px - twl, y), line, font=font_body, fill=(30, 30, 30)) y += LINE_H continue if re.match(r"^\d{4}年\d{1,2}月\d{1,2}日$", line): twl = text_width(line, font_body, draw) draw.text((x0 + max_px - twl, y), line, font=font_body, fill=(30, 30, 30)) y += LINE_H continue first_indent = not bool(re.match(r"^[一二三四五六七八九十]+、", line)) y = draw_body_paragraph(draw, y, line, font_body, x0, LINE_H, first_indent) im.save(OUT, format="PNG", optimize=True) print(f"写入 {OUT}") if __name__ == "__main__": main()