Skip to content
Merged

Dev #23

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions .cursorrules

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions AGENT.md

Large diffs are not rendered by default.

37 changes: 21 additions & 16 deletions ARCHITECTURE.md

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,28 @@ OpenFCPXMLKit uses **New Features**, **Improvements**, and **Bug Fixes** for eac

---

## [3.0.4](https://github.com/TheAcharya/OpenFCPXMLKit/releases/tag/3.0.4) - 2026-07-13

### ✨ New Features

- **PDF report export:** `FinalCutPro.FCPXML.ReportPDFExport` (`makePDFData(from:)`, `export(_:to:)`) renders a built `Report` to a multi-page `.pdf` via CoreGraphics. All nine workbook sections are supported (Selected Roles Inventory, per-role sheets, Markers, Keywords, Titles & Generators, Transitions, Video & Audio Effects, Speed Change Effects, Summary, Media Summary) with dynamic column widths, pagination, and truncation for wide tables.
- **PDF presentation:** Cover page with workbook branding (`ReportWorkbookCoverSheet` / `exportBrandingText`), dynamic table of contents (section titles and page numbers), per-page header/footer rules, and section background tinting between header and footer bands.
- **CLI `--create-pdf`:** With `--report`, also writes `{project-or-clip-name}.pdf` beside the `.xlsx` workbook from the same built `Report`. Section flags, `--exclude-column`, `--exclude-role`, `--exclude-disabled-clips`, `--timecode-format`, and `--report-project` apply to both formats. Progress includes a **Saving PDF** step when enabled.

### 🔧 Improvements

- **Shared row colours:** Excel and PDF export now use `FCPXMLReportRowColorPolicy` for inventory, section-sheet, Summary, and Media Summary text colours (refactored from `FCPXMLReportWorkbookExporter`).
- **Test suite:** Expanded to **944** tests listed in `swift test --list-tests` (**942** in `OpenFCPXMLKitTests`: 939 XCTest + 3 Swift Testing `@Test`; plus **2** optional `ExcelReportTest`), including `FCPXMLReportPDFExportTests` (cover, TOC, section parity, pagination, branding), `testExportDefaultRoleInventoryPDF` integration coverage, and strengthened `FCPXMLCompoundClipReportTests` / `FCPXMLReportTimecodeFormatTests` regression assertions.
- **CLI help:** `--help` overview and REPORT option strings now describe Excel/PDF report export consistently (`--create-pdf`, `--timecode-format`, `--exclude-column`, `--report-project`).
- **Dependencies:** SwiftExtensions minimum raised to **2.3.2**.
- **Documentation:** Manual chapter **19 — Reporting, Excel & PDF Export**; updated **16 — CLI**, **17 — Examples**, and cross-platform notes; CLI README; `AGENT.md`, `ARCHITECTURE.md` (§2.7 / §8), `.cursorrules`; and `Tests/README.md` / `Tests/ExcelReportTest/README.md`.

### 🐛 Bug Fixes

- None in this release.

---

## [3.0.3](https://github.com/TheAcharya/OpenFCPXMLKit/releases/tag/3.0.3) - 2026-07-10

### ✨ New Features
Expand Down
2 changes: 1 addition & 1 deletion Documentation/Manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ From the index you can reach all chapters:
- **16** — CLI (OpenFCPXMLKit-CLI)
- **17** — Examples (workflows and code)
- **18** — Cross-Platform & iOS (OFKXML abstraction, Foundation vs AEXML)
- **19** — Reporting & Excel Export (ReportTimecodeFormat, ReportBuildPhase progress, sections, column/disabled-clip exclusion, XLKit workbook and cell formatting)
- **19** — Reporting, Excel & PDF Export (ReportTimecodeFormat, ReportBuildPhase progress, sections, column/disabled-clip exclusion, XLKit workbook, CoreGraphics PDF, shared row colours)

---

Expand Down
2 changes: 1 addition & 1 deletion Documentation/Manual/00-Index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Complete manual and usage guide for **OpenFCPXMLKit**, a Swift 6 framework for F
| [16 — CLI](16-CLI.md) | Experimental command-line interface (OpenFCPXMLKit-CLI) |
| [17 — Examples](17-Examples.md) | End-to-end workflows and code examples |
| [18 — Cross-Platform & iOS](18-Cross-Platform-iOS.md) | XML abstraction layer, OFKXML protocols, Foundation vs AEXML backends, iOS support |
| [19 — Reporting & Excel Export](19-Reporting.md) | Report builder, ReportOptions, ReportTimecodeFormat, ReportBuildPhase progress order, report sections, column/disabled-clip exclusion, RoleDisplayPreference, XLKit workbook export and cell formatting |
| [19 — Reporting, Excel & PDF Export](19-Reporting.md) | Report builder, ReportOptions, ReportTimecodeFormat, ReportBuildPhase progress order, report sections, column/disabled-clip exclusion, RoleDisplayPreference, XLKit workbook export, CoreGraphics PDF export, and shared row colour policy |

---

Expand Down
1 change: 1 addition & 0 deletions Documentation/Manual/01-Overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ OpenFCPXMLKit provides a comprehensive API for parsing, creating, and manipulati
| **FCPXMLValidator** | Semantic validation (root, resources, ref resolution) |
| **FCPXMLDTDValidator** | DTD schema validation for a given FCPXML version |
| **FCPXMLExporter** / **FCPXMLBundleExporter** | Export `Timeline` to FCPXML string or `.fcpxmld` bundle |
| **ReportExcelExport** / **ReportPDFExport** | Export a built `Report` to `.xlsx` (XLKit) or `.pdf` (CoreGraphics) |

---

Expand Down
4 changes: 2 additions & 2 deletions Documentation/Manual/10-Extraction-Media.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Extract elements from an FCPXML tree by type or using **presets**. **FinalCutPro
- **TitlesExtractionPreset** (`.titles`) — Titles visible on the main timeline (`[ExtractedElement]`)
- **EffectsExtractionPreset** (`.effects`) — Semantic clip effects visible on the main timeline (`[ExtractedEffect]`, with `kind`, `name`, `settings`, `isAppleSupplied`)

Call **extract(types:scope:)** on an `FCPXMLElement` (or **fcpExtract(types:scope:)** on `XMLElement`) for `[FinalCutPro.FCPXML.ExtractedElement]`. Call **extract(preset:scope:)** for a preset's result type. APIs are async. The `TitlesExtractionPreset` and `EffectsExtractionPreset` presets are also the basis of the Titles and Effects report sections — see [19 — Reporting & Excel Export](19-Reporting.md).
Call **extract(types:scope:)** on an `FCPXMLElement` (or **fcpExtract(types:scope:)** on `XMLElement`) for `[FinalCutPro.FCPXML.ExtractedElement]`. Call **extract(preset:scope:)** for a preset's result type. APIs are async. The `TitlesExtractionPreset` and `EffectsExtractionPreset` presets are also the basis of the Titles and Effects report sections — see [19 — Reporting, Excel & PDF Export](19-Reporting.md).

```swift
let element: FCPXMLElement = // ... e.g. from document
Expand Down Expand Up @@ -76,4 +76,4 @@ for entry in copyResult.failed { /* error */ }
## Next

- [11 — Media Processing](11-Media-Processing.md) — MIME type, asset validation, silence, duration, parallel I/O.
- [19 — Reporting & Excel Export](19-Reporting.md) — build reports from extracted elements and export to `.xlsx`.
- [19 — Reporting, Excel & PDF Export](19-Reporting.md) — build reports from extracted elements and export to `.xlsx` or `.pdf`.
4 changes: 2 additions & 2 deletions Documentation/Manual/14-High-Level-Model.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ For quick inspection and high-level access without walking the XML tree, use **F
- **allEvents()** — All events in the document
- **allProjects()** — All projects in the document
- **allTimelines()** — Top-level timelines (sequences, clips, etc.) in document order
- **allReportTimelineSources()** — Timelines suitable for Excel reporting: every project sequence, plus event-level compound clips (`ref-clip` → `media`/`sequence`) when FCP exported a compound clip without a `<project>`
- **allReportTimelineSources()** — Timelines suitable for reporting (Excel/PDF): every project sequence, plus event-level compound clips (`ref-clip` → `media`/`sequence`) when FCP exported a compound clip without a `<project>`

```swift
let data = try loader.loadData(from: url)
Expand All @@ -35,7 +35,7 @@ let version = fcpxml.version

Bridging with **FCPXMLVersion** (DTD/validation): use `.fcpxmlVersion` and `.dtdVersion` and `init(from:)` converters where provided.

For building Excel reports from either a project or a standalone compound clip, see [19 — Reporting & Excel Export](19-Reporting.md).
For building Excel or PDF reports from either a project or a standalone compound clip, see [19 — Reporting, Excel & PDF Export](19-Reporting.md).

---

Expand Down
16 changes: 11 additions & 5 deletions Documentation/Manual/16-CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Use **one** of: `--check-version`, `--convert-version`, `--validate`, `--media-c

### REPORT

Build an Excel (`.xlsx`) report workbook from FCPXML/FCPXMLD. Works for normal project timelines and for standalone compound-clip exports (event `ref-clip` with no `<project>`). The workbook is written to `<output-dir>`; its file name is derived from the project or compound-clip name. See [19 — Reporting & Excel Export](19-Reporting.md) for the underlying API.
Build an Excel (`.xlsx`) report workbook from FCPXML/FCPXMLD, with optional PDF (`.pdf`) export via `--create-pdf`. Works for normal project timelines and for standalone compound-clip exports (event `ref-clip` with no `<project>`). The workbook is written to `<output-dir>`; its file name is derived from the project or compound-clip name. See [19 — Reporting, Excel & PDF Export](19-Reporting.md) for the underlying API.

| Option | Description |
|--------|-------------|
Expand All @@ -43,11 +43,12 @@ Build an Excel (`.xlsx`) report workbook from FCPXML/FCPXMLD. Works for normal p
| **--report-speed-change-effects** | Include the Speed Change Effects sheet (with `--report`). |
| **--report-summary** | Include the Summary sheet (project metrics and role-duration totals; with `--report`). |
| **--report-media-summary** | Include the Media Summary sheet (missing media file paths; with `--report`). |
| **--create-pdf** | Also write a PDF report alongside the Excel workbook (with `--report`). Uses the same built `Report` — sections, column exclusions, timecode format, role/disabled-clip filtering. Writes `{project-or-clip-name}.pdf` to output-dir; prints the PDF path after the `.xlsx` path. |
| **--report-project &lt;name&gt;** | Timeline name filter: matches a `<project>` name or a standalone compound-clip / `ref-clip` name when the document has more than one reportable timeline. |
| **--exclude-role &lt;role&gt;** | Exclude a role or subrole from the role inventory (repeatable). Excluding a main role also excludes its subroles. |
| **--exclude-disabled-clips** | Omit disabled clips (`enabled="0"`) from all timeline-based report sections (with `--report`). |
| **--exclude-column &lt;column&gt;** | Exclude a workbook column from every applicable report sheet (repeatable; with `--report`). |
| **--timecode-format &lt;format&gt;** | Timeline time display format for Excel report cells (with `--report`). Values: `HH:MM:SS:FF` (default; SMPTE with frames, `;` before frames for drop-frame), `Frames`, `Feet+Frames`, `HH:MM:SS`. |
| **--timecode-format &lt;format&gt;** | Timeline time display format for report cells in Excel and PDF (with `--report`). Values: `HH:MM:SS:FF` (default; SMPTE with frames, `;` before frames for drop-frame), `Frames`, `Feet+Frames`, `HH:MM:SS`. |

When `--report` is used without `--report-full` or section flags, the CLI exports role inventory only. Use `--report-full` for every optional sheet, or set individual `--report-*` section flags for a partial export (role inventory is always included). `--report-full` takes precedence when combined with section flags.

Expand Down Expand Up @@ -96,7 +97,7 @@ Common values:
| `Source File Path` | Removes Source File Path (and Missing Media on Media Summary) |
| `Frame Rate` | Removes Frame Rate/Sample Rate (and related summary metric cells) |

Unknown column names are ignored. See [19 — Reporting & Excel Export](19-Reporting.md#column-exclusion) for the full **ReportColumn** list and aliases.
Unknown column names are ignored. See [19 — Reporting, Excel & PDF Export](19-Reporting.md#column-exclusion) for the full **ReportColumn** list and aliases.

```bash
OpenFCPXMLKit-CLI --report \
Expand All @@ -108,7 +109,7 @@ OpenFCPXMLKit-CLI --report \

#### Timecode display format

`--timecode-format` controls how timeline and source time columns are written in the workbook (and appends a header suffix when not using default SMPTE frames). See [19 — Reporting & Excel Export](19-Reporting.md#timecode-display-format).
`--timecode-format` controls how timeline and source time columns are written in Excel and PDF exports (and appends a header suffix when not using default SMPTE frames). See [19 — Reporting, Excel & PDF Export](19-Reporting.md#timecode-display-format).

| Value | Cells | Example headers |
|-------|-------|-----------------|
Expand Down Expand Up @@ -170,6 +171,11 @@ OpenFCPXMLKit-CLI --report --report-full \
--timecode-format Frames \
/path/to/project.fcpxmld /path/to/output-dir

# Excel workbook plus PDF (same report configuration)
OpenFCPXMLKit-CLI --report --report-full --create-pdf \
--exclude-column Metadata \
/path/to/project.fcpxmld /path/to/output-dir

# Create a new empty project (e.g. 1920×1080 at 25 fps), write to output-dir; project file name is 1920x1080@25p.fcpxml
OpenFCPXMLKit-CLI --create-project --width 1920 --height 1080 --rate 25 /path/to/output-dir
OpenFCPXMLKit-CLI --create-project --width 640 --height 480 --rate 29.97 --project-version 1.13 /path/to/output-dir
Expand All @@ -188,6 +194,6 @@ For source layout, extending the CLI, and regenerating embedded DTDs, see **[Ope
## Next

- [17 — Examples](17-Examples.md) — End-to-end workflows and code examples.
- [19 — Reporting & Excel Export](19-Reporting.md) — the reporting API behind `--report`.
- [19 — Reporting, Excel & PDF Export](19-Reporting.md) — the reporting API behind `--report`.

[← Manual Index](00-Index.md)
27 changes: 22 additions & 5 deletions Documentation/Manual/17-Examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ for clip in timeline.clips {

---

## Build an Excel report
## Build a report (Excel and PDF)

```swift
import OpenFCPXMLKit
Expand All @@ -253,14 +253,31 @@ let report = try await fcpxml.buildReport(options: options) { phase in
print("Building \(phase.rawValue)…")
}

let outputURL = URL(fileURLWithPath: "/path/to/Report.xlsx")
try await FinalCutPro.FCPXML.ReportExcelExport.export(report, to: outputURL)
let xlsxURL = URL(fileURLWithPath: "/path/to/Report.xlsx")
try await FinalCutPro.FCPXML.ReportExcelExport.export(report, to: xlsxURL)

let pdfURL = URL(fileURLWithPath: "/path/to/Report.pdf")
try FinalCutPro.FCPXML.ReportPDFExport.export(report, to: pdfURL)

print("Wrote \(report.roleInventory?.roleSheets.count ?? 0) role sheet(s)")
print("Excluded columns: \(report.excludedColumns)")
print("Timecode format: \(report.timecodeFormat.rawValue)")
```

Equivalent CLI:
Equivalent CLI (Excel + PDF):

```bash
OpenFCPXMLKit-CLI --report --report-full --create-pdf \
--exclude-role Effects \
--exclude-disabled-clips \
--exclude-column Reel \
--exclude-column Metadata \
--exclude-column "Source File Path" \
--timecode-format Frames \
/path/to/project.fcpxmld /path/to/output-dir
```

Excel-only CLI (omit `--create-pdf`):

```bash
OpenFCPXMLKit-CLI --report --report-full \
Expand All @@ -273,7 +290,7 @@ OpenFCPXMLKit-CLI --report --report-full \
/path/to/project.fcpxmld /path/to/output-dir
```

See [19 — Reporting & Excel Export](19-Reporting.md) for the full reporting API.
See [19 — Reporting, Excel & PDF Export](19-Reporting.md) for the full reporting API.

---

Expand Down
2 changes: 1 addition & 1 deletion Documentation/Manual/18-Cross-Platform-iOS.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ let version = root?.stringValue(forAttributeNamed: "version")

## Testing

- The `OpenFCPXMLKitTests` suite (**932 tests** listed under that target: 929 XCTest + 3 Swift Testing `@Test`) runs on **macOS** and uses the Foundation backend. `swift test --list-tests` also lists **1** optional `ExcelReportTest` integration test (**933** total).
- The `OpenFCPXMLKitTests` suite (**942 tests** listed under that target: 939 XCTest + 3 Swift Testing `@Test`) runs on **macOS** and uses the Foundation backend. `swift test --list-tests` also lists **2** optional `ExcelReportTest` integration tests (**944** total).
- **iOS** is supported for building the library (e.g. iOS Simulator); running the same tests on iOS is not required for CI because they depend on Foundation XML. AEXML parity and structural validation are covered by tests that run on macOS.

---
Expand Down
Loading