uttrflow / uttrflow/uttrflow-swift
Every copied picture is expanded to an uncompressed TIFF and re-encoded as PNG, a transient ~190 MB for one 5K screenshot
- Dominant language
- Swift
- Stars
- 4
- Forks
- 17
- Avg merge
- 3h 32m
- Merged PRs (30d)
- 277
Description
## What happens
`SystemClipboardSource.image()` (`Sources/UttrflowClipboard/ClipboardSource+System.swift:28-37`) reads the picture as follows:
```swift
NSPasteboard.general.readObjects(forClasses: [NSImage.self], options: nil)?.first as? NSImage
item.tiffRepresentation // uncompressed
NSBitmapImageRep(data: tiff)
bitmap.representation(using: .png, properties: [:])
```
The pasteboard usually already holds PNG bytes: a screenshot copied with the keyboard puts `public.png` there (`Docs/panel.md` says so). Those bytes are decoded, written out as an uncompressed TIFF, decoded again and compressed again. This happens on the watcher for every picture copy, and again inside `PasteboardWatcher.claims` when a picture write was announced (`PasteboardWatcher.swift:99`). No size bound applies: `ClipboardBudget.largestClip` counts text only.
## Measured
Throwaway harness, Release build. It takes a 5120 × 2880 PNG of about 0.5 MB, turns it into an `NSImage`, and then runs the same three steps:
| step | time | size |
|---|---|---|
| `tiffRepresentation` | 56 ms | 59 MB |
| decode + PNG encode | 74 ms | 0.5 MB out |
| peak resident memory | +193 MB (131 → 324 MB) | |
## Why it matters
On an 8 GB M1 Air, each screenshot copied adds a spike of about 190 MB and more than 100 ms of processor time, even if the user never opens the panel. Copying a few screenshots in a row stacks these spikes.
## Acceptance criteria
- When the pasteboard carries PNG data, those bytes are used as they are, and the pixel size is read from the image header (for example with `CGImageSourceCopyPropertiesAtIndex`) without decoding.
- Other flavours (TIFF, HEIC and so on) are converted once, without an uncompressed TIFF in between where avoidable.
- A decision is written in `Docs/clipboard-budget.md` about whether a picture above some size is still recorded.
- The PR states before and after peak memory for one 5K screenshot, measured headlessly.
Contributor guide
Research direction
Read Sources/UttrflowClipboard/ClipboardSource+System.swift:28-37 and PasteboardWatcher.swift:99, then compare the clipboard formats described in Docs/panel.md. Trace both image paths and measure the current headless 5K screenshot case before changing them. Done means PNG bytes avoid unnecessary decoding, other formats avoid an intermediate TIFF where possible, the size decision is recorded in Docs/clipboard-budget.md, and before/after peak memory is reported.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, swift
- Domain
- desktop-dev, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 64/100