Skip to content

wrklst/ScreenshotFixer

Repository files navigation

ScreenshotFixer

A headless macOS background agent that repairs broken screenshots.

The problem

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.

Why this matters for Claude Code and AI agents

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 usual defaults workaround isn't always enough

The commonly recommended way to make macOS save screenshots as PNG is:

defaults write com.apple.screencapture type png
killall SystemUIServer

In 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 defaults setting 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.

How it works

  1. Locate the Desktop via FileManager.url(for: .desktopDirectory, …), so it resolves correctly even when the Desktop is iCloud-synced.
  2. Watch with FSEvents (FSEventStreamCreate, ~0.5 s latency). No polling.
  3. Debounce ~0.8 s after the last event, so files that are still being written (or have a pending screenshot preview) have settled.
  4. Detect by content, not extension. The primary check reads the ISO-BMFF ftyp box ("magic bytes") and matches HEIF brands (heic, heix, heim, heis, hevc, hevx, mif1, msf1). ImageIO's reported CGImageSourceGetType is used only as a secondary corroborating signal, because it can be inconsistent for mis-extensioned files.
  5. 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 with FileManager.replaceItemAt — same name, same directory.
  6. 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).
  7. Recent files only. Each scan considers .png files modified within the last 5 minutes, keeping the work cheap.

No user interface

The app is intentionally invisible — no window, no Dock icon, no menu bar item:

  • LSUIElement = true in the target's Info.plist marks it as an agent.
  • A SwiftUI App with an empty Settings { EmptyView() } scene plus an @NSApplicationDelegateAdaptor means no window is ever created.

Autostart

On first launch the app registers itself as a login item via SMAppService.mainApp.register() (macOS 13+).

Permissions — Full Disk Access required

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.

Logging

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.

Project layout

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.

Requirements

  • macOS 13 or later (for SMAppService; the project currently targets a newer SDK).
  • Xcode with a Swift 5 toolchain.

Building

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.

Limitations

  • 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).

License

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.

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages