Commit Graph
21 Commits
Author SHA1 Message Date
vangel76 28206a3c1d Merge remote-tracking branch 'origin/aep-audit-3300' into aep-import-bounds-3299 2026-11-09 19:22:00 +01:00
vangel76 04dcececf2 Merge remote-tracking branch 'upstream/main' into aep-audit-3300
# Conflicts:
#	crates/aep/tests/it/export/built.rs
2026-11-09 19:17:42 +01:00
Valentin Klein 7c62272305 .aep import: placed .ai/PDF footage framed by its ArtBox, Null anchors at the corner (#3099) (#3311)
* #3099: placed .ai pages fill the size After Effects stored; null anchors default to the corner

Footage of an .aep keeps the size After Effects stored for a placed PDF / Illustrator / EPS
file (the ArtBox, rounded up), and masks and anchors are measured against it. The page was
drawn as a PDF viewer frames it (CropBox, /Rotate) at its own size, scaled by the width ratio
at full resolution and stretched to the stored aspect below 3/4: masks too large, art off
centre, squeezed at half resolution.

- effectcraft-pdf: Framing::Placed / parse_page_framed (ArtBox clipped to the CropBox,
  /Rotate ignored); boxes with a non-finite corner or span are not used
- Footage::placed_page (set by the .aep importer, serialized only when true): the page is
  framed so and filled into the stored size (effectcraft_render::vector_fit), decoded,
  continuously rasterised and in Create Shapes from Vector Layer; Reload keeps the size;
  the frame cache keys it by size and framing
- .aep import/export: a null's absent Anchor Point is [0, 0], as After Effects reads it
- fixture ai-mask-3099.aep (own synthetic files, scrubbed, profiles stubbed) and tests
  against After Effects 2026's read-back

* #3099: placed-page framing only for .ai and .pdf, EPS as before; doc comments

After Effects' sizing was measured with PDFs named .ai only; an EPS from an .aep keeps its
bounding box at its own size (listed as not measured in docs/gaps.md and docs/aep-import.md).
Doc comments on the touched functions.

* #3099: shapes from a placed page keep its frame (track matte)

Create Shapes from Vector Layer converted every path of a placed page, so bleed, art past the
artboard or the page's background showed where the footage's raster hides them. The layers it
makes from a placed page now take a hidden "<layer> Frame" shape layer (the footage's
width x height) as their Alpha track matte: drawn at the comp's resolution, its edge is the
raster's on shape and image layers alike. The command returns the frame layer's id too.
2026-11-08 21:52:32 -06:00
vangel76 3a9cb48259 Merge remote-tracking branch 'upstream/main' into aep-audit-3300 2026-11-08 18:29:49 +01:00
vangel76 2c6fe5f108 Merge remote-tracking branch 'origin/aep-audit-3300' into aep-import-bounds-3299
# Conflicts:
#	crates/aep/src/export/emit.rs
2026-11-08 17:21:44 +01:00
vangel76 5f2d88ea5c Merge remote-tracking branch 'upstream/main' into aep-import-lumetri
# Conflicts:
#	crates/aep/src/container/effect_map.rs
#	crates/aep/src/export/effects.rs
#	crates/aep/src/import/effects.rs
#	crates/aep/tests/it/export/effects.rs
#	crates/aep/tests/it/import/effects.rs
#	docs/aep-import.md
2026-11-08 16:32:43 +01:00
vangel76 5f4e7ffc18 Merge remote-tracking branch 'upstream/main' into aep-audit-3300 2026-11-08 16:21:58 +01:00
vangel76 2e24ae47a1 aep export: the time remap and Transform keys use the shared key-list and match-name helpers; doc comments for the audit's functions (#3300) 2026-11-08 16:21:57 +01:00
FredApps 7ca249d085 Merge pull request #3120 from vangel76/aep-import-thirdparty
.aep import: map CC Color Neutralizer, EXtractoR and IDentifier
2026-11-08 15:45:08 +01:00
vangel76 4aabf112b6 #3299: aep import/export: linear hostile-input bounds, reported losses, deduplicated export code
Import: precomp loop check by candidate-graph components (no search
without a loop), one LayerId -> index map for mattes, parents and effect
layer references, popup mapping linear in the file's items, lazy loss
details (lose_with), orientation keys at one time reported, mask path
ease speeds under the property limit, Blending Options nested past the
read depth reported.

Export: precomp loops by components, parent loops found once, cached
natural sort keys, one exported-layer set, parameter definitions built
from the effect table (old encode-and-parse path kept as a test
reference), shared key-time loop, key-list rewrite, spatial record,
tdmn/tdsn helpers, unreadable curve and mesh entries reported.

Corpus import and export dumps are byte-identical to the base.
2026-11-08 15:09:45 +01:00
vangel76 b80ac9edb9 aep: read imports through a flat tree index (#3300)
Import reads an .aep through TreeIndex, one depth-first array of chunks that
borrows the file's bytes, instead of building and freeing the owned Chunk tree
(one Vec per list). The parser mirrors read::Parser step for step: the same
chunk count order against max_chunks, the same depth limit and opaque
fallbacks, the same errors. The typed view reads through Node, a handle to a
chunk of either tree, so the accessors work unchanged on both; .aepx keeps its
owned tree. Chunk, parse and write stay for export and editing.

The array starts small and doubles, never past what the input can hold or the
chunk limit allows; a failed allocation is TooLarge, a tree past u32 indices
TooManyChunks.
2026-11-08 15:00:52 +01:00
vangel76 31b99925b0 Merge remote-tracking branch 'origin/aep-cleanup-3281' into aep-import-bounds-3299 2026-11-08 14:47:48 +01:00
vangel76 525250c8e0 Merge remote-tracking branch 'origin/aep-import-thirdparty' into aep-import-bounds-3299
# Conflicts:
#	crates/aep/src/container/effect_map.rs
#	crates/aep/src/export/effects.rs
#	crates/aep/src/import/effects.rs
#	crates/aep/tests/it/export/effects.rs
#	crates/aep/tests/it/import/effects.rs
2026-11-08 14:16:33 +01:00
vangel76 e642fe329f Merge remote-tracking branch 'origin/aep-import-lumetri' into aep-import-bounds-3299
# Conflicts:
#	docs/aep-import.md
2026-11-08 14:16:04 +01:00
vangel76 c8ccf807e1 #3233: AEP import names an unnamed text layer as a following name is cut, so export and import agree 2026-11-08 04:53:01 +01:00
vangel76 66cbb9d89e aep: review fixes for #3281: NTSC table beside TimeBase, real-path NTSC round trip, light and camera defaults on import, doc wording 2026-11-08 04:34:39 +01:00
vangel76 9e2461414a aep: remove test-only container accessors, share report and time-base code (#3281)
- Remove 35 public container accessors that only tests called (header,
  camera/light, keys, footage, masks, shapes, version) and the dead
  StyleMap::switch_name. Tests now check the importer's own reading of the
  same bytes, or the decoder it uses; three import tests gain the values
  the removed checks covered.
- Import and export reports share one loss entry (Loss<C>) with record,
  total, count and summary; the JSON shape is pinned for both.
- Collector::lose_with builds a detail only below the detail cap (callers
  switch later).
- The export uses the container's TimeBase; one NTSC table serves import
  and export; TimeBase::frames saturates like units instead of returning 0.
2026-11-08 04:04:49 +01:00
vangel76 61af9e5b72 #3233: a text layer's name follows its text until the user renames it
A text layer's name followed its Source Text whenever the name started with "Text", so a user's
"Text Title" was replaced by the next text edit. The layer now records whether its name follows
the text (`name_follows_text`, optional in the project file). A new text layer named after its
text follows it; a name given at creation or by Rename (Enter, layer.rename, a script's
layer.name, Layer Settings' name) is the user's and stays; renaming to an empty name shows the
text again and follows it; committing the unchanged name changes nothing; copies keep the state.
On-canvas typing and layer.setText share the rule. The name is the text's first paragraph, which
ends at a line feed or a bare carriage return (After Effects' paragraph break).

Projects saved without the state keep the old rule for the names that followed: a name that is
empty, the text's own, or "Text"/"Text 2"... follows; any other name stays. AEP import records a
stored layer name as the user's and no name as following, and names an empty text layer without
a name "Text" instead of "Layer"; export writes no name for a following layer and keeps the name
the user gave, even when it equals the text.

Fixes #3233
2026-11-07 15:41:14 +01:00
vangel76andClaude Opus 5.5 4e9fcee1c5 Merge upstream/main into aep-import-thirdparty
#3119 (the base of this branch) is merged. Conflicts with the Cryptomatte
import (#3109) and the version report: Extra keeps Extractor, Identifier
and Cryptomatte, arbitrary.rs keeps ExtractorChannels /
identifier_channel_type next to CryptomatteData, the effect table counts
66, the docs keep both sides. The exporter from #2594 gets the Extractor
and Identifier arms: like Lumetri they have no prototype, so CC Color
Neutralizer, EXtractoR and IDentifier are reported, not written (new
test imported_plug_in_effects_are_reported_not_written).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 23:11:22 +01:00
vangel76 924c74f436 Merge remote-tracking branch 'upstream/main' into aep-import-lumetri
# Conflicts:
#	docs/file-format-parity.md
2026-11-06 10:59:50 +01:00
Valentin Klein ce9eaec650 Add After Effects project export (#2594)
Add After Effects project export with chunks built in code, explicit loss reporting, engine and UI integration, and regression coverage.
2026-11-06 09:23:16 +01:00