317 lines
15 KiB
Markdown
317 lines
15 KiB
Markdown
# Image Tools
|
|
|
|
> **Design boundary**: keep provider credentials explicit, keep in-pipeline
|
|
> acquisition manifest-driven, and treat external image references as authoring
|
|
> inputs while delivery writes self-contained SVG previews and native PPTX
|
|
> media.
|
|
|
|
Image tools cover formula rendering, prompt-based AI generation, web image search, image inspection, and Gemini watermark removal.
|
|
|
|
## `latex_render.py`
|
|
|
|
Manifest-driven LaTeX formula renderer. Default Generate has Strategist write
|
|
`images/formula_manifest.json` after Typography confirmation; Quick Generate
|
|
has the current agent write the same resource manifest without confirmation.
|
|
This script renders only those declared formulas to transparent PNGs and writes
|
|
dimensions back into the manifest.
|
|
|
|
```bash
|
|
python3 scripts/latex_render.py <project_path>
|
|
python3 scripts/latex_render.py <project_path> --dry-run
|
|
python3 scripts/latex_render.py <project_path> --providers codecogs,quicklatex,mathpad,wikimedia
|
|
```
|
|
|
|
Manifest shape:
|
|
|
|
```json
|
|
{
|
|
"providers": ["codecogs", "quicklatex", "mathpad", "wikimedia"],
|
|
"items": [
|
|
{
|
|
"id": "formula_001",
|
|
"latex": "E = mc^2",
|
|
"display": "block",
|
|
"color": "#1D1D1F",
|
|
"background": "#FFFFFF",
|
|
"transparent": true,
|
|
"dpi": 300,
|
|
"filename": "formula_001.png"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Output files land directly under `project/images/`. Formula filenames should use a shared `formula_` prefix, e.g. `formula_001.png`. The default provider chain is `codecogs,quicklatex,mathpad,wikimedia`; each provider is tried automatically until one succeeds, and the winning provider is recorded back into the manifest. `--providers` or manifest-level `providers` may override the order, but all four are available as no-key fallbacks. Formula PNGs are transparent by default. `background` is the temporary render matte and local background-removal reference; set `transparent: false` only when an opaque final formula asset is intentional. The script does not scan `spec_lock.md` or source documents for `$...$`; formula selection belongs to the active resource owner.
|
|
|
|
## `image_gen.py`
|
|
|
|
Unified image generation entry point.
|
|
|
|
This script is the **Path A** API/proxy executor for generated images. Default
|
|
Generate checks `design_spec.md §I / AI Image Acquisition Path` before manifest
|
|
mode: only `api` / `auto` permits Path A; a missing or unknown value fails
|
|
closed and returns to Step 4 recovery. Quick Generate has no Design Spec: use
|
|
the explicit active-context path when supplied, otherwise `auto` selects the
|
|
A → B → C chain defined in
|
|
[`image-generator.md`](../../references/image-generator.md) §7 without asking.
|
|
In either profile, `host-native` uses the host image tool directly and `manual`
|
|
uses the read-only Markdown sidecar.
|
|
|
|
```bash
|
|
python3 scripts/image_gen.py "A modern futuristic workspace"
|
|
python3 scripts/image_gen.py "Abstract tech background" --aspect_ratio 16:9 --image_size 4K
|
|
python3 scripts/image_gen.py "Concept car" -o projects/demo/images
|
|
python3 scripts/image_gen.py --list-backends
|
|
```
|
|
|
|
Backends are grouped into Core / Extended / Experimental tiers. Run `python3 scripts/image_gen.py --list-backends` for the current list.
|
|
|
|
Backend selection:
|
|
|
|
```bash
|
|
python3 scripts/image_gen.py "A cat" --backend openai
|
|
python3 scripts/image_gen.py "A cinematic portrait" --backend minimax
|
|
python3 scripts/image_gen.py "A product launch hero image" --backend qwen
|
|
python3 scripts/image_gen.py "科技感背景图" --backend zhipu
|
|
python3 scripts/image_gen.py "A product KV in cinematic style" --backend volcengine
|
|
```
|
|
|
|
Configuration sources:
|
|
|
|
1. Current process environment variables
|
|
2. First `.env` found in this order:
|
|
- Current working directory
|
|
- Skill directory (e.g. `~/.agents/skills/ppt-master/.env`)
|
|
- Clone repo root
|
|
- `~/.ppt-master/.env`
|
|
|
|
The active backend must always be selected explicitly via `IMAGE_BACKEND`.
|
|
|
|
Example `.env`:
|
|
|
|
```env
|
|
IMAGE_BACKEND=openai
|
|
OPENAI_API_KEY=sk-xxx
|
|
OPENAI_MODEL=gpt-image-2
|
|
# Optional proxy
|
|
# OPENAI_BASE_URL=http://127.0.0.1:3000/v1
|
|
# OpenAI-compatible provider knobs:
|
|
# OPENAI_SIZE_PRESET=auto
|
|
# OPENAI_RESPONSE_FORMAT=auto
|
|
# OPENAI_QUALITY=auto
|
|
# Allowed values: png / jpeg / webp
|
|
# OPENAI_OUTPUT_FORMAT=png
|
|
# jpeg/webp only, 0-100
|
|
# OPENAI_OUTPUT_COMPRESSION=80
|
|
# gpt-image-2: auto / opaque
|
|
# OPENAI_BACKGROUND=auto
|
|
# auto / low
|
|
# OPENAI_MODERATION=auto
|
|
```
|
|
|
|
Example process environment:
|
|
|
|
```bash
|
|
export IMAGE_BACKEND=openai
|
|
export OPENAI_API_KEY=sk-xxx
|
|
export OPENAI_MODEL=gpt-image-2
|
|
export OPENAI_OUTPUT_FORMAT=png
|
|
```
|
|
|
|
Current process environment wins over `.env`.
|
|
|
|
OpenAI backend notes:
|
|
- `gpt-image-2` is the default OpenAI model.
|
|
- Requests are sent with plain `requests.post()` to improve compatibility with
|
|
OpenAI-compatible proxies that block the OpenAI SDK's `httpx` transport.
|
|
- For `gpt-image-2`, `image_size=512px` means a low-quality draft preset, not a literal 512px edge. The model requires both edges to be multiples of 16px, a long:short ratio no greater than 3:1, and total pixels between 655,360 and 8,294,400.
|
|
- `OPENAI_BACKGROUND=transparent` is not supported by `gpt-image-2`; use `auto` or `opaque`.
|
|
- If `OPENAI_OUTPUT_FORMAT=jpeg` or `webp`, generated files use `.jpg` or `.webp` extensions instead of `.png`.
|
|
- OpenAI-compatible providers that reject OpenAI-specific fields can use `OPENAI_RESPONSE_FORMAT=omit`, `OPENAI_QUALITY=omit`, and `OPENAI_SIZE_PRESET=<preset>`. Valid response formats are `auto`, `b64_json`, `url`, and `omit`; valid size presets are `auto`, `legacy`, `gpt-image`, `gpt-image-2`, and `dall-e-2`.
|
|
|
|
Example `.env` for Agnes AI through the OpenAI-compatible backend:
|
|
|
|
```env
|
|
IMAGE_BACKEND=openai
|
|
OPENAI_API_KEY=your-agnes-key
|
|
OPENAI_MODEL=agnes-image-2.1-flash
|
|
OPENAI_BASE_URL=https://apihub.agnes-ai.com/v1
|
|
OPENAI_SIZE_PRESET=gpt-image-2
|
|
OPENAI_RESPONSE_FORMAT=omit
|
|
OPENAI_QUALITY=omit
|
|
```
|
|
|
|
Use provider-specific keys only (e.g. `GEMINI_API_KEY`, `OPENAI_API_KEY`). See `.env.example` in clone mode or `${SKILL_DIR}/.env.example` in skill-install mode for the full list per backend.
|
|
|
|
`IMAGE_API_KEY`, `IMAGE_MODEL`, and `IMAGE_BASE_URL` are intentionally unsupported.
|
|
|
|
If you keep multiple providers in one `.env` or environment, `IMAGE_BACKEND` must explicitly select the active provider.
|
|
|
|
Recommendation:
|
|
- Default to the Core tier for routine PPT work
|
|
- Use Extended only when you need a specific model style
|
|
- Treat Experimental backends as opt-in
|
|
|
|
Example `.env` for MiniMax image backend:
|
|
|
|
```env
|
|
IMAGE_BACKEND=minimax
|
|
MINIMAX_API_KEY=your-api-key
|
|
# Optional: override base URL (defaults to https://api.minimaxi.com, domestic China endpoint)
|
|
# Use https://api.minimax.io for overseas access
|
|
# MINIMAX_BASE_URL=https://api.minimax.io
|
|
# MINIMAX_MODEL=image-01
|
|
```
|
|
|
|
## `image_treat.py`
|
|
|
|
Create a non-destructive PNG derivative from one bitmap already prepared under
|
|
`<project_path>/images/`. Use this only when a slide needs a baked bitmap effect;
|
|
crop, mask, rotation, mirror, opacity, shadow, scrim, outline, and overlap remain
|
|
native SVG/PPT treatments. This tool does not perform semantic background
|
|
removal: use `slice_images.py --alpha` for flat-color keys, an already prepared
|
|
RGBA asset or the active host image editor for a standalone cutout, and
|
|
[`image-generator.md`](../../references/image-generator.md) §4.4 only for
|
|
registered subject/base layers.
|
|
|
|
```bash
|
|
python3 scripts/image_treat.py projects/demo hero.jpg \
|
|
--output hero_soft.png --brightness 0.9 --contrast 1.1 --blur 12
|
|
|
|
python3 scripts/image_treat.py projects/demo hero.jpg \
|
|
--output hero_duotone.png --duotone "#14213D" "#FCA311"
|
|
```
|
|
|
|
Supported operations are brightness, contrast, desaturation/grayscale,
|
|
duotone, and Gaussian blur. They compose in a fixed order: brightness →
|
|
contrast → tone treatment → blur. Desaturation, grayscale, and duotone are
|
|
mutually exclusive. At least one option must produce a real change; animated
|
|
or multi-frame sources are rejected rather than reduced to one frame.
|
|
|
|
Both input and output are bare filenames directly under `images/`; output must
|
|
be a new `.png` file. The tool keeps the EXIF-corrected display dimensions,
|
|
leaves any alpha mask unchanged, and never overwrites the source or an existing
|
|
derivative. If `images/image_sources.json` contains the source filename, the
|
|
new record inherits that legal provenance and records `derived_from` plus the
|
|
ordered `treatments`. Run `analyze_images.py` after all planned derivatives are
|
|
ready so the inventory reflects the files that SVG authoring will consume.
|
|
|
|
## `analyze_images.py`
|
|
|
|
Analyze objective image-file facts in a project directory before writing the
|
|
design spec or authoring SVG.
|
|
|
|
```bash
|
|
python3 scripts/analyze_images.py <project_path>/images
|
|
```
|
|
|
|
The tool does not resolve a canvas or recommend a left/right, top/bottom, or
|
|
other slide layout. Its atomic CSV records EXIF-corrected native dimensions and
|
|
`AspectRatio`, the objective aspect-ratio category, optional source
|
|
`SourceDisplayRatio`, format, actual transparent-pixel presence, usage count,
|
|
and bitmap/vector capability facts. An empty folder rewrites a header-only
|
|
report; unreadable supported files still refresh the report and produce a
|
|
non-zero exit.
|
|
|
|
Use this as the default factual inventory; it does not perform semantic image
|
|
understanding or choose composition. Generate planning follows the Strategist's
|
|
context-first boundary: source context, captions / alt text / titles, filenames,
|
|
user notes, and existing resource records come first. Only an already-selected
|
|
provided/web asset whose focal-safe crop, overlay contrast, or quiet region
|
|
remains materially ambiguous may be inspected for that placement; this never
|
|
reopens selection or provenance, never bulk-opens the image folder, and never
|
|
restores routine readback of AI-generated images.
|
|
|
|
## `image_search.py`
|
|
|
|
Zero-config web image search across openly-licensed providers. Sister tool to `image_gen.py` — used when the resource list row has `Acquire Via: web`.
|
|
|
|
```bash
|
|
python3 scripts/image_search.py "offshore wind farm" \
|
|
--filename cover_bg.jpg --slide 01_cover \
|
|
--orientation landscape -o projects/demo/images
|
|
```
|
|
|
|
For multiple web rows, `--batch images/image_queries.json` searches them concurrently (modest default, `--concurrency N` / `IMAGE_SEARCH_CONCURRENCY` to tune) instead of one call per row — the web sister of `image_gen.py --manifest`. Schema and status semantics: [`image-searcher.md`](../../references/image-searcher.md) §5.
|
|
|
|
Providers (Pexels / Pixabay are tried first when keyed; Openverse and Wikimedia are zero-config fallbacks):
|
|
|
|
| Provider | Config | Strength |
|
|
|---|---|---|
|
|
| `pexels` | recommended: `PEXELS_API_KEY` | modern stock photography, people, workplace, lifestyle |
|
|
| `pixabay` | recommended: `PIXABAY_API_KEY` | broad type coverage including photos and illustrations |
|
|
| `openverse` | zero-config | fallback aggregator: Wikimedia + Flickr + museums + rawpixel |
|
|
| `wikimedia` | zero-config | educational, scientific, geographic, historical |
|
|
|
|
Default search chain (when `--provider` is unset): configured Pexels, configured Pixabay, Openverse, then Wikimedia. Missing keyed credentials are silently skipped. Keyed providers broaden stock-photo coverage but are optional; zero-config providers remain valid.
|
|
|
|
`image_search.py` uses the same `.env` lookup order as `image_gen.py`, so skill installs can keep `PEXELS_API_KEY` / `PIXABAY_API_KEY` in `~/.ppt-master/.env`.
|
|
|
|
Query guidance:
|
|
|
|
Keep the Design Spec §VIII `Reference` as the full visual/crop intent; write a separate concise provider query for this CLI. Start with the shortest phrase that preserves identity, but retain exact multi-word names and necessary disambiguators beyond four words.
|
|
|
|
| Case | Pattern |
|
|
|---|---|
|
|
| Generic stock concept | `boardroom meeting` |
|
|
| China-specific landmark | Precise official place/identity name plus necessary geography |
|
|
| Avoid | Negative prompt wording such as `not tourist snapshot` |
|
|
|
|
License filter:
|
|
|
|
- **Default**: search all providers with `cc0,pdm,pexels,pixabay,cc by,cc by-sa` allowed together. The chosen image may be `no-attribution` or `attribution-required`; Executor adds an inline credit only when needed.
|
|
- `--strict-no-attribution` restricts the search to `cc0,pdm,pexels,pixabay` — useful for full-bleed hero images or templates that cannot host a credit element.
|
|
|
|
Pin a provider, refuse attribution, or override the manifest path:
|
|
|
|
```bash
|
|
# Pin Wikimedia
|
|
python3 scripts/image_search.py "Olympics opening ceremony" \
|
|
--filename event.jpg --provider wikimedia \
|
|
--orientation landscape -o projects/demo/images
|
|
|
|
# Strict mode — refuse CC BY / CC BY-SA
|
|
python3 scripts/image_search.py "abstract gradient" \
|
|
--filename hero.jpg --strict-no-attribution \
|
|
-o projects/demo/images
|
|
```
|
|
|
|
Suitability & manual replacement (a web top hit is metadata-relevant, not guaranteed visually right):
|
|
|
|
- By default only the best match is downloaded, plus a downscaled review copy at `images/.review/<stem>.jpg` (the placed asset stays full-resolution).
|
|
- For exact subjects (landmarks, people, companies, products), use `--require-terms` or batch `required_terms` so visually plausible but wrong metadata is rejected before ranking. Example: `--require-terms Chongqing --require-terms "Jiefangbei|Liberation Monument"`. Keep proper-name / geography anchors; do not broaden to generic terms like `canyon`, `stone pillar`, or `ancient town` just to improve coverage.
|
|
- `--save-candidates` (with `--max-candidates`, default 4) keeps an opt-in escalation pool under `candidates/<stem>/`; review it, then `--promote candidate_03.jpg --filename <name>.jpg`.
|
|
- `--from-url <url> --filename <name>.jpg` downloads a user-chosen image URL and replaces the target (recorded `license_tier: manual`) — the model-agnostic manual path; works even without a multimodal model.
|
|
|
|
Full review / escalation flow: [`image-searcher.md`](../../references/image-searcher.md) §5.
|
|
|
|
Output:
|
|
|
|
- Image saved to the specified output directory (auto-converts webp → jpg via Pillow when the filename extension demands)
|
|
- `image_sources.json` manifest with full provenance (provider, license, license_tier, author, source URL, dimensions, attribution_text)
|
|
- Manifest is idempotent on `filename` and written atomically; damaged existing provenance blocks replacement
|
|
|
|
Allowed licenses (default): CC0, Public Domain, Pexels License, Pixabay Content License, CC BY, CC BY-SA. Auto-rejected: CC BY-NC, CC BY-ND, CC BY-NC-SA, CC BY-NC-ND, all rights reserved, unknown.
|
|
|
|
The full role-level reference (intent → query translation, on-slide attribution contract) is in [`references/image-searcher.md`](../../references/image-searcher.md).
|
|
|
|
## `gemini_watermark_remover.py`
|
|
|
|
Remove Gemini watermark assets after manual download.
|
|
|
|
```bash
|
|
python3 scripts/gemini_watermark_remover.py <image_path>
|
|
python3 scripts/gemini_watermark_remover.py <image_path> -o output_path.png
|
|
python3 scripts/gemini_watermark_remover.py <image_path> -q
|
|
```
|
|
|
|
Notes:
|
|
- Requires `scripts/assets/bg_48.png` and `scripts/assets/bg_96.png`
|
|
- Best used after downloading “full size” Gemini images
|
|
|
|
Dependencies:
|
|
|
|
```bash
|
|
pip install Pillow numpy
|
|
```
|