#!/usr/bin/env python3 # ============================================================================= # build_standalone.py — INSTALL_GUIDE.html 의 모든 로컬 이미지를 base64 로 인라인하여 # 단일 자체완결 파일(INSTALL_GUIDE.standalone.html)을 만든다. # # 사용: # 1) docs/screenshots/ 에 캡처를 README 의 파일명대로 저장 # 2) python3 docs/build_standalone.py # 3) 산출물: docs/INSTALL_GUIDE.standalone.html (이미지까지 한 파일에 내장 — 폴더 없이 전달 가능) # # 파일이 아직 없는 캡처는 상대경로(src="screenshots/..")로 남겨 두므로, 본문의 # onerror 자리표시가 그대로 동작한다. 캡처를 채운 뒤 다시 실행하면 모두 내장된다. # 외부(http/https)·이미 data: 인 src 는 건드리지 않는다(폐쇄망 유지). # ============================================================================= import base64, os, re, sys BASE = os.path.dirname(os.path.abspath(__file__)) # docs/ SRC = os.path.join(BASE, 'INSTALL_GUIDE.html') OUT = os.path.join(BASE, 'INSTALL_GUIDE.standalone.html') MIME = {'.png':'image/png', '.svg':'image/svg+xml', '.jpg':'image/jpeg', '.jpeg':'image/jpeg', '.gif':'image/gif', '.bmp':'image/bmp', '.webp':'image/webp'} def to_data_uri(path: str) -> str: ext = os.path.splitext(path)[1].lower() mime = MIME.get(ext, 'application/octet-stream') with open(path, 'rb') as f: b64 = base64.b64encode(f.read()).decode('ascii') return f'data:{mime};base64,{b64}' def main() -> int: if not os.path.isfile(SRC): print(f'ERROR: {SRC} 없음', file=sys.stderr); return 1 html = open(SRC, encoding='utf-8').read() embedded, missing, skipped = [], [], [] for src in sorted(set(re.findall(r'src="([^"]+)"', html))): if src.startswith(('data:', 'http://', 'https://')): skipped.append(src); continue fp = os.path.normpath(os.path.join(BASE, src)) if os.path.isfile(fp): html = html.replace(f'src="{src}"', f'src="{to_data_uri(fp)}"') embedded.append(src) else: missing.append(src) open(OUT, 'w', encoding='utf-8').write(html) print(f'내장(embedded) {len(embedded)}개:') for e in embedded: print(' +', e) if missing: print(f'미존재 — 상대경로 유지(캡처 추가 후 재실행) {len(missing)}개:') for m in missing: print(' -', m) if skipped: print(f'건너뜀(외부/이미 data:) {len(skipped)}개') size = os.path.getsize(OUT) print(f'\n산출물: {OUT} ({size/1024:.0f} KB)') if not missing: print('→ 모든 이미지 내장 완료. 이 파일 하나만 전달하면 됩니다(폴더 불필요).') else: print('→ 일부 캡처 미제공: 해당 자리는 자리표시로 표시됩니다. 캡처 추가 후 다시 실행하세요.') return 0 if __name__ == '__main__': raise SystemExit(main())