视觉画布设计
canvas-design
基于设计原则创作静态视觉作品,用于海报与品牌图形。
stirling-pdf【文档与办公】Stirling PDF is a self-hosted web application with an HTTP API that merges, splits, compresses, converts, OCRs, watermarks and password-protects PDF files on your own server. Use when a user asks to deploy Stirling PDF with Docker, configure it with environment variables or settings.yml, call the Stirling PDF API from curl or Python, batch-process PD…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Stirling PDF packages more than 50 PDF tools behind a web UI and a REST API. It runs as one container, keeps documents on the host, and lets scripts call the same operations the UI offers. This skill covers deployment with Docker, configuration, and API calls from the shell and from Python.
Create compose.yaml in an empty directory such as /opt/stirling-pdf:
services:
stirling-pdf:
image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest
container_name: stirling-pdf
ports:
- "127.0.0.1:8080:8080" # remove 127.0.0.1 to serve the local network
volumes:
- ./stirling-data/configs:/configs # settings and database
- ./stirling-data/tessdata:/usr/share/tessdata # OCR language files
- ./stirling-data/logs:/logs
- ./stirling-data/pipeline:/pipeline # automation configs
environment:
SECURITY_ENABLELOGIN: "true"
SECURITY_INITIALLOGIN_USERNAME: admin
SECURITY_INITIALLOGIN_PASSWORD: ${STIRLING_ADMIN_PASSWORD}
SECURITY_CUSTOMGLOBALAPIKEY: ${STIRLING_API_KEY}
SYSTEM_DEFAULTLOCALE: en-GB
SYSTEM_FILEUPLOADLIMIT: 500MB
JAVA_TOOL_OPTIONS: "-Xms512m -Xmx4g"
restart: unless-stopped
cd /opt/stirling-pdf
read -rs STIRLING_ADMIN_PASSWORD && export STIRLING_ADMIN_PASSWORD # typed by the user; not echoed
export STIRLING_API_KEY="$(openssl rand -hex 32)" # store it in a password manager
docker compose up -d
curl -s http://localhost:8080/api/v1/info/status | jq -S .
The status call needs no key and returns {"status": "UP", "version": "3.0.1"}.
| Image tag | Contents |
|---|---|
latest | All PDF features; the default choice |
latest-fat | Same, plus extra fonts and conversion dependencies |
latest-ultra-lite | Core tools only: no OCR, compression, repair or Office conversion |
Update with docker compose pull && docker compose up -d. Data in the mounted folders survives the update.
Settings can be given in three places. Environment variables win over /configs/custom_settings.yml, which wins over /configs/settings.yml and the in-app settings. A YAML path becomes a variable name by writing it in upper case and replacing dots with underscores:
# ./stirling-data/configs/settings.yml
security:
enableLogin: true # same as SECURITY_ENABLELOGIN=true
system:
defaultLocale: en-GB # same as SYSTEM_DEFAULTLOCALE=en-GB
fileUploadLimit: "500MB" # same as SYSTEM_FILEUPLOADLIMIT=500MB
Restart the container after changing environment variables. For more OCR languages, download the .traineddata files from the Tesseract tessdata or tessdata_fast repository into ./stirling-data/tessdata and keep eng.traineddata in place.
Login is enabled by default. Every API call then needs the header X-API-KEY. Two kinds of key exist:
SECURITY_CUSTOMGLOBALAPIKEY, as in the Compose file above.Scripts read the key from $STIRLING_API_KEY. A missing key gives HTTP 401 with a JSON error; a wrong key gives 401 with the text Invalid API Key.
Every operation is a POST with multipart/form-data under /api/v1/ followed by a category and an operation name. The uploaded file is always the field fileInput. The response body is the resulting file.
| Operation | Path | Main fields |
|---|---|---|
| Merge | /api/v1/general/merge-pdfs | fileInput (repeat per file), sortType, generateToc |
| Split | /api/v1/general/split-pages | pageNumbers (split points such as 2,5); returns a ZIP |
| Rotate | /api/v1/general/rotate-pdf | angle: 90, 180 or 270 |
| Compress | /api/v1/misc/compress-pdf | optimizeLevel 1–9, or expectedOutputSize such as 2MB |
| OCR | /api/v1/misc/ocr-pdf | languages (repeat), ocrType, ocrRenderType, sidecar, deskew |
| PDF to images | /api/v1/convert/pdf/img | imageFormat, singleOrMultiple, colorType, dpi, pageNumbers |
| Office file to PDF | /api/v1/convert/file/pdf | fileInput |
| Password | /api/v1/security/add-password, /api/v1/security/remove-password | password, ownerPassword, keyLength |
| Watermark | /api/v1/security/add-watermark | watermarkType, watermarkText, fontSize, opacity, rotation |
BASE=http://localhost:8080
# OCR a scan in English and German; skip pages that already contain text
curl -sS -X POST "$BASE/api/v1/misc/ocr-pdf" -H "X-API-KEY: $STIRLING_API_KEY" \
-F "fileInput=@lease-2019-scan.pdf" -F "languages=eng" -F "languages=deu" \
-F "ocrType=skip-text" -F "ocrRenderType=hocr" \
-o lease-2019-searchable.pdf -w "%{http_code} %{size_download}\n"
# Render pages 1 to 3 as 150 dpi PNG files (ZIP archive)
curl -sS -X POST "$BASE/api/v1/convert/pdf/img" -H "X-API-KEY: $STIRLING_API_KEY" \
-F "fileInput=@floorplan.pdf" -F "imageFormat=png" -F "singleOrMultiple=multiple" \
-F "colorType=color" -F "dpi=150" -F "pageNumbers=1-3" -o floorplan-pages.zip
The full list of endpoints and fields is in the Swagger UI of the instance at /swagger-ui.html; the OpenAPI document is served at /v1/api-docs.
POST /api/v1/pipeline/handleData runs several operations in one request. It takes fileInput and a json field in which each step names the full endpoint path:
curl -sS -X POST "$BASE/api/v1/pipeline/handleData" -H "X-API-KEY: $STIRLING_API_KEY" \
-F "fileInput=@board-pack-october.pdf" \
-F 'json={"name":"repair-then-compress","pipeline":[
{"operation":"/api/v1/misc/repair","parameters":{}},
{"operation":"/api/v1/misc/compress-pdf","parameters":{"optimizeLevel":4}}]}' \
-o board-pack-october-small.pdf -w "%{http_code} %{size_download}\n"
One output file is returned directly; several are returned as output.zip. For long jobs add ?async=true to any operation. The response then contains a jobId; poll GET /api/v1/general/job/JOB_ID until complete is true and fetch the file from GET /api/v1/general/job/JOB_ID/result.
User request: "Combine the three September invoices into one PDF and put a password on it before I send it to the accountant."
BASE=http://localhost:8080
read -rs PDF_PASSWORD # typed by the user: the password for the accountant
curl -sS -X POST "$BASE/api/v1/general/merge-pdfs" -H "X-API-KEY: $STIRLING_API_KEY" \
-F "fileInput=@invoice-2026-0917.pdf" -F "fileInput=@invoice-2026-0922.pdf" \
-F "fileInput=@invoice-2026-0928.pdf" -F "sortType=orderProvided" \
-o invoices-2026-09.pdf -w "%{http_code} %{size_download}\n"
curl -sS -X POST "$BASE/api/v1/security/add-password" -H "X-API-KEY: $STIRLING_API_KEY" \
-F "fileInput=@invoices-2026-09.pdf" -F "password=$PDF_PASSWORD" -F "keyLength=256" \
-F "preventModify=true" -o invoices-2026-09-protected.pdf -w "%{http_code} %{size_download}\n"
Result:
200 412873
200 414106
invoices-2026-09-protected.pdf holds the three invoices in the given order and asks for the password when opened.
User request: "OCR every PDF in /srv/scans/inbox, shrink it, and put the result in /srv/scans/done."
import json, os, pathlib, requests
BASE = os.environ.get("STIRLING_URL", "http://localhost:8080")
HEADERS = {"X-API-KEY": os.environ["STIRLING_API_KEY"]}
PIPELINE = {
"name": "ocr-then-compress",
"pipeline": [
{"operation": "/api/v1/misc/ocr-pdf",
"parameters": {"languages": ["eng", "deu"], "ocrType": "skip-text", "ocrRenderType": "hocr"}},
{"operation": "/api/v1/misc/compress-pdf", "parameters": {"optimizeLevel": 4}},
],
}
src, dst = pathlib.Path("/srv/scans/inbox"), pathlib.Path("/srv/scans/done")
dst.mkdir(parents=True, exist_ok=True)
for pdf in sorted(src.glob("*.pdf")):
with pdf.open("rb") as fh:
resp = requests.post(
f"{BASE}/api/v1/pipeline/handleData", headers=HEADERS,
files={"fileInput": (pdf.name, fh, "application/pdf")},
data={"json": json.dumps(PIPELINE)}, timeout=900,
)
resp.raise_for_status()
if not resp.content:
raise SystemExit(f"{pdf.name}: empty response, see 'docker logs stirling-pdf'")
(dst / pdf.name).write_bytes(resp.content)
print(f"{pdf.name}: {pdf.stat().st_size // 1024} KB -> {len(resp.content) // 1024} KB")
Result:
delivery-note-0412.pdf: 3812 KB -> 946 KB
lease-2019-scan.pdf: 9240 KB -> 2105 KB
tax-office-letter.pdf: 1477 KB -> 388 KB
SECURITY_INITIALLOGIN_*, a fresh instance creates admin with the password stirling. Set SECURITY_ENABLELOGIN=false only on a machine nobody else can reach, because the API is then open to everyone who can connect.X-API-KEY is sent in clear text over HTTP. Keep the port bound to 127.0.0.1 or put a reverse proxy with TLS in front. Never write the key into scripts or the Compose file; read it from the environment.docker logs stirling-pdf./api/v1/misc/compress-pdf, not compress-pdf. Steps that need a second file, such as an image watermark, cannot be expressed in a pipeline; call that endpoint directly.ocrType and languages for OCR. Languages that are not installed are dropped, and the call fails when none is left.SYSTEM_FILEUPLOADLIMIT on shared servers and raise the Java heap for large files.qpdf is lighter than a Java service. Stirling PDF processes existing documents; to generate invoices or reports from data, use a PDF generation library.