Skip to content

Export as animated GIF #6

Description

@nftechie

Context

GIFs autoplay inline in GitHub issues, pull requests, READMEs, Notion and many chat tools. Today people export an MP4 and convert it with another tool.

Where to look

  • Sources/SnapcapCore/Render/VideoExporter.swift: MP4 export, with a .partial temp file and atomic replace, a progress callback, and ExportRecord.
  • Sources/SnapcapCore/Render/CompositionBuilder.swift: build(folder:project:purpose: .export) returns an AVMutableComposition and a videoComposition that already include the camera bubble and respect the trim. Keep sourceAssets alive while reading.
  • Sources/Snapcap/Views/EditorView.swift: ExportPanel (the buttons) and EditorModel.export(copyWhenDone:).
  • Sources/snapcap-cli/SnapcapCLI.swift: the export command. Add new value flags to Arguments.valued.
  • Tests/SnapcapCoreTests/ExportTests.swift: fixture-based export tests to copy.

Proposal

  • Add a GIFExporter in Sources/SnapcapCore/Render/. Read frames at a fixed rate with AVAssetReaderVideoCompositionOutput (fast for many frames), or with AVAssetImageGenerator (set videoComposition, zero tolerances and maximumSize).
  • Write the GIF with ImageIO: CGImageDestinationCreateWithURL(url, UTType.gif.identifier as CFString, frameCount, nil), file properties with kCGImagePropertyGIFLoopCount: 0, and per-frame kCGImagePropertyGIFDelayTime (plus kCGImagePropertyGIFUnclampedDelayTime).
  • Default to 12 fps at 960 px wide (keeping the aspect ratio, with even dimensions), with 10 or 15 fps and 640, 960 or 1280 px options. Warn when the trimmed duration is over about 30 seconds, since GIFs get large fast.
  • Write the output next to the MP4 as <name>.gif, using the same partial-then-replace approach. GIFs have no audio.

Acceptance criteria

  • Export GIF in the editor, with fps and width options, a progress indicator and Cancel.
  • snapcap-cli export <session> --format gif [--fps 12] [--width 960] works, and the default format stays MP4.
  • The GIF loops forever, includes the camera bubble, respects the trim, and has the expected frame count (±1) and dimensions.
  • Cancelling leaves no partial file behind and doesn't touch an existing GIF.
  • A test generates a fixture, exports a GIF, and verifies it with CGImageSourceGetCount and the frame size.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestexportRendering and exporting videogood first issueGood for newcomers

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions