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

# Tambahkan Watermark SVG ke PDF yang Ada dengan Python

> Gabungkan watermark SVG ke PDF dengan svglib, ReportLab, dan pypdf. Periksa opasitas, halaman terpotong, rotasi, teks yang dipertahankan, serta urutan lapisan.

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

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

Untuk menambahkan watermark SVG ke PDF yang sudah ada dengan Python, konversi SVG menjadi objek gambar ReportLab, render ke PDF lapisan kecil, lalu gabungkan lapisan itu ke setiap halaman asli menggunakan pypdf. Tentukan ukuran dan posisi lapisan berdasarkan kotak pemotongan terlihat setiap halaman, serta normalkan rotasi halaman sebelum penggabungan.

Gunakan `over=True` jika tanda harus tetap terlihat di atas latar halaman yang opak. Tanda semitransparan pun dapat berada di atas. Dengan `over=False`, gambar yang sama berada di bawah konten yang ada dan bisa tersembunyi di balik halaman berisi warna.

Contoh lengkap di bawah membuat SVG dan PDF sumber tiga halamannya sendiri. Contoh mencakup ukuran halaman berbeda, kotak pemotongan dengan titik asal bukan nol, serta halaman yang diputar. Hasilnya adalah PDF baru; simpan berkas asli secara terpisah.

## Pilih dahulu operasi dokumennya

| Titik awal                                             | Alur yang berguna                                                                                 |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
| PDF yang ada membutuhkan lambang SVG di setiap halaman | Merender lapisan SVG dan menggabungkannya ke halaman yang ada, seperti di bawah                   |
| PDF baru disusun dari awal                             | Menggunakan langsung [alur gambar SVG ReportLab](https://perfectvector.com/id/blog/reportlab-svg) |
| SVG yang ada sudah berisi gambar yang benar            | Mempertahankan sumber vektor asli itu; penelusuran tidak diperlukan                               |
| Logo hanya tersedia sebagai gambar raster              | Menyiapkan gambar yang sesuai dahulu, lalu menguji penggabungan PDF secara terpisah               |

[Panduan watermark pypdf](https://pypdf.readthedocs.io/en/stable/user/add-watermark.html) membedakan konten di atas dan di bawah halaman. Di sini, “watermark” berarti lambang yang terlihat; `over` menentukan urutan penumpukan sebenarnya. Ini bukan tanda keamanan, cara mencegah manipulasi, atau alur untuk dokumen bertanda tangan.

## 1. Mulai dengan SVG kecil yang didukung

Uji ini menggunakan dua jalur dengan isian: bingkai segitiga dengan bagian tengah terbuka dan tiga batang. Kedua jalur memiliki `fill-opacity="0.25"`. Tidak ada teks, filter, gambar tersemat, atau sumber daya eksternal.

Masukan yang terbatas itu penting. svglib mendukung subset SVG yang berguna, tetapi [batasan yang didokumentasikan](https://github.com/deeplook/svglib) mencakup dukungan CSS terbatas dan fitur yang tidak didukung seperti mask serta `foreignObject`. SVG yang terlihat benar di browser tetap perlu diperiksa setelah konversi. Jika berkas mengandung raster, baca [cara menemukan gambar tersemat dalam SVG](https://perfectvector.com/id/blog/svg-contains-raster-image) sebelum menganggap hasil sepenuhnya vektor.

Versi awal bentuk uji ini mengandung teks SVG selain bingkai. Pada susunan perangkat lunak yang diuji, teks hasil konversi digambar dengan opasitas penuh sementara jalurnya mempertahankan opasitas 0,25. Saya mengganti teks itu dengan gambar jalur asli dan menguji penggantinya. Hasil akhir membuktikan kasus khusus jalur ini; bukan membuktikan opasitas yang benar untuk setiap kombinasi teks atau gaya SVG.

## 2. Jalankan contoh lengkap

Lingkungan yang diuji adalah Python 3.12.14, svglib 2.2.0, ReportLab 4.4.9, dan pypdf 6.10.0. Dokumentasi pypdf saat ini juga menjelaskan rilis lebih baru, jadi bedakan versi yang diuji dari versi dokumentasi.

Dalam lingkungan terpisah, instal versi-versi tersebut:

```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
```

Simpan yang berikut sebagai `watermark_demo.py`. Contoh menyertakan semua gambar masukan dan membuat ketiga PDF, jadi tidak ada PDF atau SVG contoh yang masih perlu diunduh.

```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)
```

Jalankan:

```bash
python watermark_demo.py
```

Buka `watermark-output/source.pdf`, `overlay-top.pdf`, dan `underlay.pdf`. Halaman pertama seharusnya menampilkan lambang dalam keluaran lapisan atas, tetapi menyembunyikannya dalam keluaran lapisan bawah karena latar aslinya opak. Dua halaman lain menguji pemotongan dan rotasi, bukan mengulangi geometri halaman yang sama.

Untuk PDF biasa Anda yang tidak ditandatangani, pertahankan `make_overlay()` dan `add_artwork()`, lalu panggil:

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

Writer mempertahankan versi header sumber dengan minimum PDF 1.4 karena lapisan menggunakan transparansi. Pada pypdf 6.10.0, hanya mengkloning dokumen dapat meninggalkan header PDF 1.3 bawaan writer meskipun sumber menyatakan versi lebih baru. Penetapan eksplisit menghindari penurunan itu; bukan validasi kesesuaian. [Dokumentasi header writer](https://pypdf.readthedocs.io/en/6.10.0/modules/PdfWriter.html#pypdf.PdfWriter.pdf_header) menyarankan versi yang mendukung semua fitur dalam berkas.

Pemeriksaan pengaman menolak masukan terenkripsi dan kolom formulir yang terdeteksi. Itu bukan audit kompatibilitas atau tanda tangan lengkap. Dokumen bertanda tangan, formulir, anotasi, enkripsi, dan kebutuhan khusus dokumen memerlukan alur serta validasi terpisah sebelum mengganti berkas kerja.

## 3. Tempatkan gambar dalam koordinat halaman yang terlihat

Satu poin PDF adalah 1/72 inci. Dalam versi svglib ini, dimensi SVG tanpa satuan 240 × 80 menghasilkan gambar 180 × 60 poin: satu piksel CSS dipetakan ke 0,75 poin. Kode membaca `drawing.width` dan `drawing.height` alih-alih menganggap piksel SVG sudah sama dengan poin PDF.

Contoh membuat viewport SVG sebesar 65% lebar terlihat setiap halaman, mempertahankan rasio aspek, dan memusatkan viewport tersebut. Yang dipusatkan adalah persegi panjang gambar yang dinyatakan, bukan massa visual lambang. Nilai 65% merupakan pilihan tata letak contoh, bukan standar watermark. Skala berdasarkan lebar saja sesuai untuk lambang lebar di sini. Pengganti yang tinggi dapat melebihi tinggi halaman terlihat; saat menyesuaikan fungsi, batasi skala berdasarkan lebar dan tinggi yang tersedia serta periksa setiap halaman sebelum menggunakan PDF Anda sendiri.

| Halaman | Kondisi sumber                       | Kotak pemotongan terlihat pada keluaran, dalam poin | Lebar nominal viewport SVG |
| ------- | ------------------------------------ | --------------------------------------------------- | -------------------------- |
| 1       | Halaman lanskap 420 × 300            | 0, 0 hingga 420, 300                                | 273pt                      |
| 2       | Halaman 300 × 420, dipotong ke dalam | 10, 20 hingga 290, 400                              | 182pt                      |
| 3       | Halaman 360 × 260 dengan rotasi 90°  | 0, 0 hingga 260, 360 setelah normalisasi            | 169pt                      |

Memanggil `transfer_rotation_to_content()` memindahkan rotasi ke konten dan kotak halaman. Fungsi itu tidak meluruskan kata-kata asli terhadap pembaca. Teks asli halaman ketiga tetap berorientasi seperti dalam tampilan sumber, sementara lambang baru ditempatkan pada koordinat terlihat yang dinormalisasi. [API halaman pypdf](https://pypdf.readthedocs.io/en/stable/modules/PageObject.html) menyarankan pemindahan rotasi sebelum penggabungan halaman.

Lapisan dimulai dari titik asalnya sendiri. Mentranslasikannya sebesar `cropbox.left` dan `cropbox.bottom` menempatkannya dalam daerah terlihat target meskipun kotak pemotongan tidak dimulai dari nol. `expand=False` mencegah penggabungan memperbesar kotak halaman.

## 4. Periksa PDF tersimpan, bukan hanya pratinjau SVG

![Perbandingan PDF yang benar-benar dirender menunjukkan lapisan bawah tersembunyi, lapisan atas semitransparan terlihat, halaman potret terpotong, dan halaman sumber berotasi dengan lambang vektor terpusat](https://perfectvector.com/blog/svg-watermark-existing-pdf/pdf-overlay.webp)

*Render Poppler sebenarnya dari PDF tersimpan. Latar halaman asli menyembunyikan lapisan bawah; lapisan atas tetap terlihat. Dua tampilan terakhir memeriksa titik asal pemotongan bukan nol dan halaman yang awalnya berotasi.*

Saya membuka ulang PDF tersimpan dan memeriksa aliran konten, kotak halaman, rotasi, teks hasil ekstraksi, serta sumber daya gambar, lalu merender kotak pemotongan terlihat dengan Poppler 26.02 pada 96dpi. Pemeriksaan akhir berkas lulus 40 pengujian. Perbandingan browser juga memverifikasi hash berkas tersimpan, render yang dimuat, dan 12 pemeriksaan piksel pada resolusi asli.

| Pemeriksaan pada bentuk uji ini             | Hasil yang diamati                                                                                                                   |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Jumlah halaman dan teks asli yang diketahui | Ketiga halaman dan teks sumber yang diharapkan tetap ada pada kedua keluaran                                                         |
| Geometri lapisan                            | Dua jalur dengan isian, 18 titik sudut diperiksa, alfa isian 0,25 pada setiap halaman                                                |
| Sumber daya gambar yang ditambahkan         | Tidak ada pada halaman sumber dan keluaran asli ini                                                                                  |
| Posisi dan kotak halaman                    | Cocok dengan kotak pemotongan yang dinyatakan dan perhitungan transformasi terserialisasi; rotasi keluaran nol                       |
| Pemeriksaan bingkai dan tengah terbuka      | Piksel bingkai lapisan atas cocok dengan pencampuran yang diharapkan dalam ±2 nilai RGB; tengah terbuka mempertahankan latar halaman |
| Lapisan bawah pada latar opak               | Render sumber dan lapisan bawah halaman pertama berbeda nol piksel pada 96dpi                                                        |

Audit posisi awalnya gagal dalam perbandingan ketat dengan koordinat ideal bilangan pecahan bertoleransi 0,00001pt. ReportLab menserialisasi matriks transformasi dengan presisi terbatas. Saya mempertahankan hasil gagal itu, menghitung secara independen matriks terserialisasi yang diharapkan serta batas pembulatannya, lalu membandingkan titik sudut tersimpan dengan nilai-nilai tersebut. Selisih terbesar yang diamati dari koordinat ideal sekitar 0,000054pt, masih dalam batas turunan 0,000086pt. Ini memeriksa posisi yang tampak terpusat pada berkas ini; bukan jaminan presisi universal.

Untuk pemeriksaan visual lokal singkat dengan Poppler terinstal:

```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
```

Periksa setiap halaman pada pembesaran yang berguna. Pilih atau ekstrak juga teks asli yang diharapkan, periksa dimensi halaman, dan lihat apakah watermark tetap berupa jalur atau menambahkan gambar. Tangkapan layar tajam saja tidak membuktikan properti berkas tersebut. Uji ini tidak mengukur pencetakan, kompatibilitas penampil, penghematan ukuran berkas, atau ketahanan terhadap penghapusan watermark.

## Perbaiki kegagalan pada tahap yang tepat

| Gejala                                                 | Yang diperiksa atau diubah                                                                                      |
| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
| Tanda menghilang                                       | Bandingkan `over=False` dengan `over=True`; cari latar asli yang opak                                           |
| Posisi tanda salah pada halaman terpotong              | Gunakan ukuran dan titik asal kotak pemotongan, bukan ukuran halaman tetap                                      |
| Halaman berotasi menempatkan tanda ke arah tak terduga | Normalkan rotasi sebelum menghitung dimensi terlihat; periksa tampilan hasilnya                                 |
| Opasitas atau gaya berubah                             | Sederhanakan SVG, periksa status pewarnaan PDF hasil konversi, lalu uji ulang berkas yang persis sama           |
| Bagian seperti foto atau berpiksel tetap ada           | Periksa SVG untuk gambar tersemat; pembungkus SVG tidak mengubah bitmap menjadi jalur                           |
| Teks, formulir, atau perilaku dokumen berubah          | Berhenti dan validasi fitur dokumen sebenarnya, jangan menganggap penggabungan berhasil mempertahankan semuanya |

PDF asli tetap menjadi konten halaman; skrip tidak merasterisasi seluruh halaman. Itu tidak membuktikan bahwa setiap PDF masukan akan tetap tidak berubah setelah penggabungan sembarang. Gunakan salinan, dan tentukan konten serta fitur dokumen yang wajib tetap bekerja sebelum memproses kelompok lebih besar.

## Siapkan gambar yang belum ada sebelum penggabungan

Jika logo yang ada sudah berupa SVG bersih, pertahankan. Jika hanya tersisa logo raster datar yang sesuai, [vektorisator logo PerfectVector](https://perfectvector.com/id/vectorize-logo) dapat membantu menyiapkan gambar yang dapat diedit sebelum tahap Python ini. Periksa siluet, lubang, dan detail kecil yang dipulihkan, lalu ulangi konversi SVG serta pemeriksaan PDF tersimpan. Contoh ini menggunakan jalur asli yang dibuat langsung dan tidak menjalankan konversi PerfectVector. Vektorisasi tidak menggabungkan halaman, memvalidasi tanda tangan, atau menjamin kompatibilitas svglib.

## Tanya jawab

**Bisakah pypdf langsung membaca watermark SVG?**
Contoh ini terlebih dahulu mengonversi SVG melalui svglib dan ReportLab menjadi lapisan PDF. pypdf lalu menggabungkan konten halaman PDF; dalam alur ini pypdf tidak menafsirkan sumber SVG.

**Mengapa watermark menghilang di balik halaman PDF saya?**
Lapisan bawah dapat tertutup latar opak yang sudah ada. Gunakan `over=True` agar lapisan atas terlihat dan tetapkan opasitas gambar secara terpisah. Periksa hasil sebenarnya pada setiap halaman.

**Apakah ini mempertahankan gambar vektor dan teks asli?**
Lambang khusus jalur yang diuji tetap berupa jalur dengan isian, dan teks asli yang diharapkan tetap dapat diekstrak pada ketiga halaman. Fitur SVG dan dokumen PDF di luar bentuk uji ini membutuhkan validasi terpisah.

**Apakah menulis ulang PDF mempertahankan tanda tangan digital?**
Jangan gunakan contoh ini sebagai alur dokumen bertanda tangan. Contoh menulis ulang berkas dan tidak menguji pelestarian atau validitas tanda tangan. Simpan dokumen asli yang ditandatangani dan gunakan alur sesuai kebutuhan tanda tangannya.

## Sumber

1. [pypdf: Menambahkan stempel atau watermark](https://pypdf.readthedocs.io/en/stable/user/add-watermark.html) — Urutan lapisan atas dan bawah, penggabungan, serta panduan rotasi.
2. [pypdf: API PageObject](https://pypdf.readthedocs.io/en/stable/modules/PageObject.html) — Kotak halaman, pemindahan rotasi, dan perilaku penggabungan dengan transformasi.
3. [Dokumentasi proyek svglib](https://github.com/deeplook/svglib) — Konversi SVG ke ReportLab, satuan, dan batasan fitur yang didukung.
4. [Panduan grafis ReportLab](https://docs.reportlab.com/reportlab/userguide/ch11_graphics/) — Objek gambar dan render PDF dalam sistem grafis ReportLab.
5. [pypdf 6.10.0: Versi header PDF](https://pypdf.readthedocs.io/en/6.10.0/modules/PdfWriter.html#pypdf.PdfWriter.pdf_header) — Menyatakan versi PDF yang mendukung fitur dalam keluaran.

Pertahankan gambar asli jika tersedia. Jika hanya tersisa logo raster datar yang sesuai, [siapkan SVG yang dapat diedit dengan PerfectVector](https://perfectvector.com/id/vectorize-logo), periksa gambar itu, lalu verifikasi PDF yang baru digabungkan secara terpisah.

## Explore

- [Read the HTML article](https://perfectvector.com/id/blog/svg-watermark-existing-pdf)
- [Gambar SVG fpdf2: Pertahankan Path dalam PDF Python](https://perfectvector.com/id/blog/fpdf2-svg-image.md)
- [SVG PDFKit: Tempatkan Logo Vektor Tanpa Rasterisasi](https://perfectvector.com/id/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)
