diff options
Diffstat (limited to 'scripts/make-flow-pdfs.py')
| -rw-r--r-- | scripts/make-flow-pdfs.py | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/scripts/make-flow-pdfs.py b/scripts/make-flow-pdfs.py new file mode 100644 index 0000000..f6e263b --- /dev/null +++ b/scripts/make-flow-pdfs.py @@ -0,0 +1,110 @@ +"""いじめ重大事態対応フロー図の印刷用PDFを、SVGからベクターで生成する。 + +以前は 2.5 倍のラスタPNGを埋め込んだPDF(1ページ版 約2MB / 6ページ版 約4MB)を +使っていたが、同じレイアウトのままベクターで組み直し、大幅に軽量化する +(各ファイル約200KB。文字は拡大しても綺麗)。 + +- A4縦・タイル分割版(2列×3行=6ページ、のりしろ重複あり) +- A4縦・全体像1ページ版(縮小・見取り図) + +レイアウトは旧ラスタ版と同一(A4 3100x4382px 相当、余白100px、紙面2900x4182px、 +タイル 1160x1672.8、列 x=[0,660]、行 y=[0, base/2, base])。 +base は SVG の元の高さ(リンク行を追記する前の値)。SVG の末尾に追記した +解説ページへのリンク行は、PDFではフッターのリンク注釈として付ける。 + +使い方: python scripts/make-flow-pdfs.py +""" +import pathlib +import sys + +import pymupdf + +sys.stdout.reconfigure(encoding="utf-8") + +IMAGES = pathlib.Path(__file__).resolve().parent.parent / "public" / "ijime-judai-jitai" / "images" +URL = "https://yasutakeyohei.com/ijime-judai-jitai/flow/" +TITLE = "いじめの重大事態の対応フロー(ロール別)" + +# 旧ラスタ版と同じジオメトリ(A4 3100x4382px 相当) +A4W = pymupdf.paper_rect("a4").width +A4H = pymupdf.paper_rect("a4").height +PX2PT = A4W / 3100.0 +MARGIN = 100 * PX2PT +DEST = pymupdf.Rect(MARGIN, MARGIN, MARGIN + 2900 * PX2PT, MARGIN + 4182 * PX2PT) +TILE_W1 = 1160.0 # タイル幅(SVG座標=1x基準) +TILE_H1 = 1672.8 # タイル高さ +FOOT_SIZE = 50 * PX2PT # 旧: int(20*2.5)=50px +FOOT_TOP = (4382 - 100 + 15) * PX2PT +FOOT_COLOR = (0x45 / 255, 0x5A / 255, 0x64 / 255) +FOOT_6P = TITLE + " {n}/6 (全体の一部・のりしろ重複あり)" +FOOT_1P = TITLE + " 全体像(縮小のため文字は小さめ。読みやすい印刷は6ページ版を推奨)" + +# (SVGファイル名, 出力の6ページ版, 出力の1ページ版, SVGの元の高さ) +JOBS = [ + ("ijime-judai-flow.svg", "ijime-judai-flow-a4-6p.pdf", "ijime-judai-flow-a4-1p.pdf", 3890), + ("ijime-judai-flow-private.svg", "ijime-judai-flow-private-a4-6p.pdf", + "ijime-judai-flow-private-a4-1p.pdf", 3624), +] + + +def one_page_rect(base_h): + """1ページ版の配置(旧スクリプトの縮小計算を再現)。""" + sc = min((2900 / 2.5) / 1820, ((4182 / 2.5) - 30) / base_h) + w = 1820 * sc * 2.5 * PX2PT + h = base_h * sc * 2.5 * PX2PT + x = (3100 - 1820 * sc * 2.5) * PX2PT / 2 + return pymupdf.Rect(x, MARGIN, x + w, MARGIN + h) + + +def add_footer(page, text): + page.insert_text( + pymupdf.Point(MARGIN, FOOT_TOP + FOOT_SIZE * 0.8), + text, fontsize=FOOT_SIZE, fontname="japan", color=FOOT_COLOR, + ) + page.insert_link({ + "kind": pymupdf.LINK_URI, + "from": pymupdf.Rect(0, FOOT_TOP - 5, A4W, A4H), + "uri": URL, + }) + + +def build(svg_name, out_6p, out_1p, base_h): + svg = pymupdf.open(IMAGES / svg_name) + # show_pdf_page は PDF しか受け付けないため、いったんベクターPDFに変換する + src = pymupdf.open("pdf", svg.tobytes(garbage=4, deflate=True)) + svg.close() + + xs = [0.0, 660.0] + span = base_h - TILE_H1 + ys = [0.0, float(round(span / 2)), float(span)] + + tiles = [] + n = 0 + for y in ys: + for x in xs: + n += 1 + tiles.append((pymupdf.Rect(x, y, x + TILE_W1, y + TILE_H1), FOOT_6P.format(n=n))) + tiles.append((pymupdf.Rect(0, 0, 1820, base_h), FOOT_1P)) + + def make(pages, path): + out = pymupdf.open() + for i, (clip, footer) in enumerate(pages): + page = out.new_page(width=A4W, height=A4H) + dest = DEST if i < 6 else one_page_rect(base_h) + page.show_pdf_page(dest, src, 0, clip=clip) + add_footer(page, footer) + out.subset_fonts() + tmp = path.with_suffix(".tmp.pdf") + out.save(tmp, garbage=4, deflate=True, clean=True) + out.close() + tmp.replace(path) + print(f"{path.name}: {path.stat().st_size:,} bytes") + + make(tiles[:6], IMAGES / out_6p) + make(tiles[6:], IMAGES / out_1p) + + src.close() + + +for svg_name, out_6p, out_1p, base_h in JOBS: + build(svg_name, out_6p, out_1p, base_h) |
