PerfectVector
Yazan Irene Kim

Python ile Mevcut PDF'ye SVG Filigran Ekleyin

svglib, ReportLab ve pypdf ile mevcut PDF'ye SVG filigran birleştirin. Opaklığı, kırpılmış sayfaları, dönüşü, korunan metni ve kaplama sırasını kontrol edin.

10 dk okuma
Bu sayfada

Python'da mevcut PDF'ye SVG filigran eklemek için SVG'yi ReportLab çizimine dönüştürün, küçük PDF kaplamasına işleyin ve bu kaplamayı pypdf ile her özgün sayfaya birleştirin. Kaplamanın boyutunu ve konumunu her sayfanın görünür kırpma kutusundan belirleyin; birleştirmeden önce sayfa dönüşünü normalleştirin.

İşaretin opak sayfa zemini üzerinde görünmesi gerekiyorsa over=True kullanın. Yarı şeffaf işaret de üstte bulunabilir. over=False ile aynı tasarım mevcut içeriğin altına gider ve dolgulu sayfanın arkasında kaybolabilir.

Aşağıdaki tam örnek kendi SVG'sini ve üç sayfalık kaynak PDF'sini oluşturur. Farklı sayfa boyutları, sıfır olmayan başlangıçlı kırpma kutusu ve döndürülmüş sayfa içerir. Sonuç yeni PDF'dir; özgün dosyayı ayrı tutun.

Önce belge işlemini seçin

Başlangıç noktasıYararlı iş akışı
Mevcut PDF'nin her sayfasına SVG amblem gerekiyorAşağıdaki gibi SVG kaplaması oluşturup mevcut sayfalara birleştirin
Yeni PDF sıfırdan oluşturuluyorReportLab SVG çizim iş akışını doğrudan kullanın
Mevcut SVG doğru tasarımı içeriyorÖzgün vektör kaynağı koruyun; izleme gereksizdir
Logo yalnızca raster görsel olarak varÖnce uygun tasarımı hazırlayıp PDF birleştirmesini ayrı test edin

pypdf filigran rehberi, sayfanın üstüne ve altına yerleştirilen içeriği ayırır. Burada “filigran” görünür amblemdir; gerçek istif sırasını over belirler. Bu güvenlik işareti, kurcalamayı önleme yöntemi veya imzalı belge iş akışı değildir.

1. Küçük ve desteklenen SVG ile başlayın

Bu test iki dolgulu yol kullanır: merkezi açık üçgen çerçeve ve üç çubuk. İki yol da fill-opacity="0.25" taşır. Metin, filtre, gömülü görsel veya dış kaynak içermez.

Bu dar girdi önemlidir. svglib yararlı bir SVG alt kümesini destekler, ancak belgelenen sınırlamaları sınırlı CSS desteğini ve maskelerle foreignObject gibi desteklenmeyen özellikleri içerir. Tarayıcıda doğru görünen SVG, dönüşümden sonra yine kontrol gerektirir. Dosya raster içeriyorsa sonucu tümüyle vektör saymadan önce SVG'de gömülü görsel bulmayı okuyun.

Bu örneğin ilk sürümü çerçeveyle birlikte SVG metni içeriyordu. Test edilen araç birleşiminde dönüştürülen metin tam opak boyanırken yol 0,25 opaklığı korudu. Metni özgün yol tasarımıyla değiştirdim ve yenisini test ettim. Sonuç bu yalnızca yollu durumu doğrular; her SVG metin veya stil birleşiminin doğru opaklığını kanıtlamaz.

2. Tam örneği çalıştırın

Test edilen ortam Python 3.12.14, svglib 2.2.0, ReportLab 4.4.9 ve pypdf 6.10.0'dı. Güncel pypdf belgeleri daha yeni sürümleri de açıklar; bu nedenle test edilen sürümleri belge sürümünden ayrı tutun.

Ayrı ortamda bu sürümleri kurun:

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

Aşağıdakini watermark_demo.py olarak kaydedin. Tüm girdi tasarımını içerir ve üç PDF'yi oluşturur; indirilecek eksik örnek PDF veya SVG yoktur.

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)

Çalıştırın:

python watermark_demo.py

watermark-output/source.pdf, overlay-top.pdf ve underlay.pdf dosyalarını açın. İlk sayfa üst kaplama çıktısında amblemi göstermeli, alt katman çıktısında gizlemelidir; çünkü özgün zemin opaktır. Diğer iki sayfa aynı geometriyi tekrarlamak yerine kırpmayı ve dönüşü sınar.

Kendi imzasız sıradan PDF'niz için make_overlay() ve add_artwork() işlevlerini koruyup şunu çağırın:

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

Kaplama şeffaflık kullandığından yazıcı, kaynak başlık sürümünü en az PDF 1.4 olarak korur. pypdf 6.10.0'da yalnızca belgeyi klonlamak, kaynak daha yeni sürüm belirtse bile yazıcının varsayılan PDF 1.3 başlığını bırakabilir. Açık atama bu düşürmeyi önler; uyumluluk doğrulaması değildir. Yazıcının başlık belgeleri, dosyada kullanılan tüm özellikleri destekleyen sürümü önerir.

Koruma kontrolleri şifreli girdileri ve algılanan form alanlarını reddeder. Tam uyumluluk veya imza denetimi değildir. İmzalı belgeler, formlar, açıklamalar, şifreleme ve belgeye özel gereklilikler, çalışan dosyayı değiştirmeden önce ayrı iş akışı ve doğrulama gerektirir.

3. Tasarımı görünür sayfa koordinatlarına yerleştirin

PDF puntosu 1/72 inçtir. Bu svglib sürümünde SVG'nin birimsiz 240 × 80 ölçüleri 180 × 60 puntoluk çizim üretir: bir CSS pikseli 0,75 puntoya eşlenir. Kod, SVG piksellerini PDF puntolarına eşit varsaymak yerine drawing.width ve drawing.height değerlerini okur.

Örnek, SVG görünüm alanını her görünür sayfa genişliğinin %65'i yapar, en boy oranını korur ve bu alanı ortalar. Amblemin görsel kütlesini değil, tanımlı çizim dikdörtgenini ortalar. %65 değeri örnek yerleşim seçimidir, filigran standardı değildir. Yalnızca genişlik temelli ölçek burada gösterilen geniş ambleme uygundur. Uzun bir yeni tasarım görünür sayfa yüksekliğini aşabilir; işlevi uyarlarken ölçeği hem kullanılabilir genişlikle hem yükseklikle sınırlayın ve kendi PDF'nizi kullanmadan önce her sayfayı inceleyin.

SayfaKaynak durumuÇıktı görünür kırpma kutusu, puntoNominal SVG görünüm genişliği
1420 × 300 yatay sayfa0, 0 ile 420, 300273pt
2İçe kırpılmış 300 × 420 sayfa10, 20 ile 290, 400182pt
390° döndürülmüş 360 × 260 sayfaNormalleştirmeden sonra 0, 0 ile 260, 360169pt

transfer_rotation_to_content() çağrısı dönüşü içeriğe ve sayfa kutularına taşır. Özgün sözcükleri izleyiciye göre düzleştirmez. Özgün üçüncü sayfa metni kaynağın görüntülenen görünümündeki yönünü korur; yeni amblem normalleştirilmiş görünür koordinatlara yerleştirilir. pypdf sayfa API'si, sayfa birleştirmeden önce dönüş aktarımını önerir.

Kaplama kendi başlangıç noktasından başlar. cropbox.left ve cropbox.bottom kadar ötelemek, kırpma kutusu sıfırdan başlamasa bile hedefin görünür bölgesine yerleştirir. expand=False, birleştirmenin sayfa kutularını büyütmesini engeller.

4. Yalnızca SVG önizlemesini değil kaydedilen PDF'yi kontrol edin

Gizli alt katmanı, görünür yarı şeffaf üst kaplamayı, kırpılmış dikey sayfayı ve ortalanmış vektör amblemli döndürülmüş kaynak sayfayı gösteren gerçek PDF karşılaştırması
Kaydedilen PDF'lerin gerçek Poppler görüntüleri. Özgün sayfa zeminleri alt katmanı gizler; üst kaplama görünür kalır. Son iki görünüm sıfır olmayan kırpma başlangıcını ve özgün döndürülmüş sayfayı kontrol eder.

Kaydedilen PDF'leri yeniden açıp içerik akışlarını, sayfa kutularını, dönüşü, çıkarılan metni ve görsel kaynaklarını inceledim; ardından görünür kırpma kutularını Poppler 26.02 ile 96dpi'da görüntüledim. Son dosya incelemesi 40 kontrolü geçti. Tarayıcı karşılaştırması da kaydedilen dosya karmalarını, yüklenen görüntüleri ve doğal çözünürlükte 12 piksel örneklemesini doğruladı.

Bu örnekteki kontrolGözlenen sonuç
Sayfa sayısı ve bilinen özgün metinÜç sayfa ve beklenen kaynak metin iki çıktıda da kaldı
Kaplama geometrisiHer sayfada iki dolgulu yol, incelenen 18 köşe ve 0,25 dolgu alfası
Eklenen görsel kaynaklarıBu özgün kaynak ve çıktı sayfalarında yok
Yerleşim ve sayfa kutularıTanımlı kırpma kutuları ve kaydedilen dönüşüm hesaplarıyla eşleşti; çıktı dönüşü sıfırdı
Çerçeve ve açık merkez örnekleriÜst kaplama çerçeve pikselleri beklenen karışımla ±2 RGB değeri içinde eşleşti; açık merkezler sayfa zeminini korudu
Opak zeminli alt katmanİlk sayfanın kaynak ve alt katman görüntüleri 96dpi'da sıfır piksel farklıydı

Yerleşim denetimi önce 0,00001pt toleransla ideal kayan noktalı koordinatların katı karşılaştırmasını geçemedi. ReportLab dönüşüm matrislerini sonlu hassasiyetle kaydeder. Başarısız sonucu korudum, beklenen kaydedilmiş matrisleri ve yuvarlama sınırını bağımsız hesapladım, kaydedilen köşeleri bu değerlerle karşılaştırdım. Gözlenen en büyük ideal koordinat farkı yaklaşık 0,000054pt idi; türetilen 0,000086pt sınırının içindeydi. Bu, bu dosyalarda görsel olarak ortalı yerleşimi kontrol eder; evrensel hassasiyet garantisi değildir.

Poppler kuruluysa hızlı yerel görsel kontrol için:

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

Her sayfayı yararlı yakınlaştırmada inceleyin. Beklenen özgün metni seçin veya çıkarın, sayfa ölçülerini kontrol edin ve filigranın yol olarak mı kaldığını, görsel mi eklediğini inceleyin. Keskin ekran görüntüsü tek başına bu dosya özelliklerini kanıtlayamaz. Bu test baskıyı, görüntüleyici uyumunu, dosya boyutu kazancını veya filigran kaldırmaya direnci ölçmedi.

Hatayı doğru aşamada düzeltin

BelirtiKontrol veya değişiklik
İşaret kayboluyorover=False ile over=True değerlerini karşılaştırın; opak özgün zemin arayın
Kırpılmış sayfada işaret yanlış yerdeSabit sayfa boyutu yerine kırpma kutusunun boyutunu ve başlangıcını kullanın
Döndürülmüş sayfalarda işaret beklenmedik yöndeGörünür ölçüleri hesaplamadan önce dönüşü normalleştirin; sonucu inceleyin
Opaklık veya stil değişiyorSVG'yi sadeleştirin, dönüştürülen PDF'nin boyama durumunu inceleyip tam o dosyayı yeniden test edin
Fotoğraf benzeri veya pikselli bölge kalıyorSVG'de gömülü görsel arayın; SVG sarmalayıcı bitmap'i yollara dönüştürmez
Metin, form veya belge davranışı değişiyorBaşarılı birleştirmenin her şeyi koruduğunu varsaymak yerine durup belgenin gerçek özelliklerini doğrulayın

Özgün PDF sayfa içeriği olarak kalır; betik tüm sayfaları rasterleştirmez. Bu, her girdi PDF'nin rastgele birleştirmeden değişmeden çıkacağını kanıtlamaz. Daha büyük toplu işlemden önce kopya kullanın ve çalışmaya devam etmesi gereken içerikle belge özelliklerini tanımlayın.

Eksik tasarımı birleştirmeden önce hazırlayın

Mevcut logo temiz SVG ise koruyun. Yalnızca uygun düz raster logo kaldıysa PerfectVector'ın logo vektörleştiricisi, bu Python adımından önce düzenlenebilir tasarım hazırlamaya yardımcı olabilir. Geri kazanılan silueti, delikleri ve küçük ayrıntıları inceleyip SVG dönüşümünü ve kaydedilen PDF kontrollerini yeniden çalıştırın. Buradaki örnek özgün yerel yollar kullandı ve PerfectVector dönüşümü yapmadı. Vektörleştirme sayfaları birleştirmez, imzaları doğrulamaz veya svglib uyumunu garanti etmez.

Sık sorulan sorular

pypdf SVG filigranı doğrudan okuyabilir mi? Bu örnek önce SVG'yi svglib ve ReportLab üzerinden PDF kaplamasına dönüştürür. pypdf sonra PDF sayfa içeriğini birleştirir; bu süreçte SVG kaynağını yorumlamaz.

Filigran PDF sayfamın arkasında neden kayboluyor? Alt katman mevcut opak zeminle örtülebilir. Görünür üst kaplama için over=True kullanın ve tasarım opaklığını ayrı ayarlayın. Gerçek sonucu her sayfada kontrol edin.

Vektör tasarımı ve özgün metni korur mu? Test edilen yalnızca yollu amblem dolgulu yollar olarak kaldı ve beklenen özgün metin üç sayfada da çıkarılabildi. Bu örnek dışındaki SVG ve PDF belge özellikleri ayrı doğrulama gerektirir.

PDF'yi yeniden yazmak dijital imzayı korur mu? Bu örneği imzalı belge iş akışı olarak kullanmayın. Dosyayı yeniden yazar ve imzanın korunmasını veya geçerliliğini test etmez. İmzalı özgün dosyayı koruyup imza gerekliliklerine uygun iş akışı kullanın.

Kaynaklar

  1. pypdf: Damga veya filigran ekleme — Üst ve alt katman sırası, birleştirme ve dönüş yönlendirmesi.
  2. pypdf: PageObject API — Sayfa kutuları, dönüş aktarımı ve dönüşümlü birleştirme davranışı.
  3. svglib proje belgeleri — SVG'den ReportLab'e dönüşüm, birimler ve desteklenen özellik sınırları.
  4. ReportLab grafik rehberi — ReportLab grafik sisteminde çizim nesneleri ve PDF görüntüleme.
  5. pypdf 6.10.0: PDF başlık sürümü — Çıktıda kullanılan özellikleri destekleyen PDF sürümünü belirtir.

Özgün tasarımınız varsa koruyun. Yalnızca uygun raster logo kaldıysa PerfectVector ile düzenlenebilir SVG hazırlayın, tasarımı inceleyin ve yeni birleştirilen PDF'yi ayrı doğrulayın.

Bloga daha fazlası

PerfectVector

Düzenlemesi daha kolay,
daha temiz bir SVG ile başlayın

Kredi kartı gerekmez