| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |
Tags
- 명상명언
- 소울칼리버6
- Gemini
- DART
- Skills
- kotlin
- Freesound
- Codex
- 명심보감
- Firebase
- Coroutine
- Android
- 코틀린
- Flutter
- 이모지메모
- 장자명언
- MCP
- 파이썬
- gemini-cli
- FSM
- 오픈소스
- 오늘의역사
- 명언모음
- 생성AI
- 명언
- ASMR
- javascript
- 좋은글필사하기
- Linux
- ChatGPT
Archives
- Today
- Total
Vintage appMaker의 Tech Blog
[codex] skill-creator를 이용한 pdf 워터마킹 본문
codex의 skill_creator 활용 - pdf 워터마크
프롬프트로 pdf의 워터마크를 구현한다.그리고 완성되었다고 판단하면 skill로 등록하라고 요청한다.
1. 프롬프트
프롬프트는 특정 pdf 파일을 폴더에 넣고 프롬프트를 @pdf 파일을 OO% 투명도로 워터마크 만들어줘. 작업한 파이썬 코드는 삭제하지 않는다. 라고하면 codex가 파이썬 코드를 만들어서 작성해준다. 그 코드를 활용해서 프롬프트를 지금 기능을 SKILLS로 pdf_watermark라는 이름으로 등록해줘. pdf 파일명, 투명도, 워터마크 문자열을 입력받고 워터마크 적용해줘 라고 하면 skill이 등록된다.
2. 생성된 SKILLS 정보
- SKILLS.md
---
name: pdf-watermark
description: Add a centered diagonal watermark to every page of a PDF and save a no-print output copy using a bundled Python script. Use when the user asks for PDF watermarking, says "PDF에 워터마크", mentions the skill name pdf_watermark or pdf-watermark, or wants watermark text and opacity applied to a PDF.
---
# PDF Watermark
## Workflow
1. Confirm the target PDF path exists.
2. Extract the watermark string and opacity from the user's request.
3. If either the watermark string or opacity is missing, reply exactly: `투명도와 문자열을 알려주세요. 그 다음 사용가능합니다.`
4. Run `scripts/add_watermark_no_print.py` with the PDF path, `--text`, and `--opacity`.
5. If the user also provides an angle, pass `--angle`; otherwise let the script use the page diagonal angle.
6. Leave the original PDF unchanged and verify the output PDF was created.
## Command
```powershell
python scripts/add_watermark_no_print.py "C:\path\file.pdf" --text "vintage appMaker" --opacity 0.2
```
Optional angle:
```powershell
python scripts/add_watermark_no_print.py "C:\path\file.pdf" --text "vintage appMaker" --opacity 0.2 --angle 29
```
## Notes
- The script writes `<input_stem>_watermarked_no_print.pdf` by default.
- The script applies PDF permission flags intended to disallow printing, but some viewers may ignore them.
- Keep filenames ASCII and stable.
- add_watermark_no_print.py
from __future__ import annotations
import argparse
import io
import math
from pathlib import Path
from PyPDF2 import PdfReader, PdfWriter
from PyPDF2.constants import UserAccessPermissions
from reportlab.lib.colors import Color
from reportlab.pdfgen import canvas
def build_watermark_page(
width: float,
height: float,
text: str,
opacity: float,
angle: float | None,
):
packet = io.BytesIO()
pdf = canvas.Canvas(packet, pagesize=(width, height))
pdf.saveState()
pdf.setFillColor(Color(0.35, 0.35, 0.35, alpha=opacity))
font_size = max(32, min(width, height) / 9)
pdf.setFont("Helvetica-Bold", font_size)
rotation = angle if angle is not None else math.degrees(math.atan2(height, width))
pdf.translate(width / 2, height / 2)
pdf.rotate(rotation)
pdf.drawCentredString(0, -font_size * 0.35, text)
pdf.restoreState()
pdf.showPage()
pdf.save()
packet.seek(0)
return PdfReader(packet).pages[0]
def apply_watermark(
input_pdf: Path,
output_pdf: Path,
text: str,
opacity: float,
angle: float | None,
):
reader = PdfReader(str(input_pdf))
writer = PdfWriter()
permissions = (
UserAccessPermissions.EXTRACT
| UserAccessPermissions.EXTRACT_TEXT_AND_GRAPHICS
| UserAccessPermissions.FILL_FORM_FIELDS
| UserAccessPermissions.ASSEMBLE_DOC
)
for page in reader.pages:
width = float(page.mediabox.width)
height = float(page.mediabox.height)
watermark = build_watermark_page(width, height, text, opacity, angle)
page.merge_page(watermark)
writer.add_page(page)
writer.encrypt(
user_password="",
owner_password="vintage_appMaker_owner",
permissions_flag=permissions,
)
with output_pdf.open("wb") as fh:
writer.write(fh)
def main():
parser = argparse.ArgumentParser(
description="Add a diagonal centered watermark to every PDF page and disable printing."
)
parser.add_argument("input_pdf", type=Path, help="Source PDF path")
parser.add_argument(
"--output",
type=Path,
default=None,
help="Output PDF path. Defaults to <input_stem>_watermarked_no_print.pdf",
)
parser.add_argument(
"--text",
default="vintage appMaker",
help="Watermark text",
)
parser.add_argument(
"--opacity",
type=float,
default=0.2,
help="Watermark opacity from 0.0 to 1.0",
)
parser.add_argument(
"--angle",
type=float,
default=None,
help="Watermark rotation angle in degrees. Defaults to the page diagonal angle.",
)
args = parser.parse_args()
input_pdf = args.input_pdf.resolve()
if not input_pdf.exists():
raise FileNotFoundError(f"Input PDF not found: {input_pdf}")
if not 0.0 <= args.opacity <= 1.0:
raise ValueError("Opacity must be between 0.0 and 1.0")
output_pdf = args.output or input_pdf.with_name(f"{input_pdf.stem}_watermarked_no_print.pdf")
apply_watermark(input_pdf, output_pdf.resolve(), args.text, args.opacity, args.angle)
print(output_pdf.resolve())
if __name__ == "__main__":
main()
4. 결과
PDF_E-book_Profit_Blueprint.pdf 파일에
"para-bom"이라는 문자열을 15% 투명율로 워터마킹한다.




'Source code or Tip > 생성AI' 카테고리의 다른 글
| [codex] playwright mcp 활용 - 카카오 맵으로 지역정보 (0) | 2026.04.03 |
|---|---|
| [codex] playwright mcp로 웹스크래핑 (0) | 2026.04.01 |
| [gemini] Opal로 음성 스마트 메모앱 만들기 (0) | 2026.03.24 |
| [claude] 클로드 웹, 음성메모 skills에 등록하기 (0) | 2026.03.22 |
| [claude] 클로드 웹버전에서 skill 등록하기 (0) | 2026.03.21 |
Comments
