PerfectVector
Autor: Irene Kim8 min czytania

SVG w ReportLab: zachowaj ostrość ścieżek logo w generowanych PDF-ach

Umieszczaj logo SVG w PDF-ach ReportLab za pomocą svglib, zachowuj jego proporcje i sprawdzaj gotowy plik pod kątem ścieżek wektorowych, prawidłowego rozmiaru i brakujących szczegółów.

Na tej stronie

Użyj svglib.svg2rlg(), aby wczytać SVG do obiektu Drawing w ReportLab, a następnie umieść ten obiekt za pomocą renderPDF.draw(). Wyznacz mu na stronie obszar o określonych wymiarach i użyj jednego współczynnika skali dla obu osi. Dzięki temu odpowiednia geometria logo pozostaje zestawem instrukcji rysowania w PDF-ie zamiast wstawionego rastrowego zrzutu ekranu.

W przypadku samodzielnego eksportu bez układu dokumentu opis dobierania rozmiaru w CairoSVG porównuje piksele PNG, wymiary strony PDF i DPI.

Miarodajny test dotyczy gotowego PDF-a: czy znak zachował proporcje, kolory i małe prześwity w rozmiarze potrzebnym w Twoim dokumencie? Pomyślne wywołanie w Pythonie nie odpowiada na te pytania. Poniższy przykład umieszcza ten sam oryginalny znak dwukrotnie i sprawdza wygenerowany plik.

Jeśli masz już logo w postaci edytowalnej grafiki wektorowej, zacznij od niego. Jeśli zachował się tylko PNG lub JPG, odtwórz wektorowy plik źródłowy, zanim zaczniesz tworzyć dokument. Zdjęcia i wykresy przedstawiające dane liczbowe wymagają innego podejścia do wyboru źródła.

Zaimportuj grafikę jako obiekt Drawing

Udokumentowany sposób pracy z biblioteką svglib przekształca SVG w obiekty rysunkowe ReportLab. Przewodnik po grafice w ReportLab wyjaśnia, że takie obiekty można renderować na płótnie lub używać ich jako elementów flowable w Platypus. W tym przykładzie płótno pozwala jawnie określić pozycję i rozmiar każdego wystąpienia grafiki.

Uruchomiliśmy przykład z Pythonem 3.12, svglib 2.2.0 i ReportLab 4.4.9. Zainstaluj w środowisku projektu te dwa pakiety w podanych wersjach:

python -m pip install "svglib==2.2.0" "reportlab==4.4.9"

Zapisz ten niewielki znak jako logo.svg. Zawiera trzy ścieżki z jednolitymi wypełnieniami, bez podłączonych obrazów, fontów ani efektów. To grafika utworzona ręcznie na potrzeby tej demonstracji, a nie wynik konwersji w PerfectVector.

<svg xmlns="http://www.w3.org/2000/svg"
     width="240" height="120" viewBox="0 0 240 120">
  <path fill="#1c625e" d="M0 120 L60 0 L120 120 Z"/>
  <path fill="#e5a340" d="M96 120 L156 24 L216 120 Z"/>
  <path fill="#163451" d="M228 12 L240 12 L240 108 L228 108 Z"/>
</svg>

Atrybut viewBox pliku SVG opisuje jego wewnętrzny prostokątny obszar współrzędnych. Właściwości width i height zaimportowanego obiektu Drawing podają wymiary, których należy użyć przy umieszczaniu go w PDF-ie. Odczytaj je, zamiast zakładać, że piksel SVG odpowiada punktowi PDF.

Dla tego pliku svglib 2.2.0 zwrócił 180 × 90 punktów. Jego aktualna dokumentacja jednostek przelicza piksel CSS na 0,75 punktu PDF. Starsze przykłady mogą opierać się na innych założeniach, więc sprawdzaj wymiary przy aktualizacji istniejącego procesu generowania dokumentów.

Dopasuj logo bez rozciągania

Zapisz poniższy kod jako place_logo.py obok pliku SVG i uruchom python place_logo.py. Wszystkie pozycje na stronie i wymiary obszarów są tu podane w punktach PDF. Jeden cal to 72 punkty; domyślny początek układu współrzędnych płótna znajduje się w lewym dolnym rogu, zgodnie z opisem w przewodniku po płótnie ReportLab.

from reportlab.graphics import renderPDF
from reportlab.pdfgen import canvas
from svglib.svglib import svg2rlg
 
 
def draw_svg_in_box(pdf, drawing, x, y, box_w, box_h):
    if drawing.width <= 0 or drawing.height <= 0:
        raise ValueError("The SVG needs positive dimensions")
    factor = min(box_w / drawing.width, box_h / drawing.height)
    pdf.saveState()
    pdf.translate(x, y)
    pdf.scale(factor, factor)
    renderPDF.draw(drawing, pdf, 0, 0)
    pdf.restoreState()
 
 
drawing = svg2rlg("logo.svg")
if drawing is None:
    raise ValueError("SVG could not be loaded")
 
pdf = canvas.Canvas("logo.pdf", pagesize=(640, 360))
draw_svg_in_box(pdf, drawing, 40, 154, 144, 72)
draw_svg_in_box(pdf, drawing, 302, 126, 288, 144)
pdf.save()

Funkcja min() wybiera wymiar ograniczający skalowanie, dzięki czemu grafika mieści się w wyznaczonym obszarze. Użycie tego samego współczynnika dla X i Y zachowuje proporcje. Ta funkcja umieszcza grafikę w lewym dolnym rogu obszaru; niewykorzystane miejsce pozostaje nad nią lub po prawej stronie. Wyśrodkuj ją osobno, jeśli wymaga tego Twój układ.

Transformacja płótna jest tymczasowa. restoreState() zapobiega wpływowi skalowania logo na późniejszy tekst lub elementy strony, a oryginalny obiekt Drawing pozostaje dostępny do drugiego umieszczenia.

W teście dwa współczynniki wynosiły 0,8 i 1,6, co dało grafikę o wymiarach 144 × 72 pt i 288 × 144 pt. Podgląd dodaje etykiety i tło do tych samych dwóch wystąpień grafiki, aby łatwo było porównać ich rozmiary.

Ten sam zielono-złoty znak umieszczony w rozmiarach 144 na 72 punkty i 288 na 144 punkty w wyrenderowanym PDF-ie
Zrzut wyrenderowanego testowego PDF-a. Logo składa się z trzech oryginalnych ścieżek narysowanych w dwóch rozmiarach. Obraz na stronie jest rastrowym podglądem; inspekcja PDF-a potwierdziła obecność ścieżek rysunkowych i brak osadzonych obrazów.

W dokumencie Platypus obiekt Drawing może trafić do listy elementów dokumentu jako element flowable. Po przeskalowaniu jego zawartości za pomocą drawing.scale(factor, factor) pomnóż drawing.width i drawing.height przez ten sam współczynnik, aby układ uwzględniał nowe wymiary zajmowanego obszaru. Przy stosowaniu różnych rozmiarów korzystaj z nowo wczytanego obiektu Drawing. Powyższy przykład z płótnem nie zmienia samego obiektu.

Sprawdzaj geometrię i wygląd osobno

Sprawdziliśmy strumień zawartości testowego PDF-a za pomocą pypdf 6.10.0. Zawierał sześć operacji rozpoczęcia ścieżki, odpowiadających trzem ścieżkom znaku narysowanym dwukrotnie, oraz zero obrazów na stronie. Wyrenderowaliśmy też całą stronę za pomocą Poppler i obejrzeliśmy oba znaki. Kształty, wzajemne nakładanie się elementów, pionowy pasek i proporcje odpowiadały zamierzonym rozmieszczeniom.

Te obserwacje dotyczą tego prostego pliku testowego. Samo liczenie ścieżek nie dowodzi, że każda cecha innego SVG została poprawnie wyrenderowana. Podobnie powiększanie PDF-a na ekranie nie pozwala jednoznacznie stwierdzić, czy zawiera on instrukcje wektorowe, czy dużą bitmapę.

W swoim dokumencie:

  1. Porównaj gotowy PDF z SVG otwartym w przeglądarce lub edytorze. Szukaj brakujących szczegółów, zmienionych wypełnień, przycięć i nieoczekiwanych białych obszarów.
  2. Sprawdź znak w docelowym rozmiarze w dokumencie — przy tym rozmiarze wąskie prześwity i cienkie obrysy muszą pozostać czytelne.
  3. Sprawdź obiekty obrazów w PDF-ie, jeśli Twój proces wymaga grafiki wektorowej. Uwzględnij zdjęcia celowo umieszczone w innych miejscach strony.
  4. Przechowuj źródłowy plik SVG obok kodu generującego dokument. Sprawdź PDF ponownie po zmianie grafiki lub zależności używanych do jej renderowania.

Sam SVG może zawierać obraz rastrowy. Wczytanie takiego pliku nie odtwarza ścieżek z jego pikseli. Poradnik diagnozowania osadzonych obrazów pomaga odróżnić wektorowy plik źródłowy od SVG, który nadal zawiera bitmapę.

Obsłuż funkcje, których importer nie potrafi odtworzyć

Aktualne ograniczenia svglib obejmują nieobsługiwane maski i elementy foreignObject, ignorowane reguły @import w arkuszach stylów oraz ograniczenia dotyczące CSS i przycinania. Podgląd w przeglądarce nie może więc zastąpić testowania importera PDF.

Zachowaj kopię pliku źródłowego przed jego uproszczeniem. Jeśli logo zależy od nieobsługiwanego efektu, rozważ odtworzenie tej części za pomocą zwykłej geometrii lub skorzystanie z innej metody eksportu, której wynik możesz zweryfikować. Zachowaj oryginalny obraz rastrowy, gdy wygląd fotograficzny ma większe znaczenie niż edycja ścieżek. Spłaszczony obraz może zachować wygląd, ale zmienia wymaganie dotyczące postaci wektorowej.

W przypadku napisów świadomie wybierz między tekstem dokumentu a grafiką zamienioną na kontury. Zachowanie słów jako tekstu umożliwia edycję i wyszukiwanie, ale wymaga dostępności właściwego fontu w procesie tworzenia dokumentu. Zamiana zatwierdzonego napisu w logo na kontury zachowuje jego kształt kosztem zwykłej edycji tekstu. Nasz znak złożony wyłącznie ze ścieżek nie testuje obsługi fontów; zanim oprzesz się na tym samym procesie, użyj rzeczywistej próbki tekstu złożonego wybranym krojem pisma.

Jeśli składasz dokument w systemie składu tekstu zamiast w Pythonie, opis używania SVG w LaTeX wyjaśnia osobną metodę pracy z grafiką i etykietami.

Odtwórz logo dostępne tylko jako obraz rastrowy przed umieszczeniem go w PDF-ie

Starszy PNG w szablonie faktury jest rozsądnym kandydatem do odtworzenia w postaci wektorowej, gdy brakuje oryginalnego pliku logo. Za pomocą narzędzia PerfectVector do wektoryzacji logo zobacz podgląd grafiki rastrowej jako SVG, sprawdź kontury i prześwity, a następnie pobierz plik do wypróbowania w procesie generowania dokumentów.

Przed importem sprawdź małe napisy i obramowania. Przerysuj lub ponownie złóż elementy wymagające dokładnej typografii i usuń w edytorze niepożądaną geometrię tła. Poradnik wektoryzacji logo omawia bardziej szczegółowo decyzję o przekształceniu materiału źródłowego w edytowalny plik wektorowy.

Następnie wykonaj rzeczywisty import do ReportLab i opisane wyżej kontrole PDF-a. Dobry wynik wektoryzacji nadal musi przejść przez importer i pasować do Twojego dokumentu. PerfectVector dostarcza ścieżki grafiki; nie wybiera współrzędnych w ReportLab, nie rejestruje fontów dokumentu ani nie weryfikuje wynikowego PDF-a. W przypadku wykresów wygeneruj je ponownie z danych i źródła użytego do ich rysowania, zamiast wektoryzować ich etykiety lub przedstawione wartości.

FAQ

Czy mogę przekazać SVG do ReportLab jako zwykły obraz bitmapowy? W tym procesie zachowującym grafikę wektorową użyj svglib, aby utworzyć obiekt Drawing, i wyrenderuj go za pomocą renderPDF. Wcześniejsza konwersja SVG do PNG prowadzi zamiast tego do wstawienia obrazu rastrowego.

Dlaczego mój zaimportowany SVG jest mniejszy niż w starszym przykładzie? Testowany svglib 2.2.0 przelicza piksele CSS na punkty PDF ze współczynnikiem 0,75. Odczytaj zwrócone wymiary obiektu Drawing i dopasuj go do jawnie określonego obszaru, zamiast polegać na starszych założeniach dotyczących przeliczania pikseli na punkty.

Czy to zachowuje każdy efekt SVG? Nie. Importer ma udokumentowane ograniczenia obsługiwanych funkcji, w tym dotyczące masek i foreignObject. Porównaj wyeksportowany PDF z zamierzoną grafiką, nawet jeśli skrypt zakończy się bez błędu.

Czy mam wektoryzować zrzut ekranu wykresu? Gdy tylko to możliwe, wygeneruj wykres ponownie z jego danych i źródła użytego do rysowania. Wektoryzację logo stosuj do odpowiedniej grafiki dekoracyjnej, której edytowalny oryginał zaginął.

Źródła

  1. svglib — Package and units documentation — Konwersja SVG do obiektu Drawing, instalacja i dobieranie rozmiaru w punktach PDF.
  2. ReportLab — Graphics — Obiekty Drawing, renderowanie PDF i użycie jako elementów flowable w Platypus.
  3. ReportLab — Graphics and text with pdfgen — Współrzędne płótna, punkty i transformacje.
  4. svglib — Known limitations — Ograniczenia importu wymagające sprawdzenia gotowego PDF-a.

Zachowaj edytowalny oryginał, jeśli go masz. Jeśli pozostała tylko rastrowa grafika logo, przygotuj wersję logo w SVG do sprawdzenia, obejrzyj jej ścieżki, a następnie umieść ją w wymaganym rozmiarze i sprawdź gotowy PDF.

Więcej z bloga

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