> [Site index](https://perfectvector.com/llms.txt) — available pages and descriptions.

# Dodaj znak wodny SVG do istniejącego PDF w Pythonie

> Połącz znak wodny SVG z PDF za pomocą svglib, ReportLab i pypdf. Sprawdź krycie, przycięte strony, obrót, zachowany tekst i kolejność nakładania.

Source: https://perfectvector.com/pl/blog/svg-watermark-existing-pdf

Language: pl
Author: Irene Kim
Published: 2026-10-11T08:00:00+09:00
Updated: 2026-10-16T08:00:00+09:00

Aby dodać znak wodny SVG do istniejącego PDF w Pythonie, zamień SVG na rysunek ReportLab, wyrenderuj go do małej nakładki PDF, a następnie scal ją z każdą oryginalną stroną przez pypdf. Dobierz rozmiar i pozycję z widocznego pola przycięcia strony i znormalizuj obrót przed scalaniem.

Użyj `over=True`, gdy znak ma pozostać widoczny nad nieprzezroczystym tłem strony. Półprzezroczysty znak również może leżeć na wierzchu. Przy `over=False` ta sama grafika trafia pod istniejącą treść i może zniknąć za wypełnioną stroną.

Kompletny przykład poniżej tworzy własny SVG i trzystronicowy PDF źródłowy. Uwzględnia różne rozmiary stron, pole przycięcia z niezerowym początkiem i obróconą stronę. Wynikiem jest nowy PDF; zachowaj oryginał oddzielnie.

## Najpierw wybierz operację dokumentu

| Punkt wyjścia                                             | Przydatny proces                                                                                       |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| Istniejący PDF potrzebuje emblematu SVG na każdej stronie | Wyrenderuj nakładkę SVG i scal z istniejącymi stronami, jak poniżej                                    |
| Nowy PDF jest tworzony od podstaw                         | Użyj bezpośrednio [procesu rysowania SVG w ReportLab](https://perfectvector.com/pl/blog/reportlab-svg) |
| Istniejący SVG już ma właściwą grafikę                    | Zachowaj natywne źródło wektorowe; trasowanie jest zbędne                                              |
| Logo istnieje wyłącznie jako raster                       | Najpierw przygotuj odpowiednią grafikę, potem oddzielnie przetestuj scalanie PDF                       |

[Poradnik znaków wodnych pypdf](https://pypdf.readthedocs.io/en/stable/user/add-watermark.html) rozróżnia treść nad i pod stroną. Tutaj „znak wodny” oznacza widoczny emblemat; `over` określa rzeczywistą kolejność stosu. Nie jest to zabezpieczenie, metoda ochrony przed modyfikacją ani proces dokumentu podpisanego.

## 1. Zacznij od małego obsługiwanego SVG

Test używa dwóch wypełnionych ścieżek: trójkątnej ramki z otwartym środkiem i trzech pasków. Obie mają `fill-opacity="0.25"`. Nie ma tekstu, filtrów, osadzonych obrazów ani zasobów zewnętrznych.

To wąskie wejście ma znaczenie. svglib obsługuje użyteczny podzbiór SVG, lecz jego [udokumentowane ograniczenia](https://github.com/deeplook/svglib) obejmują ograniczony CSS oraz brak masek i `foreignObject`. SVG poprawny w przeglądarce nadal wymaga kontroli po konwersji. Jeśli zawiera raster, przeczytaj [wyszukiwanie osadzonych obrazów w SVG](https://perfectvector.com/pl/blog/svg-contains-raster-image), zanim uznasz wynik za całkowicie wektorowy.

Pierwsza wersja próbki miała tekst SVG obok ramki. W testowanym zestawie przekonwertowany tekst był malowany z pełnym kryciem, a ścieżka zachowała 0.25. Zastąpiłam tekst autorską grafiką ścieżek i przetestowałam zamiennik. Końcowy wynik potwierdza ten przypadek samych ścieżek, a nie poprawne krycie każdej kombinacji tekstu i stylów SVG.

## 2. Uruchom kompletny przykład

Testowane środowisko to Python 3.12.14, svglib 2.2.0, ReportLab 4.4.9 i pypdf 6.10.0. Aktualna dokumentacja pypdf opisuje też nowsze wydania, więc odróżniaj testowane wersje od wersji dokumentacji.

W oddzielnym środowisku zainstaluj te wersje:

```bash
python -m venv .venv
source .venv/bin/activate
python -m pip install svglib==2.2.0 reportlab==4.4.9 pypdf==6.10.0
```

Zapisz kod jako `watermark_demo.py`. Zawiera całą grafikę wejściową i tworzy trzy PDF, więc nie brakuje przykładowego PDF ani SVG do pobrania.

```python
from io import BytesIO
from pathlib import Path

from pypdf import PdfReader, PdfWriter, Transformation
from pypdf.generic import RectangleObject
from reportlab.graphics import renderPDF
from reportlab.lib.colors import HexColor
from reportlab.pdfgen import canvas
from svglib.svglib import svg2rlg

SVG = '''<svg xmlns="http://www.w3.org/2000/svg" width="240" height="80"
             viewBox="0 0 240 80">
  <path fill="#315d6f" fill-opacity="0.25" fill-rule="nonzero"
        d="M10 60 L45 8 L80 60 Z M31 48 L59 48 L45 27 Z"/>
  <path fill="#315d6f" fill-opacity="0.25"
        d="M95 23 H216 V31 H95 Z M95 39 H190 V47 H95 Z
           M95 55 H205 V63 H95 Z"/>
</svg>'''


def make_demo_source(destination):
    stream = BytesIO()
    document = canvas.Canvas(stream, pagesize=(420, 300))
    specifications = [
        (420, 300, '#f5eddb', 'SOURCE PAGE ONE'),
        (300, 420, '#ffffff', 'SOURCE PAGE TWO'),
        (360, 260, '#e8eef0', 'SOURCE PAGE THREE')
    ]
    for width, height, background, label in specifications:
        document.setPageSize((width, height))
        document.setFillColor(HexColor(background))
        document.rect(0, 0, width, height, fill=1, stroke=0)
        document.setFillColor(HexColor('#183a42'))
        document.setFont('Helvetica-Bold', 16)
        document.drawString(28, height - 40, label)
        document.setFont('Helvetica', 10)
        document.drawString(28, height - 62, 'Original text remains in the PDF content.')
        document.drawString(28, 28, 'Original vector line and opaque page background')
        document.setStrokeColor(HexColor('#c47b44'))
        document.setLineWidth(3)
        document.line(28, 48, width - 28, 48)
        document.showPage()
    document.save()
    reader = PdfReader(stream)
    reader.pages[1].cropbox = RectangleObject([10, 20, 290, 400])
    reader.pages[2].rotate(90)
    writer = PdfWriter()
    for page in reader.pages:
        writer.add_page(page)
    writer.write(destination)


def make_overlay(svg_path, width, height):
    drawing = svg2rlg(str(svg_path))
    if drawing is None or drawing.width <= 0 or drawing.height <= 0:
        raise ValueError('The SVG did not produce a usable drawing')
    scale = width * 0.65 / drawing.width
    left = (width - drawing.width * scale) / 2
    bottom = (height - drawing.height * scale) / 2
    drawing.scale(scale, scale)
    stream = BytesIO()
    overlay = canvas.Canvas(stream, pagesize=(width, height))
    renderPDF.draw(drawing, overlay, left, bottom)
    overlay.save()
    return PdfReader(stream).pages[0]


def add_artwork(source_path, svg_path, output_path, *, over):
    reader = PdfReader(source_path)
    if reader.is_encrypted:
        raise ValueError('Encrypted inputs are outside this example')
    if reader.get_fields():
        raise ValueError('Form handling is outside this example')
    writer = PdfWriter()
    writer.clone_document_from_reader(reader)
    # Cloning in pypdf 6.10.0 does not retain the source header version.
    # This overlay uses transparency, introduced in PDF 1.4.
    writer.pdf_header = max(reader.pdf_header, '%PDF-1.4')
    for page in writer.pages:
        if page.rotation:
            page.transfer_rotation_to_content()
        box = page.cropbox
        width, height = float(box.width), float(box.height)
        overlay = make_overlay(svg_path, width, height)
        page.merge_transformed_page(
            overlay,
            Transformation().translate(float(box.left), float(box.bottom)),
            over=over,
            expand=False
        )
    writer.write(output_path)


if __name__ == '__main__':
    output = Path('watermark-output')
    output.mkdir(exist_ok=True)
    artwork = output / 'emblem.svg'
    artwork.write_text(SVG)
    source = output / 'source.pdf'
    make_demo_source(source)
    add_artwork(source, artwork, output / 'overlay-top.pdf', over=True)
    add_artwork(source, artwork, output / 'underlay.pdf', over=False)
```

Uruchom:

```bash
python watermark_demo.py
```

Otwórz `watermark-output/source.pdf`, `overlay-top.pdf` i `underlay.pdf`. Strona pierwsza powinna pokazywać emblemat w wersji nakładki górnej, lecz ukrywać go w dolnej, bo oryginalne tło jest nieprzezroczyste. Pozostałe strony sprawdzają przycięcie i obrót zamiast powtarzać tę samą geometrię.

Dla własnego zwykłego, niepodpisanego PDF zachowaj `make_overlay()` i `add_artwork()`, a potem wywołaj:

```python
add_artwork(
    Path("original.pdf"),
    Path("emblem.svg"),
    Path("watermarked.pdf"),
    over=True
)
```

Writer zachowuje wersję nagłówka źródłowego z minimum PDF 1.4, ponieważ nakładka używa przezroczystości. W pypdf 6.10.0 samo klonowanie dokumentu może pozostawić domyślny nagłówek PDF 1.3 nawet przy nowszej wersji źródła. Jawne przypisanie unika obniżenia wersji; nie jest walidacją zgodności. [Dokumentacja nagłówka writera](https://pypdf.readthedocs.io/en/6.10.0/modules/PdfWriter.html#pypdf.PdfWriter.pdf_header) zaleca wersję obsługującą wszystkie funkcje pliku.

Warunki ochronne odrzucają szyfrowane wejścia i wykryte pola formularzy. Nie są pełnym audytem zgodności ani podpisów. Dokumenty podpisane, formularze, adnotacje, szyfrowanie i szczególne wymagania dokumentu potrzebują oddzielnego procesu i walidacji przed zastąpieniem roboczego pliku.

## 3. Umieść grafikę we współrzędnych widocznej strony

Punkt PDF ma 1/72 cala. W tej wersji svglib surowe wymiary SVG 240 × 80 dają rysunek 180 × 60 punktów: jeden piksel CSS mapuje się na 0.75 punktu. Kod odczytuje `drawing.width` i `drawing.height`, zamiast zakładać równość pikseli SVG i punktów PDF.

Przykład nadaje viewportowi SVG 65% szerokości widocznej strony, zachowuje proporcje i centruje viewport. Centruje zadeklarowany prostokąt rysunku, a nie wizualny ciężar emblematu. 65% jest przykładową decyzją układu, a nie standardem znaku wodnego. Skala tylko według szerokości pasuje do pokazanego szerokiego emblematu. Wysoki zamiennik może wyjść poza wysokość strony; dostosowując funkcję, ogranicz skalę dostępną szerokością i wysokością oraz sprawdź każdą stronę przed użyciem własnego PDF.

| Strona | Warunek źródłowy                       | Widoczne pole przycięcia wyniku w punktach | Nominalna szerokość viewportu SVG |
| ------ | -------------------------------------- | ------------------------------------------ | --------------------------------- |
| 1      | Pozioma strona 420 × 300               | 0, 0 do 420, 300                           | 273pt                             |
| 2      | Strona 300 × 420 przycięta do wewnątrz | 10, 20 do 290, 400                         | 182pt                             |
| 3      | Strona 360 × 260 z obrotem 90°         | 0, 0 do 260, 360 po normalizacji           | 169pt                             |

`transfer_rotation_to_content()` przenosi obrót do treści i pól strony. Nie prostuje oryginalnych słów względem oglądającego. Tekst strony trzeciej zachowuje orientację widoku źródła, a nowy emblemat trafia do znormalizowanych współrzędnych widocznego obszaru. [API stron pypdf](https://pypdf.readthedocs.io/en/stable/modules/PageObject.html) zaleca przenoszenie obrotu przed scalaniem.

Nakładka zaczyna we własnym początku. Przesunięcie o `cropbox.left` i `cropbox.bottom` umieszcza ją wewnątrz widocznego obszaru celu nawet przy początku innym niż zero. `expand=False` zapobiega powiększeniu pól strony przy scalaniu.

## 4. Sprawdź zapisany PDF, a nie tylko podgląd SVG

![Rzeczywiste porównanie renderów PDF z ukrytą dolną nakładką, widoczną półprzezroczystą górną, przyciętą stroną pionową i obróconą stroną źródłową z wyśrodkowanym emblematem wektorowym](https://perfectvector.com/blog/svg-watermark-existing-pdf/pdf-overlay.webp)

*Rzeczywiste rendery Poppler zapisanych PDF. Oryginalne tła stron ukrywają dolną nakładkę; górna pozostaje widoczna. Ostatnie dwa widoki sprawdzają niezerowy początek przycięcia i pierwotnie obróconą stronę.*

Ponownie otworzyłam PDF i sprawdziłam strumienie treści, pola stron, obrót, wyodrębniony tekst i zasoby obrazów, a potem wyrenderowałam widoczne pola przycięcia Poppler 26.02 w 96dpi. Końcowa kontrola pliku przeszła 40 testów. Porównanie w przeglądarce potwierdziło też hasze plików, wczytane rendery i 12 próbek pikseli w natywnej rozdzielczości.

| Kontrola tego przykładu                   | Zaobserwowany wynik                                                                                     |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| Liczba stron i znany oryginalny tekst     | Trzy strony i oczekiwany tekst źródłowy pozostały w obu wynikach                                        |
| Geometria nakładki                        | Dwie wypełnione ścieżki, 18 sprawdzonych wierzchołków i alfa wypełnienia 0.25 na każdej stronie         |
| Dodane zasoby obrazów                     | Brak w tych oryginalnych stronach źródłowych i wynikowych                                               |
| Położenie i pola stron                    | Zgodne z zadeklarowanym przycięciem i obliczeniami zapisanych transformacji; obrót wyjścia wynosił zero |
| Próbki ramki i otwartego środka           | Piksele górnej ramki zgodne z mieszaniem w granicach ±2 RGB; otwarte środki zachowały tło strony        |
| Dolna nakładka pod nieprzezroczystym tłem | Rendery źródła i dolnej nakładki strony pierwszej różniły się w zerze pikseli przy 96dpi                |

Audyt położenia początkowo nie przeszedł ścisłego porównania z idealnymi współrzędnymi zmiennoprzecinkowymi przy tolerancji 0.00001pt. ReportLab zapisuje macierze transformacji ze skończoną precyzją. Zachowałam błędny wynik, niezależnie obliczyłam oczekiwane zapisane macierze i granicę zaokrągleń oraz porównałam wierzchołki z tymi wartościami. Największa różnica od idealnej współrzędnej wyniosła około 0.000054pt, w wyliczonej granicy 0.000086pt. Kontroluje to wizualne wyśrodkowanie w tych plikach, a nie uniwersalną gwarancję precyzji.

Do szybkiej kontroli wizualnej z zainstalowanym Poppler:

```bash
pdftoppm -cropbox -r 96 -png watermark-output/overlay-top.pdf watermark-output/top
pdftoppm -cropbox -r 96 -png watermark-output/underlay.pdf watermark-output/below
```

Obejrzyj każdą stronę w użytecznym powiększeniu. Zaznacz lub wyodrębnij też oczekiwany tekst, sprawdź wymiary i ustal, czy znak wodny pozostał ścieżkami, czy wprowadził obrazy. Sam ostry zrzut nie potwierdza tych właściwości. Test nie mierzył druku, zgodności przeglądarek PDF, oszczędności rozmiaru ani odporności na usunięcie znaku.

## Napraw błąd na właściwym etapie

| Objaw                                                    | Co sprawdzić lub zmienić                                                                                         |
| -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Znak znika                                               | Porównaj `over=False` z `over=True`; szukaj nieprzezroczystych oryginalnych teł                                  |
| Znak leży źle na przyciętej stronie                      | Użyj rozmiaru i początku pola przycięcia zamiast stałego rozmiaru strony                                         |
| Obrócone strony ustawiają znak niespodziewanie           | Znormalizuj obrót przed obliczeniem widocznych wymiarów; sprawdź wynik                                           |
| Krycie lub styl się zmienia                              | Uprość SVG, sprawdź stan malowania przekonwertowanego PDF i ponownie przetestuj ten plik                         |
| Pozostaje fotograficzny lub pikselowy obszar             | Sprawdź osadzone obrazy SVG; opakowanie SVG nie zamienia bitmapy w ścieżki                                       |
| Tekst, formularze lub zachowanie dokumentu się zmieniają | Zatrzymaj proces i zweryfikuj rzeczywiste cechy dokumentu zamiast zakładać, że udane scalanie zachowuje wszystko |

Oryginalny PDF pozostaje treścią stron; skrypt nie rasteruje całych stron. Nie dowodzi to zachowania każdego wejściowego PDF przy dowolnym scalaniu. Używaj kopii i określ wymagane działanie treści oraz funkcji dokumentu przed większą partią.

## Przygotuj brakującą grafikę przed scalaniem

Jeśli istniejące logo jest czystym SVG, zachowaj je. Jeśli pozostał tylko odpowiedni płaski raster, [wektoryzator logo PerfectVector](https://perfectvector.com/pl/vectorize-logo) może pomóc przygotować edytowalną grafikę przed etapem Pythona. Sprawdź odzyskaną sylwetkę, otwory i drobne detale, a potem powtórz konwersję SVG i kontrole zapisanego PDF. Przykład używał autorskich natywnych ścieżek bez konwersji PerfectVector. Wektoryzacja nie scala stron, nie sprawdza podpisów i nie gwarantuje zgodności svglib.

## FAQ

**Czy pypdf odczyta znak wodny SVG bezpośrednio?**
Przykład najpierw konwertuje SVG przez svglib i ReportLab do nakładki PDF. pypdf scala potem treść stron PDF; nie interpretuje tutaj źródła SVG.

**Dlaczego znak wodny znika za stroną PDF?**
Dolną nakładkę może zakrywać istniejące nieprzezroczyste tło. Użyj `over=True` dla widocznej górnej nakładki i ustaw krycie grafiki oddzielnie. Sprawdź rzeczywisty wynik na każdej stronie.

**Czy zachowuje to wektory i oryginalny tekst?**
Testowany emblemat samych ścieżek pozostał wypełnionymi ścieżkami, a oczekiwany tekst dawał się wyodrębnić na wszystkich trzech stronach. Inne funkcje SVG i PDF wymagają oddzielnej walidacji.

**Czy przepisanie PDF zachowa podpis cyfrowy?**
Nie używaj przykładu jako procesu dokumentów podpisanych. Przepisuje plik i nie testuje zachowania ani ważności podpisu. Zachowaj podpisany oryginał i stosuj proces odpowiedni do wymagań podpisu.

## Źródła

1. [pypdf: dodawanie stempla lub znaku wodnego](https://pypdf.readthedocs.io/en/stable/user/add-watermark.html) — kolejność nakładek, scalanie i wskazówki obrotu.
2. [pypdf: API PageObject](https://pypdf.readthedocs.io/en/stable/modules/PageObject.html) — pola stron, przenoszenie obrotu i scalanie z transformacją.
3. [Dokumentacja projektu svglib](https://github.com/deeplook/svglib) — konwersja SVG do ReportLab, jednostki i ograniczenia funkcji.
4. [Poradnik grafiki ReportLab](https://docs.reportlab.com/reportlab/userguide/ch11_graphics/) — obiekty rysunkowe i renderowanie PDF w systemie grafiki ReportLab.
5. [pypdf 6.10.0: wersja nagłówka PDF](https://pypdf.readthedocs.io/en/6.10.0/modules/PdfWriter.html#pypdf.PdfWriter.pdf_header) — deklarowanie wersji obsługującej funkcje wyniku.

Zachowaj natywną grafikę, jeśli ją masz. Gdy pozostało tylko odpowiednie rastrowe logo, [przygotuj edytowalny SVG za pomocą PerfectVector](https://perfectvector.com/pl/vectorize-logo), sprawdź grafikę, a następnie oddzielnie zweryfikuj nowy scalony PDF.

## Explore

- [Read the HTML article](https://perfectvector.com/pl/blog/svg-watermark-existing-pdf)
- [Obrazy SVG w fpdf2: zachowaj ścieżki w pliku PDF tworzonym w Pythonie](https://perfectvector.com/pl/blog/fpdf2-svg-image.md)
- [PDFKit SVG: umieść logo wektorowe bez spłaszczania](https://perfectvector.com/pl/blog/pdfkit-svg.md)
- [Product facts](https://perfectvector.com/product-facts.md)
- [FAQ](https://perfectvector.com/faq.md)
- [Pricing and credits](https://perfectvector.com/pricing.md)
