HTML 덱 -> 네이티브, 편집 가능한 PPTX
이 스킬이 적용하는 규칙: 절대로 슬라이드 이미지를 PowerPoint에 붙여넣지 마세요. 모든 사각형, 막대, 점, 필, 선 및 텍스트 블록은 사용자가 이동, 색상 변경 및 다시 입력할 수 있는 실제 PowerPoint 객체여야 합니다. 변환기는 CSS를 다시 추측하는 대신 렌더링된 페이지(Playwright + 브라우저의 자체 계산된 레이아웃)를 읽은 다음 동일한 좌표에 python-pptx 도형을 작성합니다.
실행 방법
python scripts/html_to_pptx.py <deck.html> <out.pptx> [all | 1,3,5]
필요 항목: pip install -r requirements.txt 및 playwright install chromium
슬라이드는 .slide와 일치하는 요소(1280x720 px)입니다. 이미지가 인라인(data: URI)으로 포함된 .html을 같은 위치에 두거나 디스크에 함께 두십시오. examples/sample-deck.html은 먼저 시도해볼 수 있는 작은 덱입니다.
페이지가 캡처될 때의 모양(스크립트가 자동으로 수행): <html>에서 anim 클래스 제거, CSS 애니메이션/트랜지션 비활성화, window beforeprint 실행(덱은 인쇄 시 차트를 표시하는 경우가 많음), 인쇄 미디어, 줌 1, .mode 또는 .jump 클래스가 있는 요소 숨김(테마 토글, 슬라이드 탐색기). 라이트/다크 토글이 있는 덱은 현재 표시 중인 테마로 변환됩니다. 사용자가 원하는 테마인지 확인하세요.
무엇이 무엇으로 바뀌나
| HTML | PPTX |
|---|---|
| 배경, 테두리, 둥근 모서리가 있는 div/카드 | 사각형 / 둥근 사각형 (radius -> corner adjust) |
| 그라데이션 배경(선형) | 네이티브 그라데이션 채우기 |
| 한쪽 면만 있는 테두리(강조 스트라이프) | 얇은 사각형; 가는선/점선 테두리 -> 실제 선 |
border-radius:999px 필, 원 | 필 / 타원 |
텍스트 (모든 블록, 굵게/색상 실행, <br>, 링크 포함) | 블록당 하나의 텍스트 상자, 실행 유지, 하이퍼링크 유지 |
<li> | 실제 PowerPoint 글머리 기호(마커 색상 유지) |
| 인라인 SVG rect/circle/line/polyline/path/text | 사각형, 타원, 커넥터(화살촉 유지), 실제 베지어 곡선이 있는 자유형, 텍스트 상자 |
SVG <textPath>(곡선 위 텍스트) | PowerPoint 곡선 텍스트(Arch Up/Down 워프) |
CSS clip-path: polygon(...) (쉐브론, 대각선 절단) | 자유형; 내부 사진은 다각형으로 잘림 |
<img>, 사진, 아이콘 PNG | 그림(비트맵이므로 예상됨) |
text-transform, 자간, 취소선, 불투명도/알파 | 실행/채우기에 적용 |
두 뷰 토글(.vtog와 data-view=code 및 data-view=time 버튼) | 다른 뷰를 위한 두 번째 슬라이드 |
| JS 애니메이션 | 최종 고정 상태만 |
어렵게 얻은 규칙 (각각 실제 시간이 소요되었습니다 — 유지하세요)
- 텍스트 위치는 보정되었으며, 눈대중으로 '수정'하지 마십시오. PowerPoint 100% 줄 간격 = 1.2 x 글꼴 크기(Arial 및 Arial Black 모두 동일). 텍스트 상자는
top = rangeTop + (ascent-cap)*fs - lineHeight + K*fs에 배치해야 하며,(ascent-cap, K) = (0.189, 0.95)(Arial) 및(0.385, 1.0)(Arial Black),line_spacing = cssLineHeight / (1.2*fs)입니다. 한 줄 텍스트는 간격 100%와wrap=none을 사용하여 여유를 두어 다시 줄바꿈되지 않도록 합니다. - Windows의 Chrome은
font-family: Arial을 weight 800/900으로 ARIAL BLACK으로 렌더링합니다. 변환기는 이를 Arial Black에 매핑합니다(굵게 아님). 이렇게 하지 않으면 모든 굵은 헤드라인이 너무 얇고 잘못된 너비로 보입니다. - 인라인 블록 자식을 텍스트 블록으로 병합하지 마십시오.
display:inline자식만 하나의 텍스트 상자로 병합되고, 인라인블록/플렉스 자식은 별도로 처리됩니다. - 제자리에서 텍스트 노드를 측정하십시오(노드의 Range). 노드를 임시
<span>으로 감싸면 그리드/플렉스 레이아웃이 변경됩니다. - 결과를 PowerPoint에서 열어 유효한지 확인하십시오. python-pptx는 PowerPoint가 거부하는 파일을 기꺼이 작성합니다("PowerPoint에서 파일을 열 수 없습니다."). 알려진 원인: 음수/NaN 도형 크기(클램프, NaN 포인트 제거),
clip-path내부의calc()(평가). 도형을 반으로 삭제하고 다시 열어 이분법으로 찾으십시오. - 사용자 정의 지오메트리가 있는 그림은 프레임이 아닌 패스의 경계 상자를 채웁니다. 사진을 다각형으로 자르려면 사진 크기를 다각형의 경계 상자로 조정하고 나머지 부분에 대해 소스 자르기(
srcRect)를 설정하십시오. - 도형을 스크린샷으로 캡처하지 마십시오("이상한 것은 래스터화"). 로고의 SVG 경로와 클립패스 다각형을 대신 자유형으로 변환하십시오.
raster브랜치는 최후의 수단입니다. - 잘린 유령 텍스트를 건너뛰십시오(카드에 의해 잘린 큰 희미한 숫자) — PowerPoint는 텍스트 상자를 클리핑할 수 없습니다.
- PowerPoint
a:ln은spPr의 채우기 뒤에 옵니다. 테마p:style을 삭제하지 않으면 도형이 그림자를 가져옵니다. - 사용자가 열어둔 .pptx를 덮어쓰지 마십시오 — 대신 새 파일 이름을 작성하십시오.
검증 (항상 — 보지 않고 배송하지 마십시오)
PowerPoint가 설치된 Windows:
powershell -NoProfile -File scripts/render_pptx.ps1 -pptx <out.pptx> -outdir <png_dir> # PowerPoint에서 PNG로 내보내기
python scripts/compare.py <deck.html> <png_dir> 1,2,3 <out.png> # HTML | PPTX 나란히 비교
python scripts/compare.py <deck.html> <png_dir> 6:6,7:8 <out.png> # 슬라이드 번호가 다를 때 html:pptx 비교
render_pptx.ps1은 사용자가 이미 PowerPoint를 열어둔 경우 실행 중인 상태로 둡니다. PowerPoint 없이 다른 방법(예: LibreOffice headless)으로 .pptx를 PNG로 렌더링하여 s1.png, s2.png...로 저장하고 compare.py를 실행하십시오.
비교 PNG를 읽고, 수정하고, 다시 빌드하십시오. 실행 후 일반적인 정리: PowerPoint에서 텍스트가 약간 더 넓어짐(커닝), 구조적인 문제 없음.
알려진 제한 사항 (사용자에게 알리십시오)
- 텍스트 배치는 Arial 및 Arial Black에 대해 보정되었습니다. 다른 글꼴도 변환되지만, 해당 글꼴이 보정될 때까지(캡 높이와 줄 간격을 PowerPoint에서 측정) 텍스트가 몇 픽셀 위나 아래에 위치할 수 있습니다.
- 비트맵으로 제공된 사진, 아이콘 및 로고는 그림으로 유지됩니다. 텍스트는 카드 위에 별도의 자체 상자에 있습니다(그룹화되지 않음).
- 애니메이션/토글은 한 프레임으로 평탄화됩니다(토글의 두 번째 뷰는 추가 슬라이드가 됨).
- 방사형 그라데이션 및 모서리별 둥글기는 근사치입니다. 상자 그림자는 제거됩니다.
- 슬라이드 크기는 1280x720 px -> 13.333 x 7.5 in으로 고정됩니다.
크레딧
Impera Business Services 제작. MIT 라이선스 — LICENSE 참조.