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

# 9. `--extract-objects`

```
java -jar java-epic-cli.jar --extract-objects design.pdf --report=out.json [options]
java -jar java-epic-cli.jar --extract-objects --input=design.pdf --with-text
```

Lifts a **vector PDF's own filled paths** and splits them into editable objects — exact
source geometry, never rasterized, never traced. Emits the same JSON envelope as a traced
`--vectorize` run (page, spots, `objects[]` with path data); report-only unless `--output` is
also given. Shares the vectorize option surface (`--object-gap`, `--simplify-curves`, …).
An `--output` PDF carries native Illustrator private data mirroring its paths by default,
same as `--vectorize` output (see [§8](08-vectorize-rvp.md), `--no-ai-private`) — note this
is **freshly authored from the lifted geometry**; any AI data the *source* carried (e.g. live
text stories) is not copied through, because the output's ink is outlines only.

- Strokes are outlined into fills.
- Raster images, gradients, and live text **refuse** with `not liftable: ...` on stderr —
  extraction promises exactness, so anything it can't lift exactly is an error, not a guess.
- `--with-text` relaxes the live-text refusal: text is tolerated and reported as a `texts[]`
  array of runs (content, font, size, baseline anchor, fill, honesty flags) — reported,
  **never outlined into `objects[]`**. Without the flag, output is unchanged.
- With `--with-text`, a source that carries **Illustrator private data** (a real AI save, or
  an `ai_private` compile) additionally yields a `stories[]` array — the AI-truth text layer
  parsed from the ATE text engine data: per story `index`, `text`, `font`
  (family/style/ps_name), `size_pt`, `tracking` (thousandths of an em), `fill` (spot name +
  CMYK 0–100), `frame` (area-frame box, inches, top-left y-down; pre-warp for warped
  stories), `align`, `valign_center`, `fixed_size`, optional `xml_uid` (bound variable/layer
  name), and for warped stories `warp` `{style, bend, h_distortion, v_distortion, bbox_in}`
  (percent values; `bbox_in` = post-warp envelope box). Word gaps in `texts[]`
  content are judged net of character spacing (`Tc`), so a tracked run stays one word with
  its tracking reported in `char_spacing_pt` rather than splitting into letters. Since page
  ink is outlined,
  `objects[]` entries additionally carry a nullable `story_index` tagging the objects that
  are a story's letters — set **only when attribution is unambiguous** (object fully inside
  the story box, no straddlers); otherwise no object is tagged and the story is flagged
  `objects_unresolved`. When strict containment fails, a second tier retries by per-object
  overlap fraction with a wide honesty band (≥ 80 % of an object's own area inside the story
  box → the story's; ≤ 15 % → foreign; anything between → `objects_unresolved`), because a
  native Illustrator resave can carry a *stale* warp-envelope mesh — Illustrator only
  regenerates the stored mesh on warp edits, not artboard moves/rescales, so real outlined
  ink can poke past the analytic `bbox_in`. Stories tagged by the second tier are flagged
  `tagged_by_overlap` so consumers can gate on confidence (strict-tier stories carry no
  flag). Two more guards keep native-save tagging honest: a stale envelope that dwarfs the
  story's own frame (> 4× area — e.g. a 10×10 in mesh for a 1.2 in arc line) is distrusted
  and the story tags against its frame box instead, flagged `degenerate_envelope`; and
  objects already resolved to an earlier story never count for or against a later one, so
  one story's letters can't make a sibling ambiguous. A story whose ink is a live text run
  inside its box (a live-text source keeps real page text, so nothing outlined exists to
  tag) resolves clean with zero tagged objects instead of flagging `objects_unresolved`.
  A present tag means the object is safe to substitute away. Use
  `--object-gap` to split objects finely enough for tagging; the default one-object-per-ink
  grouping usually straddles. `stories[]` is absent for files without usable AI data.

Reminder: this is the mode broken by JDK 21 ([§2](02-invocation-fundamentals.md), [§15](15-troubleshooting-and-landmines.md)).
