Skip to content

Add Keynote reader and writer - #891

Open
yasumorishima wants to merge 1 commit into
PHPOffice:masterfrom
yasumorishima:feature/keynote-reader-writer
Open

Add Keynote reader and writer#891
yasumorishima wants to merge 1 commit into
PHPOffice:masterfrom
yasumorishima:feature/keynote-reader-writer

Conversation

@yasumorishima

@yasumorishima yasumorishima commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

What it does

Adds a Reader and Writer for the Apple Keynote (.key) presentation format.

The implementation targets the legacy iWork '09 structure, where a Keynote
package is a Zip archive containing an index.apxl XML document. Both classes
follow the existing reader/writer conventions (ReaderInterface / AbstractWriter)
and are registered in IOFactory for automatic resolution.

Supported in this first milestone:

  • Slides
  • Text placeholders — paragraphs and runs
  • Shape geometry (position and size)
  • Speaker notes

Why

Resolves the long-standing request for Keynote support (#48). A previous attempt
(#860) targeted the modern IWA binary format and stalled; this PR deliberately
scopes to the XML-based iWork '09 structure so it can be implemented in pure PHP
(no new dependencies), stays compatible with the project's supported PHP versions
(7.4+), and is fully verifiable in CI.

Scope / limitations (intentional)

  • The modern IWA binary format (Keynote '13 and later: Snappy-compressed
    Protobuf) is out of scope and is safely rejected by canRead() (no false
    positives).
  • Because of the format generation gap, output is not guaranteed to open
    directly in a current Keynote.app. Correctness is instead guaranteed by a
    round-trip test (write → read → assert structure).
  • Content that the basic format cannot represent — non-text shapes (images,
    lines, tables, charts) and in-run line breaks — is silently skipped on
    save; this is characterized by tests (see below).
  • Styling (font/bold/size/color), themes and document properties are left as
    follow-up work.

How it was tested

  • New unit tests for the reader and writer, plus a dedicated round-trip test.
  • Reader coverage includes canRead() rejection of non-Keynote files, non-Zip
    files and directories, and load() error cases (missing file, wrong format).
  • Round-trip coverage includes: multi-slide content with geometry, paragraphs,
    runs and speaker notes; an empty presentation; Unicode and XML metacharacters
    (< > & " ', non-ASCII, emoji) surviving escaping unchanged; multiple text
    placeholders per slide
    preserved in order; and non-representable content
    (a line shape and an in-run line break) being skipped without data corruption.
  • phpunit, phpstan (level 6), php-cs-fixer and phpmd all pass; the full
    existing suite remains green (no regressions).

Notes

  • No new runtime dependencies; uses only ext-xml and ext-zip (already required).
  • Documentation updated in docs/usage/readers.md and docs/usage/writers.md.

Closes #48

/claim #48

@yasumorishima
yasumorishima force-pushed the feature/keynote-reader-writer branch from fc81da2 to 4e7e96b Compare June 25, 2026 18:33
@yasumorishima

Copy link
Copy Markdown
Contributor Author

A quick note on the currently red CI jobs — they are all unrelated to this change:

  • PHPUnit / PHPStan / samples on PHP 7.2 & 7.3 fail at composer install: dependencies can no longer be resolved because phpoffice/phpspreadsheet now requires PHP >= 7.4. These jobs fail before running anything, and this affects the repository's CI in general on those versions (not specific to this PR).
  • PHPStan on PHP 8.4: with no committed composer.lock, the latest phpunit/phpunit (13.x) is installed, which PHPStan then reports as extends unknown class PHPUnit\Framework\TestCase across all existing test classes (e.g. AbstractShapeTest). This is an environment/tooling issue, not something introduced here.
  • PHPUnit 8.1: a single pre-existing failure in Writer\ODPresentation\ObjectsChartTest::testTypeAxisUnit, unrelated to Keynote.

The new Keynote reader/writer is green on every job where the environment resolves correctly: PHPStan 7.1 / 7.4 / 8.0–8.3, PHPUnit 7.1 / 7.4 / 8.0 / 8.2 / 8.3 / 8.4, all samples jobs, PHP-CS-Fixer and PHPMD.

Happy to adjust anything on request.

@yasumorishima
yasumorishima force-pushed the feature/keynote-reader-writer branch 2 times, most recently from e4df1bd to fa09911 Compare July 14, 2026 13:22
@coveralls

coveralls commented Jul 29, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 92.141% (-0.006%) from 92.147% — yasumorishima:feature/keynote-reader-writer into PHPOffice:master

@yasumorishima

Copy link
Copy Markdown
Contributor Author

Rebased onto master now that #897 is merged.

The two PHP Static Analysis (8.4) / (8.5) failures on this PR came from PHPStan 1.x being unable to resolve PHPUnit 13 symbols on PHP 8.4/8.5, which #897 fixed by moving to PHPStan ^2.2. After rebasing, PHPStan 2.2.8 at level 6 (no baseline) reported three issues in this PR's own files, all fixed here:

  • Writer/Keynote.php: dropped the '' == $pFilename half of the tempnam() guard — tempnam() returns non-falsy-string|false, so the comparison was always false.
  • Tests/KeynoteRoundtripTest.php: removed two instanceof RichText guards that follow an assertInstanceOf(RichText::class, ...) — they were always true, and calling the getters directly makes the assertions unconditional.

The presentation diff is otherwise unchanged from the previous head.

Add basic support for the Apple Keynote (.key) presentation format,
targeting the legacy iWork '09 structure where the presentation is stored
as an `index.apxl` XML document inside the `.key` package.

The reader and writer cover slides, text placeholders (paragraphs and
runs), shape geometry and speaker notes, and are validated with a
round-trip test. The modern IWA binary format used by Keynote '13 and
later is intentionally out of scope and is safely rejected by canRead().

Both classes follow the existing reader/writer conventions, are registered
in IOFactory for automatic resolution, and are documented in the usage
pages.

Refs PHPOffice#48
@yasumorishima
yasumorishima force-pushed the feature/keynote-reader-writer branch from 2d24ff2 to 35abce6 Compare August 20, 2026 04:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Reader / Writer for Keynote

2 participants