PerfectVector
작성: Irene Kim7분 읽기

WeasyPrint SVG 이미지: PDF에서 빠진 로고 해결하기

올바른 기준 URL과 명시적 CSS 크기로 WeasyPrint PDF에서 빠진 SVG 로고를 해결하세요. 저장된 PDF의 벡터 경로, 비율과 그림을 확인합니다.

목차

WeasyPrint는 HTML 이미지 요소를 통해 SVG를 PDF에 배치할 수 있습니다. HTML을 문자열로 전달할 때 로고가 사라지면 이미지 URL부터 확인하세요. 상대 경로에는 기준 URL이 필요합니다. 파일을 불러온 뒤에는 CSS로 인쇄 크기를 설정하고 저장된 PDF를 확인하세요. 현재 WeasyPrint API 참고 문서는 이 base_url 요구사항을 설명합니다.

아래 예제는 직접 만든 프레임 모양 로고로 이미지 누락 사례를 재현합니다. 수정된 PDF에 요청한 크기의 벡터 그리기 도형이 있는지도 확인합니다. SVG가 이미 있다면 그 파일로 시작하세요. 원본 그림이 픽셀로만 있을 때만 이 작업 흐름에 벡터화가 들어갑니다.

그림을 바꾸기 전에 로딩 확인하기

로고가 없어도 PDF는 만들어질 수 있습니다. 리소스 경고를 확인하고 이미지 경로를 해결한 뒤, 모양을 편집하거나 다른 형식으로 바꾸기 전에 같은 SVG를 다시 렌더링하세요.

작은 문서로 SVG 누락 재현하기

Python 3.13.9와 WeasyPrint 70.0으로 테스트했습니다. 프로젝트 환경에서 고정 버전을 설치하세요.

python -m pip install "weasyprint==70.0"
python -m weasyprint --info

WeasyPrint에는 Pango를 포함한 네이티브 라이브러리도 필요합니다. 가져오기나 버전 명령이 실패하면 운영체제별 설치 지침을 따르세요. 네이티브 라이브러리 누락은 로고 누락과 다른 문제입니다.

다음 폴더 구조를 만드세요.

example/
  render.py
  assets/
    logo.svg

이 직접 만든 데모 그림을 assets/logo.svg로 저장하세요. 중앙 구멍은 단색 사각형보다 확인에 유용한 특징입니다. 직접 작성한 도형이며 PerfectVector 변환 결과가 아닙니다.

<svg xmlns="http://www.w3.org/2000/svg"
     width="120" height="60" viewBox="0 0 120 60">
  <path fill="#087f8c" fill-rule="evenodd"
        d="M0 0H120V60H0Z M20 15V45H100V15Z"/>
</svg>

다음을 render.py에 넣으세요.

from pathlib import Path
import logging
from weasyprint import HTML
 
logging.basicConfig(level=logging.WARNING)
root = Path(__file__).resolve().parent
 
html = """<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <style>
    @page { size: A4; margin: 20mm; }
    body { margin: 0; }
    .logo { display: block; width: 60mm; height: auto; }
  </style>
</head>
<body>
  <img class="logo" src="assets/logo.svg" alt="Frame logo">
</body>
</html>
"""
 
HTML(string=html).write_pdf(root / "missing-base.pdf")
 
HTML(
    string=html,
    base_url=root.as_uri() + "/",
).write_pdf(root / "resolved.pdf")

python render.py를 실행하세요. 첫 번째 PDF에는 프레임이 없고 이미지 대체 텍스트가 나타났습니다. 로그에는 다음이 있었습니다.

Relative URI reference without a base URI: assets/logo.svg

두 번째 PDF에는 구멍이 유지된 청록색 프레임이 표시됐습니다. 두 호출 모두 파일을 생성했으므로 PDF가 있다는 사실만으로는 성공 여부를 확인할 수 없었습니다.

상대 경로에 고정된 시작 폴더 지정하기

assets/logo.svg는 다른 위치를 기준으로 파일을 지정합니다. 두 번째 호출의 base_url이 그 시작 위치를 제공합니다. root.as_uri()는 절대 파일 URI를 만들고 끝의 슬래시는 디렉터리 기준임을 나타냅니다. 로고는 같은 assets 폴더에 남고 SVG 내용도 바뀌지 않습니다.

Path(__file__)를 사용하면 다른 작업 디렉터리에서 실행해도 예제가 스크립트 폴더를 기준으로 합니다. 노트북에서는 보통 __file__을 사용할 수 없으므로 프로젝트 폴더를 명시하세요.

폴더 속 SVG 그림이 화살표를 통해 문서 페이지의 같은 그림과 연결된 일러스트
리소스 경로 해석의 예시: 문서가 그림을 배치하려면 먼저 SVG 파일에 도달하는 경로가 필요합니다.

또 다른 유용한 대조 테스트가 있습니다. HTML을 render.py 옆에 invoice.html로 저장하고 파일 자체를 불러오세요.

HTML(filename=str(root / "invoice.html")).write_pdf(
    root / "from-file.pdf"
)

WeasyPrint는 입력 파일명이나 URL에서 기준 위치를 얻을 수 있습니다. 파일 기반 테스트는 명시적 기준 URL 사례와 같은 프레임을 만들었습니다. HTML 문자열에는 이런 추론에 사용할 대응 파일명이 없습니다. 입력 모드와 기준 경로 해석 규칙은 HTML 생성자에 설명되어 있습니다.

로그인해야 접근할 수 있는 이미지라면 올바른 URL만으로 부족할 수도 있습니다. URL fetcher 문서는 기본 HTTP 클라이언트가 쿠키나 인증을 제공하지 않는다고 설명합니다. 애플리케이션에서 승인된 리소스 가져오기 방식을 사용하고 PDF를 생성하는 환경에서 테스트하세요. 로그인한 브라우저에 보이는 로고를 PDF 프로세스에서도 접근할 수 있다고 가정하지 마세요.

이미지 크기와 PDF 페이지 크기 따로 설정하기

예제는 @page로 A4 용지와 여백을 설정하고 .logo로 이미지 너비를 60 mm로 설정합니다. 원본 비율이 2:1이므로 height: auto에서 높이는 30 mm가 됩니다. 저장한 PDF에서 프레임은 60 × 30 mm였고 페이지 위와 왼쪽 가장자리에서 20 mm 떨어진 곳에 시작했습니다.

여기서는 그림이 viewBox 전체를 채웁니다. 자신의 로고는 그 사각형 안에 여백이 있어 60 mm 이미지 상자 안의 실제 표식이 더 좁게 보일 수 있습니다. CSS 너비를 임의로 늘리기 전에 SVG 캔버스를 확인하세요. SVG 가져오기 크기 가이드는 이 차이를 더 자세히 설명합니다.

실제 치수를 확인할 때는 write_pdf()를 기본 zoom=1로 유지하세요. WeasyPrint의 PDF 출력 참고 문서는 zoom을 바꾸면 물리적 CSS 단위와 이름으로 지정한 페이지 크기도 함께 조절된다고 경고합니다.

보이는 현상먼저 확인할 사항다음 단계
로고 대신 대체 텍스트 표시이미지 URL과 리소스 로그유효한 기준 URL 또는 접근 가능한 절대 URL 제공
로고 크기가 잘못됨CSS 너비와 원본 가로세로 비율물리적 너비 설정 후 SVG 캔버스 확인
그림 일부가 빠짐원본 경계와 해당 SVG 기능작은 실패 예제로 줄이고 내보낸 PDF 비교
로컬에서는 되지만 서버에서는 실패사용 가능한 파일, 글꼴과 URL 접근배포된 프로세스의 리소스로 테스트

PDF 내용과 모양 확인하기

현재 WeasyPrint 형식 문서는 SVG 이미지가 PDF 출력에서 벡터로 렌더링된다고 설명합니다. 그렇다고 .svg로 끝나는 모든 파일이 벡터 그림만 포함한다는 뜻은 아닙니다. SVG에는 비트맵이 삽입될 수 있습니다. 결과에 여전히 픽셀이 보이면 삽입 이미지 진단으로 확인하세요.

이 단순한 예제에서는 PyMuPDF 1.26.7로 저장된 PDF를 검사했습니다.

입력 사례그리기 기록삽입된 이미지보이는 프레임
기준 URL 없는 HTML 문자열00없음. 대체 텍스트 표시
폴더 기준 URL이 있는 HTML 문자열1060 × 30 mm, 구멍 유지
파일명으로 불러온 HTML10경로를 해결한 문자열과 같은 결과

이 결과는 제공한 프레임에 해당하며 모든 SVG 기능에 해당하지는 않습니다. 복합 경로 하나가 보이는 모양 하나를 뜻하지도 않습니다. 안쪽 하위 경로가 구멍을 정의합니다.

자신의 resolved.pdf를 검사하려면 pymupdf==1.26.7을 설치하고 다음을 실행하세요.

import pymupdf
 
with pymupdf.open("resolved.pdf") as document:
    page = document[0]
    print("Drawing records:", len(page.get_drawings()))
    print("Embedded images:", len(page.get_images()))
    for drawing in page.get_drawings():
        box = drawing["rect"]
        print("Bounds in mm:", box.width * 25.4 / 72,
              box.height * 25.4 / 72)

PyMuPDF의 페이지 참고 문서는 그리기 및 이미지 검사 메서드를 설명합니다. 이 개수는 진단 정보이며 충실도 인증이 아닙니다. PDF도 직접 열어 실제 전달 크기에서 구멍, 색상, 비율과 글자를 확인하세요. 복잡한 그림은 기능별로 검사하고 렌더러 업그레이드 시 검사를 반복하세요.

새 SVG를 먼저 준비해야 할 때

사용 가능한 로고가 PNG나 JPG뿐이라면 PerfectVector의 로고 벡터화 도구로 HTML 문서에 넣기 전 SVG 후보를 준비할 수 있습니다. 편집기에서 윤곽선, 작은 구멍과 글자를 확인한 뒤 같은 WeasyPrint 처리 과정으로 SVG를 테스트하세요. 이미지 벡터화 가이드는 픽셀이 경로가 될 때 무엇이 바뀌는지 설명합니다.

편집 가능한 원본 SVG가 있다면 유지하세요. 다시 추적하기보다 파일 참조나 레이아웃을 고치세요. 사진은 래스터 이미지로 남겨도 되고, 정확한 브랜드 글자는 원래 글꼴이나 수동 재작성이 필요할 수 있습니다. 벡터화는 누락된 서버 파일, 인증이나 지원하지 않는 렌더링 기능을 해결하지 못합니다.

SVG를 독립 PDF 페이지로 변환하기만 하면 된다면 CairoSVG 내보내기 작업 흐름이 그 작은 작업을 다룹니다. WeasyPrint는 그림이 다른 콘텐츠와 페이지를 공유하는 HTML 문서 사례에 적합합니다.

FAQ

WeasyPrint가 SVG 로고 없이 PDF를 만드는 이유는 무엇인가요? 이미지 로딩이 실패해도 나머지 문서는 렌더링될 수 있습니다. 리소스 로그와 이미지 URL을 확인하세요. 제공한 테스트에서는 상대 이미지 경로가 있는 HTML 문자열에 명시적 기준 URL이 필요했습니다.

먼저 SVG를 PNG로 변환해야 하나요? 아닙니다. WeasyPrint는 SVG 이미지를 받습니다. 벡터 출력을 의도했다면 지원되는 벡터 그림을 SVG로 유지하고 저장한 PDF를 확인하세요. 벡터 도형보다 모양을 우선하기로 의도적으로 선택한다면 래스터 내보내기도 대안입니다.

base_url이 로고의 인쇄 크기를 바꾸나요? 아닙니다. 상대 리소스 URL을 해석하는 기준을 제공합니다. 이미지 배치 크기는 CSS로 설정하고 SVG 크기와 viewBox는 별도로 확인하세요.

Sources

  1. WeasyPrint API 참고 문서 — HTML 입력, 기준 URL, SVG 출력과 PDF zoom 동작을 설명합니다.
  2. WeasyPrint 시작하기 — 인증 제한을 포함한 설치와 리소스 가져오기를 다룹니다.
  3. PyMuPDF 페이지 참고 문서 — 예제에 사용한 그리기 및 삽입 이미지 검사 메서드를 설명합니다.

래스터 로고만 있나요? PerfectVector로 SVG를 준비하고 모양과 글자를 확인하세요. HTML에 배치한 뒤 저장된 PDF에서 모양과 실제 크기를 검증하세요.

블로그의 다른 글

편집하기 쉬운
더 깔끔한 SVG로 다시 시작하세요