Universal image batch converter with a modern GUI. Scans directories recursively and converts JPEG, PNG, HEIC, AVIF, WebP, JPEG XL, Camera RAW, TIFF, BMP, JPEG 2000, QOI, and ICO files to JPEG, PNG, WebP, AVIF, TIFF, or JPEG XL with full metadata preservation.
Most image converters get the details wrong — they strip metadata, mangle colors by dropping ICC profiles, or use lossy 4:2:0 chroma subsampling by default. HEICShift is built on research into what existing tools do poorly:
| Problem | Other Tools | HEICShift |
|---|---|---|
| Color accuracy | ImageMagick strips ICC profiles with -strip, causing Display P3 → sRGB color shift |
Passes ICC profiles through to output — colors stay accurate |
| Chroma subsampling | Most default to 4:2:0 (halves color resolution) | Uses 4:4:4 — full color fidelity |
| Format selection | Force you to pick JPEG or PNG for everything | Auto-detects: JPEG for photos, PNG only when transparency exists |
| Metadata | Online converters and many CLI tools strip EXIF/GPS/timestamps | Preserves EXIF, ICC, and XMP data by default |
| Performance | Single-threaded or limited concurrency | Parallel conversion with configurable worker count (up to 32) |
| Format coverage | Most only handle HEIC or one format at a time | 12+ input format families from a single tool |
| Format | Extensions | Decoder | Install |
|---|---|---|---|
| JPEG | .jpg .jpeg .jpe .jfif |
Pillow | Auto |
| PNG | .png |
Pillow | Auto |
| HEIC/HEIF | .heic .heif .hif |
pillow-heif | Auto |
| AVIF | .avif |
pillow-heif | Auto |
| WebP | .webp |
Pillow | Auto |
| TIFF | .tif .tiff |
Pillow | Auto |
| BMP | .bmp |
Pillow | Auto |
| JPEG 2000 | .jp2 .j2k .jpx |
Pillow | Auto |
| ICO/CUR | .ico .cur |
Pillow | Auto |
| JPEG XL | .jxl |
pillow-jxl-plugin | Auto (optional) |
| Camera RAW | .cr2 .cr3 .nef .arw .dng .orf .rw2 .raf |
rawpy/libraw | Auto (optional) |
| QOI | .qoi |
qoi | Auto (optional) |
Output formats: JPEG, PNG, WebP, AVIF, TIFF, JPEG XL
Optional decoders are installed automatically on first launch. If installation fails (e.g. no compiler for rawpy), those formats are skipped gracefully and the app logs which are unavailable.
- Auto format detection — JPEG for photos, PNG when alpha channel is present
- 12+ input formats — JPEG, PNG, HEIC, AVIF, WebP, JXL, RAW, TIFF, BMP, JP2, QOI, ICO
- Cross-format conversion — convert between any formats (JPEG to WebP, PNG to JPEG, etc.); same-format no-ops auto-skipped
- AVIF output — next-gen AV1 codec via Pillow's native encoder, best compression ratio
- JPEG XL output — next-gen JPEG replacement via pillow-jxl-plugin (quality + effort tuning)
- CSV export — structured conversion report with per-file status, sizes, timing, and warnings
- CLI mode — headless conversion via
--inputflag with full feature parity (all GUI options exposed as flags) - In-place conversion — convert next to the original and delete the source file
- Atomic writes — in-place mode uses temp file + atomic rename for crash-safe conversion
- Output validation — verifies file exists, size > 0, and passes integrity check before accepting
- Disk space pre-check — blocks conversion if estimated output exceeds available space, warns at 80%
- Strip metadata — option to remove all EXIF/ICC/XMP from output files
- Auto-open output folder — automatically opens the output folder when conversion finishes
- File count in title bar — shows file count after scan, progress during conversion, summary when done
- Resize upscaling guard — warns when image is already smaller than the resize target
- Conversion presets — Web Optimized, Archive Quality, Mobile Friendly, Print/TIFF one-click presets
- Smart option visibility — format-specific controls auto-show/hide based on output format
- Dark title bar — native dark title bar on Windows 10/11 matching Catppuccin theme
- Conversion speed stats — elapsed time + files/sec displayed in status bar during conversion
- Log context menu — right-click for Copy Selection, Copy All, Open File Location
- Source/output overlap guard — prevents output directory from overwriting source files
- Drag & drop — drop folders or individual image files onto the window
- Format filter — per-family checkboxes to include or exclude input formats from scanning
- Skip existing — resume interrupted batches by skipping files where output already exists
- EXIF auto-rotate — applies orientation from EXIF metadata before saving (prevents double-rotation)
- Image resize — Max Dimension (px) or Scale (%) with LANCZOS resampling
- Filename prefix/suffix — prepend or append text to output filenames
- Progressive JPEG — optional progressive encoding for web-optimized output
- Lossless WebP — optional lossless mode when WebP is selected as output
- JPEG chroma subsampling — toggle between 4:4:4 (default, max fidelity) and 4:2:0 (smaller files)
- sRGB color conversion — convert embedded ICC profiles (Display P3, Adobe RGB, etc.) to sRGB
- TIFF compression — None, LZW, or Deflate when TIFF output is selected
- PNG compression level — adjustable 1–9 for PNG output (default 6)
- Recent directories — dropdown of last 10 source directories for quick re-access
- Metadata preservation — EXIF, ICC color profiles, XMP
- Parallel conversion — 1–32 workers via ThreadPoolExecutor
- Recursive scanning — processes entire directory trees
- Folder structure preservation — mirrors source layout in output (optional)
- Quality control — adjustable slider (50–100) for JPEG/WebP/AVIF
- Scan breakdown — shows count per format family after scanning
- Live stats — files found, total size, converted, skipped, failed, space saved
- Progress ETA — shows current filename and estimated time remaining
- Completion notification — system tray balloon + notification sound when batch finishes
- Embedded log — per-file results with timing and size delta, export to file or clear
- Cancel support — stop mid-conversion without corrupting output
- Settings persistence — remembers all settings including format filter state across sessions
- Catppuccin Mocha dark theme — including dark scrollbars and dark title bar
- Responsive UI scaling — QScrollArea for controls, QSplitter between controls and log, works from 720p to 4K+
- Cross-platform — native file manager integration on Windows, macOS, and Linux
git clone https://github.com/SysAdminDoc/HEICShift.git
cd HEICShift
python heicshift.pyAll dependencies install automatically on first launch. No manual setup.
- Browse or drag & drop a directory containing image files
- Filter which input formats to include (optional — all enabled by default)
- Scan to discover all supported files (recursive by default)
- Adjust settings — format, quality, workers, metadata toggle
- Convert All — output goes to
source/converted/by default
Toggle "Convert in place" to save output next to each source file and delete the original.
Enable "Skip files that already have output" to resume interrupted batches without re-converting.
The log panel shows per-file results with size before/after and conversion time. Logs can be exported to a text file or CSV report.
Run HEICShift from the command line for scripted or headless operation. If --input is provided, the GUI is skipped entirely.
# Convert a directory to JPEG at quality 85
python heicshift.py --input ./photos --format jpeg --quality 85
# Convert to WebP with 4 workers, output to specific folder
python heicshift.py -i ./photos -o ./output -f webp -w 4
# Dry run — list files that would be converted
python heicshift.py --input ./photos --dry-run
# In-place conversion (saves next to originals, deletes source)
python heicshift.py --input ./photos --in-place
# Strip metadata and resize
python heicshift.py --input ./photos --strip-metadata --resize max_dim:1920
# Convert to AVIF with sRGB color conversion
python heicshift.py --input ./photos --format avif --srgb
# Convert to JPEG XL (requires pillow-jxl-plugin)
python heicshift.py --input ./photos --format jxl --quality 90
# Resize by scale percentage
python heicshift.py --input ./photos --resize scale:50
# TIFF with LZW compression
python heicshift.py --input ./photos --format tiff --tiff-compression lzw
# Progressive JPEG with filename prefix, skip already-converted
python heicshift.py -i ./photos -f jpeg --progressive --prefix "web_" --skip-existing
# Print version
python heicshift.py --versionCLI flags:
| Flag | Description |
|---|---|
-i, --input |
Source directory (enables CLI mode) |
-o, --output |
Output directory (default: <input>/converted) |
-f, --format |
Output format: auto, jpeg, png, webp, avif, tiff, jxl |
-q, --quality |
JPEG/WebP quality 50–100 (default: 92) |
-w, --workers |
Parallel worker count (default: min(cpu_count, 8)) |
--in-place |
Convert next to originals, delete source |
--recursive |
Scan subdirectories (default) |
--no-recursive |
Only scan top-level directory |
--dry-run |
List files and exit without converting |
--strip-metadata |
Remove all EXIF/ICC/XMP from output |
--resize |
Resize images, e.g. max_dim:1920 or scale:50 |
--skip-existing |
Skip files where output already exists |
--progressive |
Save JPEGs as progressive |
--chroma-420 |
Use 4:2:0 chroma subsampling for JPEG |
--lossless |
Save WebP in lossless mode |
--srgb |
Convert embedded ICC profiles to sRGB |
--prefix |
Prepend text to output filenames |
--suffix |
Append text to output filenames |
--tiff-compression |
TIFF compression: none, lzw, deflate (default: none) |
--png-level |
PNG compression level 1–9 (default: 6) |
--no-structure |
Flatten output (no subdirectory mirroring) |
--version |
Print version and exit |
Exit codes: 0 = all OK, 1 = partial failure, 2 = total failure or bad input.
Source Directory HEICShift Output
photos/ converted/
├─ IMG_001.heic ──→ pillow-heif decoder ──→ ├─ IMG_001.jpg
├─ IMG_002.avif ──→ Pillow processing ──→ ├─ IMG_002.jpg
├─ shot.webp ──→ EXIF/ICC passthrough ──→ ├─ shot.jpg
├─ photo.cr2 ──→ rawpy demosaic ──→ ├─ photo.jpg
└─ render.qoi ──→ qoi decoder ──→ └─ render.jpg
- pillow-heif — HEIC/HEIF/AVIF decoding
- pillow-jxl-plugin — JPEG XL decoding (optional)
- rawpy — Camera RAW demosaicing via libraw (optional)
- qoi — QOI format decoding (optional)
- Pillow — image processing, WebP/TIFF/BMP/JP2/ICO decoding, output encoding
- PyQt6 — GUI framework
- HDR gain maps in HEIC files are lost during conversion (no JPEG/PNG equivalent). Keep originals for HDR workflows.
- Apple Live Photo motion data and depth maps cannot be preserved in any static format.
- Camera RAW metadata — rawpy performs a full demosaic; EXIF is not carried through. Use ExifTool as a post-pass if needed.
- QOI has no metadata support by design — nothing to preserve.
- HEIC odd dimensions may produce artifacts in some downstream decoders (libheif/codec limitation).
MIT
