PerfectVector
Autor: Irene Kim8 min czytania

Obrazy SVG w WeasyPrint: napraw brakujące logo w plikach PDF

Napraw brakujące logo SVG w plikach PDF z WeasyPrint za pomocą poprawnego bazowego adresu URL i jawnego określenia rozmiaru w CSS, a następnie sprawdź ścieżki wektorowe, proporcje i grafikę w zapisanym pliku PDF.

Na tej stronie

WeasyPrint może umieścić SVG w pliku PDF za pomocą elementu obrazu HTML. Jeśli logo znika, gdy przekazujesz HTML jako ciąg znaków, najpierw sprawdź adres URL obrazu: ścieżka względna wymaga bazowego adresu URL. Gdy plik już się załaduje, ustaw jego rozmiar wydruku w CSS i sprawdź zapisany plik PDF. Aktualna dokumentacja API WeasyPrint opisuje ten wymóg dotyczący base_url.

Poniższy przykład odtwarza przypadek brakującego obrazu przy użyciu autorskiego logo w kształcie ramki. Sprawdza też, czy naprawiony plik PDF zawiera wektorową geometrię rysunku o żądanym rozmiarze. Jeśli masz już SVG, zacznij od tego pliku. Wektoryzacja pojawia się w tym procesie tylko wtedy, gdy grafika źródłowa istnieje w postaci pikseli.

Sprawdź ładowanie, zanim zmienisz grafikę

Plik PDF może powstać nawet wtedy, gdy brakuje w nim logo. Sprawdź ostrzeżenie dotyczące zasobu, rozwiąż problem ze ścieżką obrazu i ponownie wyrenderuj ten sam SVG, zanim zaczniesz edytować jego kształty lub konwertować go do innego formatu.

Odtwórz problem z brakującym SVG w małym dokumencie

Testowaliśmy przy użyciu Pythona 3.13.9 i WeasyPrint 70.0. Użyj środowiska projektu i zainstaluj wskazaną wersję:

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

WeasyPrint potrzebuje też bibliotek natywnych, w tym Pango. Skorzystaj z instrukcji instalacji dla danego systemu operacyjnego, jeśli import lub polecenie sprawdzające wersję kończy się błędem. Brak biblioteki natywnej to inny problem niż brak logo.

Utwórz taką strukturę folderów:

example/
  render.py
  assets/
    logo.svg

Zapisz tę autorską grafikę demonstracyjną jako assets/logo.svg. Otwór pośrodku daje Ci do sprawdzenia coś bardziej użytecznego niż pełny prostokąt. To ręcznie opracowana geometria, a nie wynik konwersji w 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>

Umieść poniższy kod w 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")

Uruchom python render.py. W naszym pierwszym pliku PDF nie było ramki, a zamiast niej pojawił się tekst alternatywny obrazu. Dziennik zawierał:

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

Drugi plik PDF pokazywał turkusową ramkę z zachowanym otworem. Oba wywołania utworzyły plik, więc samo istnienie pliku PDF nie było użytecznym sprawdzianem powodzenia.

Zapewnij ścieżkom względnym stały folder początkowy

assets/logo.svg wskazuje plik względem innej lokalizacji. base_url w drugim wywołaniu podaje tę lokalizację początkową. root.as_uri() tworzy bezwzględny URI pliku; końcowy ukośnik sprawia, że jest on bazą wskazującą katalog. Logo pozostaje w tym samym folderze assets, a zawartość SVG się nie zmienia.

Użycie Path(__file__) utrzymuje też powiązanie przykładu z folderem skryptu, gdy uruchamiasz go z innego katalogu roboczego. W notatniku użyj zamiast tego jawnie wskazanego folderu projektu, ponieważ __file__ zwykle nie jest tam dostępne.

Ilustracja grafiki SVG w folderze połączonej strzałką z tą samą grafiką na stronie dokumentu
Ilustracja ustalania lokalizacji zasobu: dokument potrzebuje ścieżki do pliku SVG, zanim będzie mógł umieścić grafikę.

Jest jeszcze jeden przydatny test kontrolny. Zapisz HTML jako invoice.html obok render.py i wczytaj sam plik:

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

WeasyPrint może wyznaczyć bazę na podstawie nazwy pliku wejściowego lub adresu URL. Nasz test z plikiem dał taką samą ramkę jak przypadek z jawnie określoną bazą. Ciąg znaków zawierający HTML nie ma odpowiadającej mu nazwy pliku, z której można by wywnioskować tę bazę. Te tryby wejściowe i ich reguły ustalania bazy opisano w dokumentacji konstruktora HTML.

W przypadku obrazu dostępnego po zalogowaniu poprawny adres URL nadal może nie wystarczyć. Dokumentacja mechanizmu pobierania zasobów z adresów URL podaje, że domyślny klient HTTP nie zapewnia obsługi plików cookie ani uwierzytelniania. Użyj zatwierdzonego w Twojej aplikacji sposobu pobierania zasobów i przetestuj go w środowisku generującym PDF. Nie zakładaj, że logo widoczne w przeglądarce po zalogowaniu jest dostępne dla procesu tworzącego PDF.

Ustaw rozmiar obrazu niezależnie od rozmiaru strony PDF

Przykład używa @page do określenia arkusza A4 i marginesów, a .logo ustawia szerokość obrazu na 60 mm. Proporcje źródłowe 2:1 sprawiają, że przy height: auto ma on 30 mm wysokości. W naszym zapisanym pliku PDF ramka miała wymiary 60 × 30 mm i zaczynała się 20 mm od górnej i lewej krawędzi strony.

Tutaj rysunek wypełnia cały swój viewBox. Twoje logo może mieć pustą przestrzeń wewnątrz tego prostokąta, więc pole obrazu o szerokości 60 mm może zawierać wyraźnie węższy znak. Sprawdź obszar SVG, zanim spróbujesz skompensować tę różnicę, arbitralnie zwiększając szerokość w CSS. Poradnik dotyczący rozmiaru importowanego SVG wyjaśnia to rozróżnienie bardziej szczegółowo.

Podczas sprawdzania wymiarów fizycznych pozostaw domyślne zoom=1 w write_pdf(). Dokumentacja wyjścia PDF WeasyPrint ostrzega, że zmiana zoom skaluje również fizyczne jednostki CSS i nazwane rozmiary stron.

Co widziszCo sprawdzić najpierwNastępny krok
Tekst alternatywny zastępuje logoAdres URL obrazu i dziennik zasobówPodaj prawidłowy bazowy adres URL lub dostępny bezwzględny adres URL
Logo ma niewłaściwy rozmiarSzerokość w CSS i proporcje źródłaUstaw szerokość w jednostkach fizycznych i sprawdź obszar SVG
Brakuje części grafikiGranice źródła i konkretną funkcję SVGOgranicz przykład do niewielkiego przypadku odtwarzającego błąd i porównaj wyeksportowany PDF
Renderowanie lokalne działa, a na serwerze nieDostępne pliki, fonty i dostęp do adresów URLPrzetestuj przy użyciu zasobów procesu uruchomionego we wdrożonym środowisku

Sprawdź zawartość i wygląd pliku PDF

Aktualna dokumentacja formatów WeasyPrint podaje, że obrazy SVG są renderowane w plikach PDF jako grafika wektorowa. Nie oznacza to, że każdy plik z rozszerzeniem .svg zawiera wyłącznie grafikę wektorową: SVG może zawierać osadzony obraz rastrowy. Sprawdź to za pomocą diagnostyki osadzonych obrazów, jeśli w wyniku nadal widać piksele.

W przypadku tego prostego materiału testowego sprawdziliśmy zapisane pliki PDF za pomocą PyMuPDF 1.26.7:

Przypadek wejściowyRekordy rysunkówOsadzone obrazyWidoczna ramka
Ciąg znaków HTML bez bazy00Brak; pojawił się tekst alternatywny
Ciąg znaków HTML z folderem jako bazą1060 × 30 mm, otwór zachowany
HTML wczytany na podstawie nazwy pliku10Taki sam wynik jak dla ciągu znaków z określoną bazą

Te wyniki dotyczą dostarczonej ramki, a nie wszystkich funkcji SVG. Jedna ścieżka złożona również nie oznacza jednego widocznego kształtu: jej wewnętrzna podścieżka definiuje otwór.

Aby sprawdzić swój resolved.pdf, zainstaluj pymupdf==1.26.7 i uruchom:

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)

Dokumentacja klasy Page w PyMuPDF opisuje metody sprawdzania rysunków i obrazów. Te liczby służą diagnostyce i nie stanowią potwierdzenia wierności odwzorowania. Otwórz też plik PDF: sprawdź otwór, kolory, proporcje i ewentualne napisy w rzeczywistym rozmiarze, w jakim dokument trafi do odbiorcy. Sprawdzaj kolejno poszczególne elementy złożonej grafiki i powtarzaj kontrole przy aktualizacji silnika renderującego.

Kiedy najpierw przygotować nowy SVG

Gdy jedyne dostępne logo to PNG lub JPG, narzędzie do wektoryzacji logo PerfectVector może przygotować plik SVG do sprawdzenia, zanim umieścisz go w dokumencie HTML. Sprawdź kontury, małe otwory i napisy w edytorze, a następnie przetestuj SVG w tym samym procesie WeasyPrint. Poradnik wektoryzacji obrazów wyjaśnia, co się zmienia, gdy piksele stają się ścieżkami.

Zachowaj oryginalny edytowalny SVG, jeśli istnieje. Popraw odwołanie do jego pliku lub układ zamiast ponownie go wektoryzować. Fotografie mogą pozostać obrazami rastrowymi, a dokładne odwzorowanie firmowych napisów może wymagać oryginalnego fontu lub ręcznego przerysowania. Wektoryzacja nie naprawia brakujących plików na serwerze, uwierzytelniania ani nieobsługiwanych funkcji renderowania.

Jeśli potrzebujesz jedynie przekonwertować SVG na osobną stronę PDF, proces eksportu w CairoSVG obejmuje to mniejsze zadanie. WeasyPrint nadaje się do dokumentu HTML, w którym grafika dzieli stronę z inną treścią.

FAQ

Dlaczego WeasyPrint tworzy PDF bez mojego logo SVG? Mimo błędu ładowania obrazu pozostała część dokumentu może nadal zostać wyrenderowana. Sprawdź dziennik zasobów i adres URL obrazu. W dostarczonym teście ciąg znaków HTML ze względną ścieżką obrazu wymagał jawnie określonego bazowego adresu URL.

Czy muszę najpierw przekonwertować SVG na PNG? Nie. WeasyPrint przyjmuje obrazy SVG. Zachowaj obsługiwaną grafikę wektorową jako SVG, jeśli taki ma być wynik, i sprawdź zapisany plik PDF. Eksport rastrowy jest alternatywą, gdy świadomie stawiasz wygląd ponad geometrią wektorową.

Czy base_url zmienia rozmiar wydruku logo? Nie. Zapewnia bazę do rozwiązywania względnych adresów URL zasobów. Ustaw rozmiar umieszczanego obrazu za pomocą CSS, a wymiary SVG i viewBox sprawdź osobno.

Źródła

  1. WeasyPrint API reference — Opisuje dane wejściowe HTML, bazowe adresy URL, renderowanie SVG w wynikowym PDF oraz działanie parametru zoom przy generowaniu PDF.
  2. WeasyPrint First Steps — Obejmuje instalację i pobieranie zasobów, w tym ograniczenia uwierzytelniania.
  3. PyMuPDF Page reference — Opisuje użyte w przykładzie metody sprawdzania rysunków i osadzonych obrazów.

Masz tylko logo rastrowe? Przygotuj SVG za pomocą PerfectVector, sprawdź jego kształty i napisy, a następnie umieść go w swoim HTML i zweryfikuj jego wygląd oraz wymiary fizyczne w zapisanym pliku PDF.

Więcej z bloga

Zacznij od czystszego SVG,
który łatwiej edytować