Skip to content

Blake-C/macos-image-viewer-application

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

89 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Image Viewer

A fast, native macOS image gallery and viewer built with Swift and SwiftUI. No Xcode required — built entirely with Swift Package Manager from the command line.

Note: This application was written entirely by Claude (Anthropic) and has not been reviewed by a human developer. Use at your own discretion.

Features

Gallery

  • Grid view of all images in a folder with thumbnail previews
  • View button in the toolbar opens a popover for layout, thumbnail style, and size:
    • Grid or Masonry layout toggle
    • Square or aspect-ratio thumbnail mode (also Cmd+T)
    • Adjustable thumbnail size slider (100–280px, persisted per folder)
  • Filter button opens a popover for favorites, file type, and date:
    • Favorites — star images and filter to show only favorites
    • Filter by file type (JPEG, PNG, HEIC, RAW, etc.)
    • Filter by date range (modified date)
  • Sort by name, date modified, or file size (ascending or descending)
  • Search by filename (Cmd+S to focus search field)
  • Multi-select with Cmd+click (individual) or Shift+click (range)
  • Remembers your sort, filters, thumbnail size, and view settings per folder
  • Auto-refreshes when files are added, removed, or renamed in the folder
  • Optional recursive subfolder scanning (toggled in folder settings)
  • Recent folders list — quick access to the last 10 opened folders via the toolbar
  • Drag a folder onto the gallery window to open it; drag images out to Finder

Full-Image View

  • Click any thumbnail to open the full image
  • Smooth zoom with scroll wheel, trackpad pinch, Cmd++ / Cmd+-, or Cmd+1 (actual pixels)
  • Pan by dragging
  • Cmd+0 to reset zoom to fit
  • Arrow keys to navigate between images (or pan when zoomed in)
  • Image position counter (e.g. 3 / 47) shown in the bottom-right corner
  • Image info overlay (I) — filename, pixel dimensions, file size, date modified
  • Metadata sheet (M) — full ImageIO metadata (General, TIFF, EXIF, GPS, IPTC, PNG); ComfyUI workflow images show parsed model, generation, and prompt sections; every field has a copy-to-clipboard button
  • Right-click context menu with the same actions as the gallery thumbnail menu
  • Play/pause slideshow button in the top-right corner (Cmd+P)
  • Trash button in the top-right corner
  • Returns to gallery scrolled to the current image

Slideshow

  • Press Cmd+P to start/stop a slideshow (or use the play/pause button in the full-image toolbar)
  • Crossfade transition between images on auto-advance; instant cut on manual navigation
  • Adjustable interval (0.5s minimum) via controls overlay
  • Shuffle mode — randomly selects the next image instead of advancing sequentially
  • Ken Burns pan & zoom effect — portrait images pan top-to-bottom, landscape pan left-to-right

Delete / Trash

  • Cmd+Delete moves the current image to Trash (gallery and full-image view)
  • Trash button in the top-right of the full-image view
  • Multi-select trash via the action bar in the gallery
  • Plays the system trash sound on deletion
  • In-app deletions do not trigger an unnecessary folder refresh

Multi-select Actions

  • Move selected images to Trash
  • Move selected images to another folder
  • Copy file paths to clipboard

Thumbnail Context Menu (right-click)

  • Open in default app
  • Show in Finder
  • Add/remove from Favorites
  • Copy image to clipboard
  • Copy file path
  • Set as desktop wallpaper
  • Move to Trash

Full-Image Context Menu (right-click)

  • Same actions as the thumbnail context menu

Folder Security & Settings

  • Lock any open folder with Touch ID via the gear icon in the gallery toolbar
  • Authentication is required each time a locked folder is opened — including on app launch
  • Falls back to your macOS login password if Touch ID is unavailable
  • Lock state is stored per-folder in UserDefaults and enforced via macOS LocalAuthentication
  • Disabling a lock requires Touch ID or your login password
  • Locked folders show a lock icon in the toolbar gear button
  • Toggle recursive subfolder scanning per-folder in the settings sheet

General

  • Multiple independent windows (Cmd+N), each with its own folder and state
  • Full-screen support (Cmd+F)
  • Refresh folder (Cmd+R)
  • Open folder (Cmd+O)
  • Remembers the last opened folder across launches
  • Per-folder settings persistence (sort, filters, thumbnail size, layout mode, recursive scan)
  • Window title bar shows folder name, image count, and total file size — updates live
  • Favorites persist using file bookmarks — survive renames and moves within a volume

Supported Formats

Standard: jpg jpeg png gif heic heif tiff tif bmp webp avif

RAW: dng raw cr2 cr3 arw nef orf rw2 raf pef srw x3f 3fr mef nrw rwl iiq

RAW formats are decoded via macOS ImageIO — support depends on your macOS version and the camera model.

Requirements

  • macOS 14 (Sonoma) or later
  • Xcode Command Line Tools or a full Xcode install (for the Swift compiler)

Install command line tools if needed:

xcode-select --install

Building

Clone the repository and run the build script from the project root:

git clone <repo-url>
cd image-viewer-gallery
./build-app.sh

This compiles a release build and produces ImageViewer.app in the project directory.

Install to /Applications

Always remove the old bundle before copying — overwriting in place can cause macOS to cache the old binary or code signature:

rm -rf /Applications/ImageViewer.app
cp -r ImageViewer.app /Applications/

If macOS shows a security warning the first time you open the app, right-click ImageViewer.app and choose Open, then confirm. This is expected for apps distributed outside the Mac App Store.

After installation, refresh the Launch Services database so the app appears correctly in Spotlight and Launchpad:

/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -r -domain local -domain system -domain user && killall Finder

Updating the app

If a newly built version doesn't reflect your latest changes, macOS likely cached the old bundle. Quit the app first, then do a clean replace:

./build-app.sh && killall ImageViewer 2>/dev/null; rm -rf /Applications/ImageViewer.app && cp -r ImageViewer.app /Applications/

The killall step ensures the old process isn't still holding the bundle open. The rm -rf before copying is the critical part — never overwrite a running or previously-installed .app in place.

Run without installing

open ImageViewer.app

Or run directly from the terminal (prints logs to stdout):

.build/release/ImageViewer

Rebuilding the app icon

The app icon is pre-generated and included in the repo (AppIcon.icns). If you want to regenerate it:

swift make-icon.swift
iconutil -c icns AppIcon.iconset

Keyboard Shortcuts

Gallery

Shortcut Action
Arrow keys Navigate thumbnails
Enter / Space Open selected image
Cmd+Delete Move selected image to Trash
Cmd+S Focus search field
Cmd+T Toggle square / aspect-ratio thumbnails
Cmd+O Open folder
Cmd+R Refresh folder
Cmd+N New window
Cmd+F Toggle full screen
Escape Clear multi-selection / clear search

Full-Image View

Shortcut Action
← → Previous / next image (or pan when zoomed)
↑ ↓ Pan up / down
Scroll wheel Zoom in / out at cursor
Cmd++ / Cmd+- Zoom in / out
Cmd+0 Reset zoom to fit
Cmd+1 Zoom to actual pixels (1:1)
F Toggle favorite
I Toggle image info overlay
M Open metadata sheet
Cmd+P Start / stop slideshow
Cmd+Delete Move current image to Trash
Cmd+S Return to gallery and focus search
Cmd+O Open folder
Escape / Enter / Space Return to gallery
Cmd+R Refresh folder

Search Field

Shortcut Action
Cmd+S Focus search field
Escape Clear search text (first press) / defocus (second press)

Project Structure

Sources/ImageViewer/
├── AppState.swift               # Central state, navigation, sort, filter, slideshow, folder watching
├── ImageViewerApp.swift         # App entry point, per-window setup, menu commands, title bar
├── Views/
│   ├── RootView.swift           # Top-level view switcher, folder auth gate
│   ├── FolderPickerView.swift   # Initial folder selection screen, auth failure UI
│   ├── GalleryView.swift        # Thumbnail grid, masonry layout, toolbar, filter popover
│   ├── ThumbnailCell.swift      # Individual thumbnail with context menu (grid + masonry)
│   ├── FullImageView.swift      # Full-image viewer, zoom/pan, Ken Burns, crossfade, context menu
│   ├── MetadataPanelView.swift  # Full ImageIO + ComfyUI metadata sheet
│   ├── SlideshowControlsOverlay.swift
│   ├── InfoOverlayView.swift    # Image metadata HUD
│   └── FolderSettingsSheet.swift  # Touch ID lock and recursive scan toggle
└── Utilities/
    ├── ImageLoader.swift            # Async image loading with LRU thumbnail cache
    ├── FolderScanner.swift          # Async directory enumeration
    ├── FolderLockManager.swift      # Keychain-backed Touch ID lock state
    └── ComfyUIWorkflowParser.swift  # Parses ComfyUI workflow JSON embedded in PNG metadata

Technical Notes

  • Built with SwiftUI + AppKit on Swift Package Manager — no Xcode project file
  • Minimum deployment target: macOS 14
  • Thumbnail loading is fully asynchronous with an in-memory LRU cache keyed on (url, size) — prevents blurry thumbnails when switching between grid and masonry layouts
  • Directory scanning runs off the main thread to avoid UI freezes on large folders; optional recursive mode uses FileManager.enumerator
  • Each window owns an independent AppState object — windows don't share state
  • Per-folder settings are stored in UserDefaults as JSON, capped at 50 entries to prevent unbounded growth
  • Folder changes are detected via DispatchSource file system events with a 0.5s debounce
  • In-app deletions suppress the folder watcher to avoid redundant refreshes
  • Folder lock state is stored in UserDefaults; authentication is enforced via LAContext.evaluatePolicy(.deviceOwnerAuthentication) which gates access with Touch ID or the macOS login password
  • Favorites use URL.bookmarkData() for persistence, so starred images survive renames and moves within a volume; path-based fallback handles migration from older data
  • File sizes and modification dates are cached during sort, eliminating redundant disk reads on re-sort
  • Trackpad pinch-to-zoom uses an NSEvent.magnify local monitor alongside the scroll-wheel zoom monitor

License

MIT

About

A fast, native macOS image gallery and viewer built with Swift and SwiftUI. No Xcode required — built entirely with Swift Package Manager from the command line.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors