*Epic CLI Manual — [index](../MANUAL.md)*

# 8. `--vectorize` / `--rvp`

```
java -jar java-epic-cli.jar --vectorize --input=logo.png --output=logo.pdf [options]
```

Epic RVP (Raster-to-Vector Processor). Converts a raster image (PNG, JPEG, TIFF, BMP, GIF —
anything ImageIO reads) into a vector PDF 1.5 in which every shape is a flat spot color:
source colors are normalized into a small set of core inks, antialiasing is collapsed into
them, and the resulting regions are traced to outlines. No raster data is carried into the
output. **A PDF input** instead has its stencil plates lifted and re-traced (plate-lifting
rewrite of already-separated stencil PDFs).

`--rvp` is an alias. This mode has its own help (`--vectorize --help`, plus topics `colour`,
`antialiasing`, `outlines`, `examples`).

## How the pipeline thinks (summary of the topic pages)

- **All color decisions happen in CIE L\*a\*b\***, not RGB — one `--delta-e` threshold behaves
  consistently across the gamut.
- **Discovery** seeds inks from the most populous colors down, requiring each new ink to sit
  ≥ `--delta-e` from every accepted one. Discovered inks are named `SPOT1`, `SPOT2`, … in
  descending coverage order. Their CMYK values are converted from screen color — treat them
  as placeholders: run once with `--report`, replace with the job's real inks, re-run with
  `--colors`.
- **Antialiasing** is defeated in three stages: blend pruning at palette selection (a
  candidate color lying near the line between two accepted inks is rejected as their blend),
  per-pixel snapping (against paper the decision uses **recovered coverage**, which is what
  keeps half-covered hairlines alive — `--ink-threshold`), and spatial cleanup (`--smooth`
  majority filter + `--min-area` speckle absorption).
- **Coverage tracing** (`--trace=coverage`, the default) interpolates the true edge from the
  antialiasing fringe, giving subpixel outlines with no staircase; `--trace=binary` walks
  pixel boundaries and exists for sources with no usable fringe (already-posterized art,
  pre-thresholded masks). Coverage tracing never changes topology.
- **Corners** are detected by turn angle, pinned before simplification, and sharpened back to
  the intersection of the adjacent straight runs (capped, so curves don't spike).

## Options

**Geometry**

| Flag | Default | Meaning |
|---|---|---|
| `--dpi=N` | 300 | Resolution of the **source** — an assertion about the input used to size the page, *not* a resampling request. |
| `--simplify=PX` | 0.75 | Douglas-Peucker tolerance in source pixels. 0 keeps every vertex. Corners are pinned regardless. |
| `--trace=coverage\|binary` | coverage | Outline placement (see above). |
| `--corner-angle=DEG` | 35 | Turn at which a vertex counts as a corner and is protected. |
| `--no-sharpen-corners` | off | Leave corners where coverage put them. |

**Color**

| Flag | Default | Meaning |
|---|---|---|
| `--colors=SPEC` | discover | Snap to an explicit palette. SPEC: `Name:C,M,Y,K[@RRGGBB]` entries joined with `;` — CMYK 0–100, the optional `@RRGGBB` anchor is the *screen* color pixels are matched against (it changes which pixels match, never the ink written). |
| `--max-colors=N` | 8 | Ceiling on discovered inks. **Set it to the job's known ink count — the single most effective artifact-killer.** Within budget, close shades are kept apart and only true duplicates (ΔE < 4) merge. |
| `--delta-e=F` | 12 | Minimum Lab separation between distinct inks while over budget. |
| `--min-color-share=F` | 0.005 | Minimum fraction of the image a color must cover to count. |
| `--no-blend-prune` | off | Keep colors that look like blends of two stronger inks (use when a real ink sits chromatically between two others). |
| `--paper=auto\|none` | **none** | `auto` leaves the lightest near-neutral unprinted (plain white backgrounds). The default prints every ink — near-white can be a real plate (garment underbase), and deleting a real plate costs more than an extra white separation. Alpha transparency is always unprinted, no flag needed. |
| `--ink-threshold=F` | 0.45 | Recovered-coverage level at which a part-covered pixel becomes ink vs paper — what keeps hairlines alive. Above 1 disables. |

**Cleanup**

| Flag | Default | Meaning |
|---|---|---|
| `--smooth=N` | 1 | Majority-filter passes over the ink map (0 disables — do that for hairline-built art and rely on `--min-area`). |
| `--smooth-weight=N` | 4 | Weight of a pixel's own ink during smoothing; raise to protect thin features. |
| `--min-area=F` | 0.5 | Drop regions below this area (square points) into their dominant neighbour. |
| `--despeckle-passes=N` | 3 | Cap on absorption passes. |
| `--no-weld` | off | Disable seam welding. By default butting inks are welded into **kissing fit** — trapping is the printer's job, so seams are delivered true; keylines are preserved. |
| `--fit=curves\|lines` | lines | Refit smooth outline runs against paper as cubic Béziers; corners and welded seams kept exactly. Off = output identical to pre-curve releases. |
| `--fit-tolerance=F` | 0.2 | Max distance (pt) a fitted curve may sit from any traced vertex — the trace's own noise floor. A run that can't fit stays a polyline. |
| `--simplify-curves[=PT]` | off | Illustrator-style simplification of the fitted outlines before writing (see [§10](10-simplify-curves.md) for the algorithm). Implies `--fit=curves`. Report `d` strings gain cubic `C` commands. |
| `--simplify-tolerance=PT` | 0.35 | Max drift of the simplified outline, in points, size-independent — matches Illustrator's Object > Path > Simplify envelope. |
| `--simplify-corner-angle=D` | 5 | Tangent turn past which an anchor is a corner and must survive. |

**Output**

| Flag | Default | Meaning |
|---|---|---|
| `--overprint` | off | Mark fills as overprinting so adjacent inks combine on press instead of knocking out. |
| `--no-ai-private` | AI data **on** | Skip the native Illustrator private data (AIPDFPrivateData) the output carries by default. With the default on, Illustrator opens the PDF as a **native AI document** — real spot swatches, one editable compound path per ink (even-odd, cubics preserved) — instead of a foreign-PDF import. The page ink is byte-identical either way; the data only affects what Illustrator does on open. |
| `--object-gap=IN` | color-only | Grouping distance (inches, between drawn shapes, not bounding boxes) for the report's `objects[]`. Default: one object per ink. Passing a distance opts into geometric division within each color. |
| `--upscale=N` | auto | Upscale 2–6× before tracing (bicubic **on the coverage**, so antialiasing — not the pixel staircase — defines the edge; curve fitting defaults on for the run). Automatic for low-res sources: with `--dpi` asserted, anything under 300 upscales to ≥300; without it, sources under 1000 px on the longest side upscale toward 1000 px. Pinned off by `--dpi≥300`, `--upscale=1`, or `--no-upscale`. Geometry in inches never changes. |
| `--report=PATH` | — | Write the JSON report (inks + geometry). |
| `--verbose` | off | Stage-by-stage progress on stderr. |

## The report's `objects[]` contract

Entries carry per-ink absolute SVG path data — **inches, y-down, nonzero fill, `M`/`L`/`Z`
commands forever by default**; cubic `C` commands appear only when `--fit=curves` /
`--simplify-curves` are opted into. Downstream editors (the heatapplied Designer) parse these
strings directly.
