A headless macOS background agent that repairs broken screenshots.
When capturing HDR content, macOS sometimes saves a screenshot as a HEIF/HEIC
file but gives it a .png extension. The file is therefore mislabeled: its
name says PNG, its bytes say HEIF. Many apps refuse to open such files or render
them incorrectly.
ScreenshotFixer watches your Desktop, detects these mislabeled files by inspecting their actual contents (never the extension), and rewrites them as genuine PNG files in place.
This is especially relevant when you take screenshots to show something to Claude Code or other AI coding agents and chat assistants. Many of these tools commonly accept widely-supported image formats (such as PNG) but may not accept HEIF/HEIC. Support varies between tools and changes over time, so it's worth checking what your specific tool accepts.
A screenshot that is secretly HEIF with a .png name can be rejected or fail
to upload even though it looks like a normal PNG in Finder. PNG, by contrast,
is broadly supported, lossless, and a safe default for sharing screenshots with
an agent. ScreenshotFixer makes sure the files you drag into these tools are
actually PNG, so they just work.
The commonly recommended way to make macOS save screenshots as PNG is:
defaults write com.apple.screencapture type png
killall SystemUIServerIn practice this setting is not fully reliable for HDR captures: screenshots
can still be written as HEIF data while keeping the .png suffix, which
reproduces exactly the mislabeled-file problem above. ScreenshotFixer exists to
catch and correct those cases automatically, regardless of the screencapture
setting.
Note: the exact conditions under which the
defaultssetting is bypassed are not officially documented; the behavior described here is observed, not a documented guarantee. The content-based detection in this app does not rely on understanding why it happens — it only checks what the bytes actually are.
- Locate the Desktop via
FileManager.url(for: .desktopDirectory, …), so it resolves correctly even when the Desktop is iCloud-synced. - Watch with FSEvents (
FSEventStreamCreate, ~0.5 s latency). No polling. - Debounce ~0.8 s after the last event, so files that are still being written (or have a pending screenshot preview) have settled.
- Detect by content, not extension. The primary check reads the
ISO-BMFF
ftypbox ("magic bytes") and matches HEIF brands (heic,heix,heim,heis,hevc,hevx,mif1,msf1). ImageIO's reportedCGImageSourceGetTypeis used only as a secondary corroborating signal, because it can be inconsistent for mis-extensioned files. - Convert & replace atomically. A real HEIF is decoded with ImageIO and
re-encoded as PNG (
CGImageDestinationCreateWithURL,UTType.png) to a sibling temp file, then swapped in withFileManager.replaceItemAt— same name, same directory. - No reprocessing loops. Only files whose bytes are actually HEIF are
touched. After conversion the file is a genuine PNG, so the FSEvent triggered
by our own replace is examined and skipped. Filenames with spaces are handled
(everything is
URL-based). - Recent files only. Each scan considers
.pngfiles modified within the last 5 minutes, keeping the work cheap.
The app is intentionally invisible — no window, no Dock icon, no menu bar item:
LSUIElement = truein the target's Info.plist marks it as an agent.- A SwiftUI
Appwith an emptySettings { EmptyView() }scene plus an@NSApplicationDelegateAdaptormeans no window is ever created.
On first launch the app registers itself as a login item via
SMAppService.mainApp.register() (macOS 13+).
The Desktop is a TCC-protected folder, so the app needs Full Disk Access, granted once by the user:
System Settings → Privacy & Security → Full Disk Access → add ScreenshotFixer.
If access is denied, the directory read fails with "Operation not permitted" and
a clear message is written via os.Logger.
Note: The app runs non-sandboxed (
ENABLE_APP_SANDBOX = NO). Full Disk Access is a non-sandbox mechanism — a sandboxed app cannot use it to reach the Desktop. The trade-off is that this app cannot be distributed through the Mac App Store.
Uses os.Logger under the subsystem matching the bundle identifier
(wrklst.ScreenshotFixer). It logs the start of monitoring, every converted file
(with path), and all errors. Inspect it in Console.app by filtering on that
subsystem.
| File | Role |
|---|---|
ScreenshotFixerApp.swift |
@main app entry; empty Settings scene; AppInfo logging identifiers. |
AppDelegate.swift |
App lifecycle; registers the login item and starts the watcher. |
FolderWatcher.swift |
FSEvents stream, debounce, and recent-PNG scanning. |
HEICConverter.swift |
Content-based HEIF detection and PNG conversion with atomic replace. |
- macOS 13 or later (for
SMAppService; the project currently targets a newer SDK). - Xcode with a Swift 5 toolchain.
Open ScreenshotFixer.xcodeproj in Xcode and build/run the ScreenshotFixer
scheme. Because the app is an agent, running it shows no window; verify behavior
in Console.app.
- Conversion is lossy with respect to HDR: the re-encoded PNG is standard 8-bit SDR. The goal is universal readability, not HDR fidelity.
- Full Disk Access cannot be granted programmatically; it is a one-time manual step. Failures are logged to Console only (no on-screen alert).
Released under the MIT License. You are free to use, copy, modify, and distribute this software, including for commercial purposes, provided the copyright and license notice are retained.