Files
office_translator/translators/watermark.py
sepehr ce8e150a61 feat: homelab deployment - NPM + IONOS DNS + monitoring + NAS backup
- Restructured docker-compose for Nginx Proxy Manager (no custom nginx)
- Added domain wordly.art configuration
- Added Prometheus + Grafana monitoring stack with pre-configured dashboards
- Added PostgreSQL backup script to NAS (daily/weekly/monthly rotation)
- Added alert rules for backend, system, and Docker metrics
- Updated deployment guide for NPM + IONOS DNS homelab setup
- Added marketing plan document
- PDF translator and watermark support
- Enhanced middleware, routes, and translator modules

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-10 11:43:28 +02:00

169 lines
5.2 KiB
Python

"""
Watermark module for Free-tier output files.
Strategy: Add a subtle, professional footer/header that:
- Clearly marks the file as "Free plan" output
- Doesn't destroy the document's usability
- Motivates upgrade without frustrating the user
DOCX: Footer with light-gray text + link
PPTX: Small text box bottom-right on each slide
XLSX: Footer text on each sheet
"""
from pathlib import Path
from typing import Optional
from docx import Document
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx.enum.text import WD_ALIGN_PARAGRAPH
from core.logging import get_logger
logger = get_logger(__name__)
WATERMARK_TEXT = "Translated with Office Translator — Free Plan"
WATERMARK_URL = "wordly.art"
WATERMARK_COLOR = "B0B0B0" # Light gray
def add_watermark_docx(output_path: Path) -> None:
"""Add a subtle footer watermark to a DOCX file."""
try:
document = Document(str(output_path))
for section in document.sections:
# Enable footer
footer = section.footer
footer.is_linked_to_previous = False
if not footer.paragraphs:
footer.add_paragraph()
para = footer.paragraphs[0]
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
# Clear existing content
for run in para.runs:
run.clear()
# Add watermark run
run = para.add_run(WATERMARK_TEXT)
run.font.size = 8 # Pt — small
run.font.color.rgb = None # Will set via XML
# Set color via XML (more reliable)
rPr = run._r.get_or_add_rPr()
color_elem = OxmlElement("w:color")
color_elem.set(qn("w:val"), WATERMARK_COLOR)
rPr.append(color_elem)
document.save(str(output_path))
logger.info("watermark_added", file=str(output_path))
except Exception as e:
logger.error("watermark_docx_error", error=str(e))
# Don't fail the whole translation if watermark fails
def add_watermark_pptx(output_path: Path) -> None:
"""Add a small watermark text box to each slide."""
try:
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN
prs = Presentation(str(output_path))
for slide in prs.slides:
# Add text box at bottom-right
left = Inches(5.5)
top = Inches(7.0)
width = Inches(3.5)
height = Inches(0.4)
txBox = slide.shapes.add_textbox(left, top, width, height)
tf = txBox.text_frame
tf.word_wrap = True
p = tf.paragraphs[0]
p.alignment = PP_ALIGN.RIGHT
run = p.add_run()
run.text = WATERMARK_TEXT
run.font.size = Pt(7)
run.font.color.rgb = RGBColor(0xB0, 0xB0, 0xB0)
prs.save(str(output_path))
logger.info("watermark_added_pptx", file=str(output_path))
except Exception as e:
logger.error("watermark_pptx_error", error=str(e))
def add_watermark_xlsx(output_path: Path) -> None:
"""Add a footer watermark to each sheet."""
try:
from openpyxl import load_workbook
from openpyxl.worksheet.header_footer import HeaderFooter
wb = load_workbook(str(output_path))
for ws in wb.worksheets:
if ws.sheet_properties.pageSetUpPr is None:
from openpyxl.worksheet.properties import PageSetupProperties
ws.sheet_properties.pageSetUpPr = PageSetupProperties()
ws.oddFooter.center.text = WATERMARK_TEXT
ws.oddFooter.center.font = "Arial,Regular"
ws.oddFooter.center.size = 8
wb.save(str(output_path))
wb.close()
logger.info("watermark_added_xlsx", file=str(output_path))
except Exception as e:
logger.error("watermark_xlsx_error", error=str(e))
def add_watermark_pdf(output_path: Path) -> None:
"""Add a subtle footer watermark on every page of a PDF using PyMuPDF."""
try:
import fitz
doc = fitz.open(str(output_path))
for page in doc:
rect = page.rect
# Position at bottom center
text_point = fitz.Point(
rect.width / 2 - 100,
rect.height - 15
)
page.insert_text(
text_point,
WATERMARK_TEXT,
fontsize=7,
color=(0.69, 0.69, 0.69), # #B0B0B0
fontname="helv",
)
doc.save(str(output_path), incremental=True, encryption=0)
doc.close()
logger.info("watermark_added_pdf", file=str(output_path))
except Exception as e:
logger.error("watermark_pdf_error", error=str(e))
def add_watermark(output_path: Path, file_extension: str) -> None:
"""Apply watermark based on file type."""
ext = file_extension.lower()
if ext == ".docx":
add_watermark_docx(output_path)
elif ext == ".pptx":
add_watermark_pptx(output_path)
elif ext == ".xlsx":
add_watermark_xlsx(output_path)
elif ext == ".pdf":
add_watermark_pdf(output_path)
else:
logger.info("watermark_skipped", extension=ext)