Skip to content
Back to skills

4 Watermarking And Stamping

ASecurity

Sub-skill of pypdf: 4. Watermarking and Stamping.

  • 17 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 9, 2026
developmentpythongoaws

Security analysis

A100/100

Scanned September 9, 2026

npx -y skills add vamseeachanta/workspace-hub --skill 4-watermarking-and-stamping --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 4 Watermarking And Stamping?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 4 Watermarking And Stamping
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/vamseeachanta-4-watermarking-and-stamping/badge)](https://www.skillsdirectory.com/skills/vamseeachanta-4-watermarking-and-stamping)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: pypdf-4-watermarking-and-stamping
description: 'Sub-skill of pypdf: 4. Watermarking and Stamping.'
version: 1.0.0
category: data
type: reference
scripts_exempt: true
---

# 4. Watermarking and Stamping

## 4. Watermarking and Stamping


```python
"""
Add watermarks, stamps, and overlays to PDF pages.
"""
from pypdf import PdfReader, PdfWriter
from pathlib import Path
from typing import Optional, Tuple
from io import BytesIO

# For creating watermarks
try:
    from reportlab.pdfgen import canvas
    from reportlab.lib.pagesizes import letter
    from reportlab.lib.colors import Color
    REPORTLAB_AVAILABLE = True
except ImportError:
    REPORTLAB_AVAILABLE = False


def create_text_watermark(
    text: str,
    output_path: str,
    font_size: int = 60,
    opacity: float = 0.3,
    rotation: int = 45,
    color: Tuple[float, float, float] = (0.5, 0.5, 0.5)
) -> str:
    """Create a watermark PDF with specified text."""
    if not REPORTLAB_AVAILABLE:
        raise ImportError("reportlab is required for creating watermarks")

    packet = BytesIO()
    c = canvas.Canvas(packet, pagesize=letter)
    width, height = letter

    # Set transparency
    c.setFillColor(Color(*color, alpha=opacity))

    # Save state, rotate, draw text
    c.saveState()
    c.translate(width / 2, height / 2)
    c.rotate(rotation)
    c.setFont("Helvetica-Bold", font_size)

    # Draw text centered
    text_width = c.stringWidth(text, "Helvetica-Bold", font_size)
    c.drawString(-text_width / 2, 0, text)

    c.restoreState()
    c.save()

    # Write to file
    packet.seek(0)
    with open(output_path, 'wb') as f:
        f.write(packet.getvalue())

    return output_path


def add_watermark(
    input_path: str,
    watermark_path: str,
    output_path: str,
    pages: Optional[list] = None
) -> None:
    """Add watermark to PDF pages.

    Args:
        input_path: Source PDF file
        watermark_path: Watermark PDF file
        output_path: Destination file
        pages: List of page numbers to watermark (0-indexed), None for all
    """
    reader = PdfReader(input_path)
    watermark_reader = PdfReader(watermark_path)
    watermark_page = watermark_reader.pages[0]

    writer = PdfWriter()

    for i, page in enumerate(reader.pages):
        if pages is None or i in pages:
            page.merge_page(watermark_page)
        writer.add_page(page)

    writer.write(output_path)
    print(f"Watermarked PDF saved to: {output_path}")


def add_page_numbers(
    input_path: str,
    output_path: str,
    position: str = "bottom-center",
    start_number: int = 1,
    prefix: str = "Page ",
    font_size: int = 10
) -> None:
    """Add page numbers to PDF.

    Args:
        input_path: Source PDF file
        output_path: Destination file
        position: Position of page number (bottom-center, bottom-right, etc.)
        start_number: Starting page number
        prefix: Text before page number
        font_size: Font size for page numbers
    """
    if not REPORTLAB_AVAILABLE:
        raise ImportError("reportlab is required for adding page numbers")

    reader = PdfReader(input_path)
    writer = PdfWriter()

    for i, page in enumerate(reader.pages):
        # Get page dimensions
        width = float(page.mediabox.width)
        height = float(page.mediabox.height)

        # Create page number overlay
        packet = BytesIO()
        c = canvas.Canvas(packet, pagesize=(width, height))

        # Calculate position
        page_num_text = f"{prefix}{start_number + i}"

        if position == "bottom-center":
            x = width / 2
            y = 30
        elif position == "bottom-right":
            x = width - 50
            y = 30
        elif position == "top-center":
            x = width / 2
            y = height - 30
        elif position == "top-right":
            x = width - 50
            y = height - 30
        else:
            x = width / 2
            y = 30

        c.setFont("Helvetica", font_size)
        text_width = c.stringWidth(page_num_text, "Helvetica", font_size)

        if "center" in position:
            x -= text_width / 2

        c.drawString(x, y, page_num_text)
        c.save()

        # Merge with page
        packet.seek(0)
        overlay = PdfReader(packet)
        page.merge_page(overlay.pages[0])
        writer.add_page(page)

    writer.write(output_path)
    print(f"Page numbers added to: {output_path}")


def add_header_footer(
    input_path: str,
    output_path: str,
    header: Optional[str] = None,
    footer: Optional[str] = None,
    font_size: int = 10
) -> None:
    """Add header and/or footer to all pages."""
    if not REPORTLAB_AVAILABLE:
        raise ImportError("reportlab is required for adding headers/footers")

    reader = PdfReader(input_path)
    writer = PdfWriter()

    for page in reader.pages:
        width = float(page.mediabox.width)
        height = float(page.mediabox.height)

        # Create overlay
        packet = BytesIO()
        c = canvas.Canvas(packet, pagesize=(width, height))
        c.setFont("Helvetica", font_size)

        if header:
            text_width = c.stringWidth(header, "Helvetica", font_size)

*Content truncated — see parent skill for full reference.*

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.