Native macOS SwiftUI application for lossless cropping of JPEG/HEIC images with metadata preservation.
- ✅ Support for various image formats (JPEG, HEIC, PNG, TIFF)
- ✅ Flexible aspect ratios (3:2, 16:9, 1:1, 21:9, portrait, etc.)
- ✅ Target format selection: 16:9, 1:1, Custom
- ✅ MCU-sensitive cropping for JPEG (lossless)
- ✅ Standard cropping as fallback
- ✅ Interactive GUI with red crop frame
- ✅ MCU grid visualization (optional)
- ✅ Metadata storage (EXIF DefaultCropOrigin/Size + Custom XMP Tags)
- ✅ Automatic loading of saved crop coordinates - Images with saved crop data are detected and the crop box is automatically positioned
- ✅ Visual indicators - Images with saved crop metadata are marked with a blue badge in the list
- ✅ Automatic filename generation from EXIF date
- ✅ Batch processing for multiple images
- ✅ HEIC to JPEG conversion (optional)
- ✅ Responsive UI - Optimized for various screen sizes (min. 900×600 pixels)
Coming soon - Add screenshots of your app in action
- macOS 12.0 or higher
- Xcode 14.0 or higher
- jpegtran (for MCU-sensitive cropping):
brew install jpeg-turbo - exiftool (for metadata manipulation):
brew install exiftool
- Clone the repository:
git clone https://github.com/YOUR_USERNAME/PhotoCropper.git
cd PhotoCropper- Open the project:
open PhotoCropper.xcodeproj- In Xcode:
- Product → Build (⌘B)
- Product → Run (⌘R)
- Open Xcode and open the project
PhotoCropper.xcodeproj - Product → Scheme → PhotoCropper select
- Product → Destination → My Mac select
- Create Release build:
- Product → Scheme → Edit Scheme...
- Run → Build Configuration → Release select
- OK
- Build: ⌘B (or Product → Build)
- Run: ⌘R (or Product → Run)
cd PhotoCropper
xcodebuild -project PhotoCropper.xcodeproj -scheme PhotoCropper -configuration Release clean buildThe app is typically located at:
~/Library/Developer/Xcode/DerivedData/PhotoCropper-*/Build/Products/Release/PhotoCropper.app
In Finder:
- Open Finder
- ⌘⇧G (Go to Folder)
- Enter path:
~/Library/Developer/Xcode/DerivedData - Open the
PhotoCropper-*folder - Navigate to:
Build/Products/Release/ - You'll find
PhotoCropper.appthere
Via Terminal:
# Find the app automatically
find ~/Library/Developer/Xcode/DerivedData -name "PhotoCropper.app" -path "*/Release/*" | head -1To have the app at a fixed location:
# Create dist folder
mkdir -p dist
# Copy the app there
cp -R ~/Library/Developer/Xcode/DerivedData/PhotoCropper-*/Build/Products/Release/PhotoCropper.app dist/The app is then available at dist/PhotoCropper.app and can be easily shared.
- Open image: File → Open or Drag & Drop
- Select target format: 16:9, 1:1, or Custom
- Cropping mode: MCU-sensitive (Lossless) or Standard
- Adjust crop box: Interactively drag with mouse
- Save: Metadata is saved in EXIF/XMP
- ⌘O - Open image
- Space - Toggle composition overlays
- Enter - Mark as done and move to next image
- ⌘⇧W - Close all images
PhotoCropper/
├── Models/
│ ├── AspectRatio.swift # Aspect ratio calculations
│ ├── CropSettings.swift # Crop settings
│ ├── ImageData.swift # Image data with metadata
│ ├── ExifData.swift # EXIF/XMP structures
│ ├── BatchImageItem.swift # Individual batch element
│ ├── BatchImageManager.swift # Batch management
│ ├── CompositionOverlay.swift # Composition guides
│ └── OverlayGuide.swift # Unified overlay system
├── Views/
│ ├── ContentView.swift # Main view
│ ├── CanvasView.swift # Image canvas (AppKit)
│ ├── ControlsView.swift # Controls
│ ├── PreviewView.swift # Preview
│ ├── ExportView.swift # Export dialog
│ ├── InfoPanel.swift # Info panel
│ ├── BatchImageListView.swift # Batch list
│ └── BatchExportView.swift # Batch export
├── Services/
│ ├── ImageService.swift # Image loading & format detection
│ ├── ImageCropService.swift # Standard cropping (all formats)
│ ├── JPEGService.swift # JPEG MCU cropping (lossless)
│ ├── MetadataService.swift # Metadata facade
│ ├── MetadataReader.swift # Metadata reading
│ ├── MetadataWriter.swift # Metadata writing
│ ├── CropEngine.swift # Crop calculations
│ └── ExifDateParser.swift # EXIF date parsing
└── Utilities/
├── CoordinateMapper.swift # Coordinate transformations
├── FileManager+Extensions.swift # File operations
├── KeyboardMonitor.swift # Keyboard events
├── ProcessExecutor.swift # External commands (posix_spawn)
└── NSImage+Extensions.swift # Image helpers
- SwiftUI + AppKit Hybrid: Canvas uses AppKit for better performance
- jpegtran Integration: Shell command for lossless JPEG cropping (via ProcessExecutor)
- exiftool Integration: Metadata manipulation without image re-encoding
- ImageIO Framework: For image loading and metadata
- Clean Code Architecture:
- Separation of Concerns (Models/Services/Views/Utilities)
- Single Responsibility Principle
- Dependency Injection
- Comprehensive error handling with Result types
- Complete Swift DocC documentation
- Metadata Strategy:
- Reader/Writer/Facade Pattern for metadata services
- 3-Pass Strategy for exiftool (Delete → Write → Sync)
- Normalized coordinates (0.0-1.0) for resolution independence
DefaultCropOrigin: Normalized crop origin [x, y]DefaultCropSize: Normalized crop size [width, height]
XMP-crs:CropTop: Normalized Y coordinateXMP-crs:CropLeft: Normalized X coordinateXMP-crs:CropBottom: Normalized Y + heightXMP-crs:CropRight: Normalized X + width
Stored in XMP-dc:Subject as structured tags:
PhotoCropper:CropMode: MCU-Sensitive or StandardPhotoCropper:TargetRatio: Target aspect ratio (e.g., "16:9")PhotoCropper:OriginalRatio: Original image ratioPhotoCropper:CropOriginX: Normalized X originPhotoCropper:CropOriginY: Normalized Y originPhotoCropper:CropWidth: Normalized widthPhotoCropper:CropHeight: Normalized height
All coordinates are stored normalized (0.0 to 1.0) to be resolution-independent.
- MCU size detection is simplified (standard: 8x8 for JPEGs)
- For precise MCU detection, direct libjpeg would be necessary
- HEIC does not support MCU cropping (uses re-encoding)
- PNG/TIFF always use re-encoding (no lossless crop available)
- No automated tests (manual testing only)
Contributions are welcome! Please see CONTRIBUTING.md for details.
- CLAUDE.md: Central project documentation and architecture overview
- REFACTORING_PLAN.md: Detailed plan of the refactoring performed (Steps 1-13)
- All services and models are documented with Swift DocC
This project is licensed under the MIT License - see the LICENSE file for details.
- jpegtran from jpeg-turbo for lossless JPEG manipulation
- exiftool by Phil Harvey for comprehensive metadata handling
- Apple's ImageIO framework for robust image handling
If you encounter any issues or have questions:
- Open an Issue
- Check existing Discussions
Made with ❤️ for photographers who need precise, lossless image cropping