cheat sheet
sips
macOS built-in image processor covering format conversion, resizing, cropping, rotation, color profiles, metadata inspection, and batch processing recipes.
sips — Scriptable Image Processing System
What it is
sips (Scriptable Image Processing System) is a command-line image manipulation tool built into macOS and maintained by Apple as part of the operating system — no install required. It handles format conversion, resizing, cropping, rotation, color-profile management, and metadata queries entirely from the terminal using CoreImage under the hood. Reach for sips when you need fast, dependency-free image processing on macOS; for more complex compositing or effects, ImageMagick offers a broader feature set.
Inspect an image
Use -g (get property) to read individual metadata fields from an image without modifying it. Running sips with no flags prints a short summary; -g all dumps every property sips tracks, including format, dimensions, DPI, color space, bit depth, and embedded ICC profile.
sips image.png # summary: format, size, color space
sips -g all image.png # all metadata properties
sips -g pixelWidth -g pixelHeight image.png # just dimensions
sips -g format image.png # file format
sips -g dpiWidth -g dpiHeight image.png # DPI
sips -g colorSpace image.png # e.g. RGB, Gray, CMYK
sips -g bitsPerSample image.png # bit depth
sips -g hasAlpha image.png # true/false
sips -g profile image.png # embedded ICC profile
Output (sips -g all image.png):
/Users/alice/photos/image.png
pixelWidth: 1920
pixelHeight: 1080
typeIdentifier: public.png
format: png
formatOptions: default
dpiWidth: 72.000
dpiHeight: 72.000
samplesPerPixel: 4
bitsPerSample: 8
hasAlpha: yes
space: RGB
profile: sRGB IEC61966-2.1
Output (sips -g pixelWidth -g pixelHeight image.png):
/Users/alice/photos/image.png
pixelWidth: 1920
pixelHeight: 1080
Output (sips -g format image.png):
/Users/alice/photos/image.png
format: png
Format conversion
-s format <type> rewrites the image in a different container and codec; use --out to write to a new file and leave the original intact. sips supports the formats listed below; HEIF output requires macOS 10.13 or later.
sips -s format jpeg image.png --out output.jpg # PNG → JPEG
sips -s format png image.jpg --out output.png # JPEG → PNG
sips -s format tiff image.jpg --out output.tiff # → TIFF
sips -s format gif image.png --out output.gif # → GIF
sips -s format bmp image.png --out output.bmp # → BMP
sips -s format pdf image.png --out output.pdf # → PDF (single page)
sips -s format heif image.jpg --out output.heif # → HEIF/HEIC
# Supported output formats:
# jpeg | tiff | png | gif | jp2 | pict | bmp | qtif | psd | sgi | tga | pdf | heif
Output: (none — exits 0 on success)
JPEG quality
-s formatOptions controls compression when the output format is JPEG (or JP2). Pass an integer from 0 to 100 or one of the named presets; lower values produce smaller files with more visible artifacts, higher values retain more detail at the cost of file size.
sips -s format jpeg -s formatOptions 80 image.png --out out.jpg # 80% quality
sips -s format jpeg -s formatOptions 50 image.png --out out.jpg # 50% (smaller)
sips -s format jpeg -s formatOptions best image.png --out out.jpg # best quality
sips -s format jpeg -s formatOptions low image.png --out out.jpg # low quality
# formatOptions values: 0-100 integer, or: low | normal | high | best | lzw | packbits
Output: (none — exits 0 on success)
Resize
-Z <n> fits the image within an n×n bounding box while preserving the aspect ratio — the most common resize operation. For independent control of width or height, use --resampleWidth or --resampleHeight; for an exact pixel size that may distort, use --resampleHeightWidth.
# Fit within a bounding box (preserves aspect ratio)
sips -Z 800 image.png # fit within 800×800, in-place
sips -Z 800 image.png --out resized.png # save to new file
# Set exact pixel width (height scales proportionally)
sips --resampleWidth 1200 image.png --out wide.png
# Set exact pixel height (width scales proportionally)
sips --resampleHeight 600 image.png --out tall.png
# Set exact dimensions (may distort aspect ratio)
sips --resampleHeightWidth 600 800 image.png --out exact.png
# Set exact dimensions, constrained (no distortion)
sips --resampleHeightWidthMax 600 800 image.png --out fitted.png
# Resize to a percentage of original size
sips --resampleWidth $(sips -g pixelWidth image.png | awk '{print int($2 * 0.5)}') image.png
Output: (none — exits 0 on success)
Crop
-c height width trims the image to the given dimensions, anchored at the top-left corner. sips does not support center-cropping natively; for that, combine with AppleScript or use ImageMagick's gravity Center -extent.
# Crop to exact dimensions from top-left
sips -c 400 600 image.png # crop to 400px tall × 600px wide (h w order)
# Crop and save to new file
sips -c 400 600 image.png --out cropped.png
# Crop a region: -c height width (from the top-left corner)
sips -c 300 500 image.png --out banner.png
Output: (none — exits 0 on success)
Rotate & flip
-r <degrees> rotates clockwise; pass a negative value for counter-clockwise rotation. -f horizontal mirrors left-right; -f vertical flips top-to-bottom. Both flags can be chained with resize or format conversion in a single command.
sips -r 90 image.png # rotate 90° clockwise
sips -r 180 image.png # rotate 180°
sips -r 270 image.png # rotate 270° clockwise (= 90° CCW)
sips -r -90 image.png # rotate 90° counter-clockwise
sips -f horizontal image.png # flip horizontally (mirror)
sips -f vertical image.png # flip vertically
# Combine: rotate then flip
sips -r 90 -f horizontal image.png --out result.png
Output: (none — exits 0 on success)
Color profiles & color space
-m <profile.icc> converts pixel data to match a target ICC profile, which is essential when preparing images for print or ensuring consistent web color. -e strips any embedded profile without converting, producing a raw file that assumes sRGB in most viewers.
# Match to a profile
sips -m /System/Library/ColorSync/Profiles/sRGB\ Profile.icc image.png
# List available profiles
ls /System/Library/ColorSync/Profiles/
# Strip profile (embed none)
sips -e image.png # embed no profile
# Set color space
sips --setProperty colorSpace "RGB" image.png
sips --setProperty colorSpace "Gray" image.png
# Convert to sRGB (common web workflow)
sips -m /System/Library/ColorSync/Profiles/sRGB\ Profile.icc \
-s format jpeg image.png --out web.jpg
Output: (none — exits 0 on success)
Padding
-p height width extends the canvas to the specified dimensions, centering the original image and filling the added area with white. Use this to create letterbox or pillarbox effects, or to make an image square without cropping.
# Add equal padding (canvas extension)
sips -p 200 300 image.png # pad to 200×300 (h w); fills with white
sips -p 500 500 image.png --out padded.png
Output: (none — exits 0 on success)
Batch processing
Wrap sips in a shell for loop or pipe find output into while read to process entire directories at once. When --out points to an existing directory, sips preserves original filenames — use that pattern to keep the source folder untouched.
# Convert all HEIC to JPEG in current directory
for f in *.heic; do
sips -s format jpeg "$f" --out "${f%.heic}.jpg"
done
# Convert all HEIC to JPEG (case-insensitive)
for f in *.HEIC *.heic; do
[[ -f "$f" ]] && sips -s format jpeg "$f" --out "${f%.*}.jpg"
done
# Resize all PNG files to max 1200px (in-place)
for f in *.png; do sips -Z 1200 "$f"; done
# Resize all images, save to a resized/ subdirectory
mkdir -p resized
for f in *.jpg *.jpeg *.png; do
[[ -f "$f" ]] && sips -Z 800 "$f" --out "resized/$f"
done
# Convert all PNG in a folder to JPEG at 85% quality
for f in *.png; do
sips -s format jpeg -s formatOptions 85 "$f" --out "${f%.png}.jpg"
done
# Process every image inside a directory tree
find . -iname "*.png" | while read f; do
sips -Z 1920 "$f"
done
# Get dimensions of every image in a folder
for f in *.png *.jpg; do
[[ -f "$f" ]] && echo "$f: $(sips -g pixelWidth -g pixelHeight "$f" | tail -2 | awk '{printf $2" "}')"
done
Output: (none — exits 0 on success)
Combine operations
# Resize + convert + quality in one pass
sips -Z 1200 -s format jpeg -s formatOptions 85 input.png --out output.jpg
# Rotate + resize + convert
sips -r 90 -Z 800 -s format jpeg input.heic --out output.jpg
# Crop + convert
sips -c 900 1200 -s format png input.jpg --out thumb.png
Output: (none — exits 0 on success)
Metadata manipulation
--setProperty writes individual metadata fields such as DPI directly into the file. Note that sips does not strip EXIF data (GPS, camera model, etc.) — for full EXIF removal use exiftool; sips handles only the properties it exposes via -g.
# Remove all metadata (strip EXIF, profiles)
sips -e image.jpg # strip color profile
# For full EXIF strip, use exiftool (brew install exiftool)
# Set DPI
sips --setProperty dpiWidth 72 --setProperty dpiHeight 72 image.png
sips --setProperty dpiWidth 300 --setProperty dpiHeight 300 image.tiff
# Set description / title (limited support)
sips --setProperty description "My Image" image.png
Output: (none — exits 0 on success)
Output directory
# --out can be a file or a directory
sips -Z 800 image.png --out resized.png # specific filename
sips -Z 800 *.png --out ./resized/ # all PNGs into a dir
# When --out is a dir, filenames are preserved
Output: (none — exits 0 on success)
Common recipes
# Prepare images for web (resize + sRGB + JPEG 85%)
for f in *.png *.jpg; do
[[ -f "$f" ]] && sips -Z 1920 \
-s format jpeg -s formatOptions 85 \
-m /System/Library/ColorSync/Profiles/sRGB\ Profile.icc \
"$f" --out "web/${f%.*}.jpg"
done
# Create square thumbnails (crop to center then resize)
# Note: sips crops from top-left; center-crop needs AppleScript or ImageMagick
sips -c 800 800 image.jpg --out square.jpg
# Check if image has alpha channel (useful in scripts)
has_alpha=$(sips -g hasAlpha "$f" | awk '/hasAlpha/{print $2}')
[[ "$has_alpha" == "yes" ]] && echo "Has alpha: $f"
# Batch rename + convert
i=1
for f in *.heic; do
sips -s format jpeg "$f" --out "photo_$(printf "%03d" $i).jpg"
((i++))
done
# Reduce screenshot size for sharing
sips -Z 1280 -s format jpeg -s formatOptions 75 screenshot.png --out screenshot_small.jpg
# Convert sRGB PNG to print-ready 300 DPI TIFF
sips --setProperty dpiWidth 300 --setProperty dpiHeight 300 \
-s format tiff image.png --out print.tiff
Output: (none — exits 0 on success)
Quick reference — property names
| Property | Description |
|---|---|
pixelWidth | Width in pixels |
pixelHeight | Height in pixels |
dpiWidth | Horizontal DPI |
dpiHeight | Vertical DPI |
colorSpace | RGB, Gray, CMYK, etc. |
bitsPerSample | Bit depth (8, 16, …) |
samplesPerPixel | Channels (3=RGB, 4=RGBA) |
hasAlpha | yes / no |
format | jpeg, png, tiff, heif, … |
formatOptions | Quality / compression |
profile | Embedded ICC profile name |
Quick reference — flags
| Flag | Description |
|---|---|
-g prop | Get property value |
-s prop val | Set property value |
-Z n | Fit within n×n (preserves ratio) |
--resampleWidth n | Set width, scale height |
--resampleHeight n | Set height, scale width |
--resampleHeightWidth h w | Exact size (may distort) |
-c h w | Crop to h×w from top-left |
-r deg | Rotate (90/180/270/-90) |
-f dir | Flip (horizontal/vertical) |
-p h w | Pad canvas to h×w |
-m profile.icc | Match color profile |
-e | Strip embedded profile |
--out path | Output file or directory |
Format conversion matrix
sips invokes CoreImage and ImageIO under the hood, so the supported output container set tracks the Image I/O codecs that ship with the current macOS version. HEIF/HEIC writing arrived in macOS 10.13 (High Sierra), and the modern set on macOS 14+ adds WebP read support. The keyword you pass to -s format or --setProperty format is pinned in the table below.
| Keyword | Container | R/W | Typical use |
|---|---|---|---|
jpeg | JFIF / JPEG | R+W | Photographs, web delivery |
jpeg-2000 | JPEG 2000 | R+W | Niche scientific / medical |
png | PNG | R+W | Lossless screenshots, UI assets, alpha |
tiff | TIFF | R+W | Print, archival, layered scans |
gif | GIF | R+W | Animated and palette-limited graphics |
bmp | Windows Bitmap | R+W | Legacy interop, embedded systems |
pdf | PDF (one page) | R+W | Single-page document export |
heif | HEIF / HEIC | R+W (10.13+) | iPhone-format photos, ~½ of JPEG |
psd / sgi / tga / pict / qtif | various legacy | R+W | Niche editor / engine handoff |
webp | WebP | R only (14+) | Encode WebP with cwebp or ImageMagick |
raw (CR2, NEF, ARW, DNG) | camera RAW | R only | Inspect only — re-encode in Lightroom |
he / he-raw (TicoRAW) | High Efficiency RAW | R only (Tahoe 26.4+) | Native decode of intoPIX TicoRAW captures; re-encode required for distribution |
# Discover what sips will accept on the current macOS
sips -h 2>&1 | sed -n '/format/,/}/p' | head -20
# Convert any image to every distributable format in one loop
for fmt in jpeg png tiff heif gif bmp pdf; do
ext=${fmt/jpeg/jpg}
ext=${ext/heif/heic}
sips -s format "$fmt" hero.png --out "hero.$ext"
done
# --setProperty format is interchangeable with -s format
sips --setProperty format jpeg hero.png --out hero.jpg
sips -s formatOptions 90 -s format jpeg hero.png --out hero.jpg
# Verify the written format matches the requested one
sips -g format hero.heic
Output:
/Users/alice/Pictures/hero.heic
format: heic
The keyword heic is what sips -g format reports when reading an HEIF container — but the keyword you pass to -s format is heif. That asymmetry trips up scripts that try to round-trip the value. The same goes for jpeg-2000 vs the .jp2 file extension. The file extension you append after --out is purely cosmetic; sips writes the format you specified in -s format, not the format implied by the extension.
Resize semantics
The five resize flags differ in two dimensions: which axes they pin, and whether they refuse to upscale. Get this wrong once and you ship a feed of 32 px thumbnails because a single source image was already smaller than the cap. The decision tree:
| Flag | Pins | Upscales? | Distorts? | When to reach for it |
|---|---|---|---|---|
-Z N | Both axes within N×N | yes (will enlarge to fit) | no | "Make this image fit a box" — most common |
-z H W | Both axes within H×W | yes | no | Non-square bounding box |
--resampleWidth N | Width = N, height scales | yes | no | "Make this 1200 px wide" — exact width control |
--resampleHeight N | Height = N, width scales | yes | no | "Make this 600 px tall" |
--resampleHeightWidth H W | Exact H×W | yes | yes | When you need an exact pixel grid and accept stretching |
--resampleHeightWidthMax H W | Both axes within H×W | yes | no | Like -z but lets you express the cap as max H and max W independently |
# Original is 4000×3000
sips -g pixelWidth -g pixelHeight portrait.jpg
Output:
/Users/alice/Pictures/portrait.jpg
pixelWidth: 4000
pixelHeight: 3000
# -Z 1200: fits within 1200×1200 → 1200×900 (aspect kept, height computed)
sips -Z 1200 portrait.jpg --out fit-1200.jpg
sips -g pixelWidth -g pixelHeight fit-1200.jpg | tail -2
# -z 600 1200: fit within 600 tall × 1200 wide → 1200×900 then capped to 600×800?
# No — sips computes the largest box-respecting result: 800×600
sips -z 600 1200 portrait.jpg --out fit-box.jpg
sips -g pixelWidth -g pixelHeight fit-box.jpg | tail -2
# --resampleWidth 1200: width pinned, height proportional → 1200×900
sips --resampleWidth 1200 portrait.jpg --out width-1200.jpg
# --resampleHeightWidth 600 800: stretched to exactly 600×800 (aspect lost!)
sips --resampleHeightWidth 600 800 portrait.jpg --out stretched.jpg
sips -g pixelWidth -g pixelHeight stretched.jpg | tail -2
Output:
pixelWidth: 1200
pixelHeight: 900
pixelWidth: 800
pixelHeight: 600
pixelWidth: 800
pixelHeight: 600
Avoiding upscale
None of the sips resize flags have a built-in "shrink only" guard the way ImageMagick's 1920x1080> geometry suffix does. To avoid upscaling small images, read the current size and short-circuit:
shrink_only() {
local file=$1 cap=$2
local w=$(sips -g pixelWidth "$file" | awk '/pixelWidth/{print $2}')
local h=$(sips -g pixelHeight "$file" | awk '/pixelHeight/{print $2}')
if (( w > cap || h > cap )); then
sips -Z "$cap" "$file" --out "${file%.*}-resized.${file##*.}"
else
cp "$file" "${file%.*}-resized.${file##*.}"
fi
}
shrink_only large.jpg 1920 # actually resizes
shrink_only thumb.png 1920 # just copies
Output: (none — exits 0 on success)
Resampling algorithm
sips does not expose a -filter choice the way ImageMagick does. It uses Lanczos resampling via CoreImage on every resize, which is appropriate for photographs but slightly blurrier than nearest-neighbor for pixel art. If you need nearest-neighbor (for sprites, icons, or screenshots of CRT effects), reach for ImageMagick's -sample or -scale instead.
Crop, pad, rotation in depth
-c, -p, and -r look symmetric but the corner from which they operate differs and the fill colour behaves differently. Crop anchors at the top-left; pad anchors at the center; rotation pivots around the geometric center and fills out-of-frame corners with the pad colour.
Crop anchor and --cropOffset
-c h w is implicitly anchored at (0, 0). Some macOS versions accept --cropOffset y x to move that anchor — verify with sips -h | grep -i crop before relying on it in scripts, because the flag was undocumented in earlier releases.
# Top-left default
sips -c 600 800 source.jpg --out top-left.jpg
# Center crop is not native — compute the offset manually
W=$(sips -g pixelWidth source.jpg | awk '/pixelWidth/{print $2}')
H=$(sips -g pixelHeight source.jpg | awk '/pixelHeight/{print $2}')
CW=800; CH=600
OX=$(( (W - CW) / 2 ))
OY=$(( (H - CH) / 2 ))
# Crop with explicit offset (newer sips)
sips -c "$CH" "$CW" --cropOffset "$OY" "$OX" source.jpg --out center.jpg
Output: (none — exits 0 on success)
--padColor
The default fill colour for -p and for the corners that appear during a non-multiple-of-90 rotation is white. Pass --padColor RRGGBB (hex, no #) to override.
# Pad to 1200×1200 with a black background
sips -p 1200 1200 --padColor 000000 portrait.jpg --out square-black.jpg
# Brand-colour padding for social posters
sips -p 630 1200 --padColor 8a5cff hero.png --out og.png
# Letterbox a 16:9 image inside a 1:1 canvas (vertical bars)
sips -p 1080 1080 --padColor 0a0a0f wide.jpg --out square-bars.jpg
Output: (none — exits 0 on success)
Rotation pad colour
Rotating by a non-cardinal angle (anything other than 90/180/270) creates triangular gaps in the four corners. sips fills those with white by default and with --padColor when supplied.
sips -r 15 --padColor 0a0a0f photo.jpg --out tilted.jpg
sips -r 7 --padColor ffffff scan.jpg --out deskewed.jpg
Output: (none — exits 0 on success)
The default rotation is destructive — pixels are clipped to fit the new bounding box and the canvas expands to contain the rotated content. There is no equivalent of ImageMagick's +distort SRT for arbitrary affine transforms; if you need that, drop down to magick or to osascript driving Image Events.
EXIF, ICC, and ColorSync metadata
sips exposes a subset of EXIF, IPTC, and ICC-profile fields via the property accessors. It does not expose the full EXIF block (no GPS, no lens metadata, no camera-make custom tags). For full EXIF you still need exiftool. But for the fields it does expose, sips has the advantage of being preinstalled, ColorSync-aware, and atomic with format conversion.
Reading metadata
# Every property sips knows about
sips -g all photo.jpg
# Discrete property reads
sips -g make -g model photo.jpg # camera make/model
sips -g creation -g software photo.jpg # capture date, capturing software
sips -g profile -g profileName photo.jpg # ICC profile, profile name
sips -g description -g copyright photo.jpg # IPTC fields when present
Output:
/Users/alice/Pictures/photo.jpg
make: Apple
model: iPhone 15 Pro
creation: 2026:05:24 14:02:11
software: 17.5
profile: Display P3
profileName: Display P3
description: Sunset over the bay
Writing metadata
-s prop value and --setProperty prop value write a single property. -d prop and --deleteProperty prop remove a property without touching anything else.
# Set DPI (no resampling — just changes the recorded resolution)
sips --setProperty dpiWidth 300 --setProperty dpiHeight 300 print.tif
# Tag with an IPTC description
sips --setProperty description "Q2 launch hero" --setProperty copyright "© 2026 Alice Dev" hero.jpg
# Remove a single property
sips --deleteProperty description photo.jpg
# Strip every property sips can address (best-effort EXIF strip)
for prop in description copyright make model software; do
sips --deleteProperty "$prop" photo.jpg 2>/dev/null
done
Output: (none — exits 0 on success)
--deleteProperty is silently ignored if the property is not currently set on the image — no error, exit code 0. That makes it safe to chain across a batch of mixed-source files.
ICC profile management
ICC profiles describe how pixel values map to a colour space. -m profile.icc re-renders pixels into the target colour space; --matchTo is the documented long form (older versions only supported -m). --embedProfile switches whether the converted profile is embedded into the file. -e strips any embedded profile without converting.
# Convert from Display P3 (iPhone) to sRGB (web) — re-renders pixels
sips -m /System/Library/ColorSync/Profiles/sRGB\ Profile.icc \
photo-p3.heic --out photo-srgb.jpg
# Or with the long-form name
sips --matchTo /System/Library/ColorSync/Profiles/sRGB\ Profile.icc \
photo-p3.heic --out photo-srgb.jpg
# Match to profile but do NOT embed it (saves bytes for sRGB-by-convention web pipelines)
sips -m /System/Library/ColorSync/Profiles/sRGB\ Profile.icc \
--embedProfile 0 photo.jpg --out web.jpg
# Strip profile without converting (assumes the viewer will interpret as sRGB)
sips -e photo.jpg --out raw.jpg
# Where ColorSync profiles live
ls /System/Library/ColorSync/Profiles/ | head -10
ls ~/Library/ColorSync/Profiles/ 2>/dev/null
ls /Library/ColorSync/Profiles/ 2>/dev/null
Output:
AdobeRGB1998.icc
DCI(P3) RGB.icc
Display P3.icc
Generic CMYK Profile.icc
Generic Gray Gamma 2.2 Profile.icc
Generic RGB Profile.icc
ITU-2020.icc
ITU-R 2020.icc
ProPhoto.icc
ROMM RGB.icc
--embedProfile 0 is a common space-saving step for web JPEGs once you've already converted to sRGB — most browsers assume sRGB when no profile is present, so the embedded sRGB IEC61966-2.1 profile adds ~3 kB per image with no visual benefit.
Image properties reference
The complete set of properties that sips -g reads. The "Write" column marks the ones -s prop value and --setProperty prop value can also modify. Not every property is settable on every format — dpiWidth/dpiHeight are honoured by TIFF/PNG/JPEG but ignored by HEIC.
| Property | Read | Write | Description |
|---|---|---|---|
pixelWidth / pixelHeight | yes | no | Pixel dimensions (use resize flags to change) |
dpiWidth / dpiHeight | yes | yes | Print-resolution metadata (does not resample) |
typeIdentifier | yes | no | UTI, e.g. public.png, public.jpeg |
format / formatOptions | yes | yes | Output container + quality/preset |
space / samplesPerPixel / bitsPerSample | yes | no | Colour space, channel count, bit depth |
hasAlpha | yes | no | Whether the image has an alpha channel |
profile / profileName | yes | no | Embedded ICC profile (set via -m profile.icc) |
make / model / software | yes | yes | EXIF camera + capturing-software fields |
creation | yes | yes | Capture timestamp, YYYY:MM:DD HH:MM:SS |
description / copyright / artist | yes | yes | IPTC/EXIF text fields |
# Pull a single value programmatically (property name is the second token)
WIDTH=$(sips -g pixelWidth photo.jpg | awk '/pixelWidth/{print $2}')
HEIGHT=$(sips -g pixelHeight photo.jpg | awk '/pixelHeight/{print $2}')
echo "Aspect: $(echo "scale=4; $WIDTH/$HEIGHT" | bc)"
Output:
Aspect: 1.7778
HEIC and HEIF specifics
HEIF (High Efficiency Image Format) is the ISO container; HEIC is the macOS file-extension flavour using H.265-encoded image data. iPhones from the iPhone 7 onward default to capturing in HEIC and the files are roughly half the size of the JPEG equivalent at the same visual quality.
# Inspect: HEIC files have ten-thousand-foot identical sips output to JPEG
sips -g format -g pixelWidth -g pixelHeight IMG_4521.heic
Output:
/Users/alice/Pictures/IMG_4521.heic
format: heic
pixelWidth: 4032
pixelHeight: 3024
# Convert HEIC → JPEG (most common interop step)
sips -s format jpeg -s formatOptions 90 IMG_4521.heic --out IMG_4521.jpg
# JPEG → HEIC (rare, but useful for re-archiving)
sips -s format heif old-photo.jpg --out old-photo.heic
# Note: the keyword is `heif` even though the extension is .heic
# Burst convert an iPhone-Photos export to web-friendly JPEG
mkdir -p web/
for f in *.HEIC *.heic; do
[[ -f "$f" ]] || continue
sips -s format jpeg -s formatOptions 85 "$f" --out "web/${f%.*}.jpg"
done
# HEIC quality is also driven by formatOptions (0–100)
sips -s format heif -s formatOptions 70 photo.jpg --out small.heic
# Strip the profile and re-encode HEIC for max compression
sips -e -s format heif -s formatOptions 60 photo.jpg --out tiny.heic
Output: (none — exits 0 on success)
HEIC limitations to remember: many non-Apple tools still cannot read HEIC; uploading HEIC to legacy CMSes will silently break thumbnails; HEIC does not support image sequences (live photos) — those are HEIF with multiple images, but sips only sees the primary image.
PDF rasterisation
sips can read a single page from a PDF and write it as a raster format. It does this by rasterising the first page only — multi-page PDFs collapse to one frame. If you need every page, ImageMagick (magick -density 150 doc.pdf out-%d.png) or pdftoppm are better choices.
# Single-page PDF → PNG (first page only)
sips -s format png document.pdf --out page-1.png
# Specify dimensions (sips will set the raster size, not the PDF page DPI)
sips -s format png -Z 2400 document.pdf --out page-large.png
# PDF → JPEG at 85% quality
sips -s format jpeg -s formatOptions 85 receipt.pdf --out receipt.jpg
# Inspect a PDF (sips reports the first page's dimensions)
sips -g pixelWidth -g pixelHeight document.pdf
Output:
/Users/alice/Documents/document.pdf
pixelWidth: 612
pixelHeight: 792
The 612×792 result is the PDF page expressed at the default 72 DPI (8.5×11 inches × 72 = 612×792). If you need a higher-DPI raster from a PDF, either upscale with -Z (lossy) or use pdftoppm -r 300 input.pdf out to rasterise at the source resolution.
When to choose sips vs ImageMagick vs ffmpeg
The three tools overlap heavily, but each has a sweet spot. The cheat-sheet below summarises when each one is the right answer; sips is rarely the most powerful tool but it's almost always the fastest to reach for on macOS because it requires no install.
| Need | Best tool | Why |
|---|---|---|
| Convert HEIC → JPEG on macOS | sips | Preinstalled; CoreImage-native HEIC decode |
| Batch resize a dozen photos | sips -Z | One-line shell loop |
| Read EXIF date/camera | sips -g (limited) or exiftool (complete) | sips covers basics with zero install |
| Strip ColorSync profile | sips -e | Built-in, no install |
| Generate thumbnails on a CI runner | depends | If the runner is macOS use sips; on Linux use ImageMagick |
| Rich filters (blur, sharpen, sepia) | magick | sips has no -blur or -sharpen |
| Drawing / annotation / text overlay | magick | sips cannot draw |
| Animated GIF frames | ffmpeg | sips is single-frame only |
| Frames from a video → images | ffmpeg | sips cannot decode video |
| 200+ formats including SVG / WebP write | magick | sips writes ~12 formats; no WebP write |
| Multi-page PDF rasterise | magick or pdftoppm | sips reads only the first page |
| RAW photo handling | none of these | use Lightroom, RawTherapee, or dcraw |
| Strip every byte of EXIF/IPTC/XMP | exiftool -all= | sips only addresses a handful of fields |
# The same task — JPEG → PNG — in all three tools
sips -s format png input.jpg --out output.png # macOS only
magick input.jpg output.png # cross-platform
ffmpeg -loglevel quiet -y -i input.jpg output.png # also possible
# Add a watermark — only ImageMagick can do this in one command
magick input.jpg -gravity SouthEast -fill white -pointsize 24 \
-annotate +10+10 "© Alice Dev" output.jpg
Output: (none — exits 0 on success)
Cross-link: imagemagick for the heavy-duty work; ffmpeg for animation/video frames.
Automator, Shortcuts, and Folder Actions
sips is the canonical CLI Apple bundles with macOS, so Automator's "Run Shell Script" action and Shortcuts' "Run Shell Script" action both call it natively. The pattern is the same in both: receive files from Finder as positional arguments, then loop over them invoking sips.
#!/bin/bash
# Quick Action / Shortcut body — resize selected images to 1920 px in place
# In Automator: New → Quick Action → Run Shell Script, "Pass input: as arguments"
# In Shortcuts: Run Shell Script, "Input: as arguments"
for f in "$@"; do
/usr/bin/sips -Z 1920 "$f"
done
Output: (none — exits 0 on success)
Folder Action variant — auto-process every image dropped into ~/Pictures/Drop Here/:
#!/bin/bash
DEST=~/Pictures/Resized/
mkdir -p "$DEST"
for f in "$@"; do
base=$(basename "$f")
/usr/bin/sips -Z 1920 -s format jpeg -s formatOptions 85 \
"$f" --out "$DEST/${base%.*}.jpg"
done
Output: (none — exits 0 on success)
Open Automator → New Folder Action → choose the watched folder → add "Run Shell Script" → paste body → save.
AppleScript and osascript
The Image Events scripting addition exposes the same Core Image plumbing that sips uses, but with object-oriented control over orientation, embedded profile, and metadata. Reach for AppleScript when sips falls short — for example, center-cropping with computed anchors.
-- center-crop.applescript
on run argv
set inputPath to item 1 of argv
set outputPath to item 2 of argv
tell application "Image Events"
launch
set theImage to open POSIX file inputPath
copy dimensions of theImage to {w, h}
set side to (the smaller of w and h)
crop theImage to dimensions {side, side}
save theImage in POSIX file outputPath as JPEG
close theImage
end tell
end run
osascript center-crop.applescript ~/Pictures/wide.jpg ~/Pictures/square.jpg
# Inline — list every image in Photos that is wider than 4000 px
osascript -e 'tell application "Photos" to get filename of (every media item whose pixel width > 4000)'
Output:
IMG_0142.jpeg, IMG_0188.heic, panorama-2025-04.jpg, IMG_0421.heic
Cross-link to macos-cli for the broader shell-driving-AppleScript story.
Performance and parallelism
sips is single-threaded per invocation but a typical M-series Mac will happily run 8–16 concurrent processes. The bottleneck for batch jobs is usually CPU on HEIC/HEIF and I/O on JPEG re-encode.
# Serial loop — slow
time for f in *.heic; do
sips -s format jpeg -s formatOptions 85 "$f" --out "out/${f%.heic}.jpg"
done
# real 0m38.214s
# Parallel with GNU parallel (brew install parallel) — ~6× faster
time ls *.heic | parallel -j 8 \
'sips -s format jpeg -s formatOptions 85 {} --out "out/{.}.jpg"'
# real 0m6.812s
# Parallel with xargs (preinstalled — NUL-safe for weird filenames)
find . -name '*.heic' -print0 | \
xargs -0 -n 1 -P 8 -I {} \
sips -s format jpeg -s formatOptions 85 {} --out "{}.jpg"
Output: (none — exits 0 on success)
On an M2 Pro: 6-second wall time vs 38 serial — a ~6× speedup at -P 8. Pure CPU-bound HEIC decoding scales near-linearly; JPEG re-encode at 85% quality is largely I/O bound on SSDs and the gain levels off after -P 4.
In-place vs --out: the clobber rule
sips defaults to in-place modification when --out is omitted. This is the single most common mistake — accidentally destroying originals because the script left off the flag. Two safe patterns:
# Pattern 1: always pass --out (recommended)
sips -Z 800 photo.png --out photo-thumb.png # preserves photo.png
# Pattern 2: pass --out as a directory; sips preserves the original filename
mkdir -p resized
sips -Z 800 *.png --out resized/
# Confirm the original is untouched
diff -q photo.png photo-original.png && echo "unchanged"
Output:
/Users/alice/Pictures/photo.png
/Users/alice/Pictures/photo-thumb.png
unchanged
When --out is omitted, sips silently overwrites the input with no confirmation and no recovery — there is no -i interactive prompt. Build defensively: always pass --out even when the new file is going next to the original.
# Multi-output destination behaviour
# 1. --out is a non-existent path with an extension → that's the new filename
sips -Z 800 a.png --out resized.png # writes resized.png
# 2. --out is an existing directory → preserves the input filename inside it
sips -Z 800 a.png --out resized/ # writes resized/a.png
# 3. --out has a non-image extension or unwritable path → exits non-zero
sips -Z 800 a.png --out /no/such/dir/r.png ; echo "exit=$?"
Output:
Error: cannot create output file /no/such/dir/r.png
exit=1
Common pitfalls
- In-place by default — omitting
--outoverwrites the source. There is no undo. Wrap every destructive command behind--outeven when the output should live next to the original, and back up yourOriginals/folder before any first batch run. -c h worder is height first, width second — opposite of CSS, opposite ofWIDTH × HEIGHTnotation everywhere else. The same goes for-p h wand--resampleHeightWidth h w. Test on one file before unleashing the loop on a thousand.-z(lowercase) vs-Z(uppercase) —-Z Ncaps both axes at N;-z H Wcaps within an H×W box. Different glyphs, very different semantics.- EXIF orientation traps — phone photos store landscape pixel data with an EXIF
Orientation=6tag for "rotate 90 CW on display".sipsdoes not auto-orient on resize, so a portrait-mode iPhone photo run throughsips -Z 1920will produce a sideways thumbnail. Either pre-rotate withsips -rbased on the orientation tag, or pipe through ImageMagick's-auto-orientfirst. -s format heifvsformat: heicon read — the keyword you write isheif; the valuesips -g formatreports isheic. Scripts that round-trip the value need a map.--deletePropertydoes not actually strip EXIF GPS —sipsonly knows about properties it exposes via-g. GPS, lens MakerNotes, and XMP blocks pass through untouched. Useexiftool -all=for a full EXIF wipe before publishing photos with location metadata.- JPEG quality field is named
formatOptions, notquality—sips --setProperty quality 85silently does nothing; the correct invocation is-s formatOptions 85. --padColortakes hex without#—--padColor #000000errors out;--padColor 000000works.- Center-crop is not native —
-c h walways anchors at top-left. Either compute--cropOffsetmanually, or fall back to AppleScript Image Events. - RAW files are read-only —
sipscan-g alla.CR2or.NEFbut cannot convert it. Re-encode RAW withdcrawor in Lightroom first. - WebP write is not supported — read works on macOS 14+, but
sips -s format webpsilently ignores the request and writes the source format. Usecwebpfrombrew install webpfor WebP output. - ColorSync defaults are surprising —
sips -s format jpeg input.png --out output.jpgdoes not drop alpha; PNG's alpha channel maps to JPEG's white background by default but the embedded profile is preserved. Pass-eto drop the profile if you want a truly bare JPEG. sips -Z 0 file.jpgis a foot-gun — caps "within 0×0" which sips interprets as "scale to one pixel". Always validate inputs.- Multiple
-sflags on the same property — only the last one takes effect.sips -s formatOptions 50 -s formatOptions 90 in.jpg --out out.jpgwrites at 90. - Glob expansion with HEIC — Finder names files
.HEIC(uppercase).for f in *.heicmisses them on a case-sensitive filesystem. Use*.heic *.HEICorfind . -iname '*.heic'. - Quoted paths with spaces —
--out "/Users/alice/My Photos/out.jpg"works; bare paths do not. Always double-quote the input and--outarguments.
Real-world recipes
Web-resize an entire blog asset folder
The most common batch: walk blog/assets/, produce 1920-wide JPEGs at 85% quality with sRGB profile, into a sibling blog/dist/ folder.
SRC=$HOME/Sites/blog/assets
DST=$HOME/Sites/blog/dist
SRGB=/System/Library/ColorSync/Profiles/sRGB\ Profile.icc
find "$SRC" -type f \( -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.heic' \) -print0 |
while IFS= read -r -d '' f; do
rel=${f#$SRC/}
out="$DST/${rel%.*}.jpg"
mkdir -p "$(dirname "$out")"
sips -Z 1920 \
-m "$SRGB" \
-s format jpeg -s formatOptions 85 \
--embedProfile 0 \
"$f" --out "$out" >/dev/null
done
echo "Done. Output:"
find "$DST" -type f | wc -l
Output:
Done. Output:
142
Generate a multi-resolution favicon set
Apps, websites, and PWAs need a stack of icon sizes. sips produces every size from a single high-res source in one loop.
SRC=icon-source.png # ideally 1024×1024
mkdir -p icons
for size in 16 32 48 64 96 128 192 256 384 512 1024; do
sips -Z "$size" "$SRC" --out "icons/icon-${size}.png" >/dev/null
done
ls -la icons/
Output:
-rw-r--r-- 1 alice staff 1207 May 25 14:02 icon-16.png
-rw-r--r-- 1 alice staff 1924 May 25 14:02 icon-32.png
-rw-r--r-- 1 alice staff 2840 May 25 14:02 icon-48.png
-rw-r--r-- 1 alice staff 3711 May 25 14:02 icon-64.png
-rw-r--r-- 1 alice staff 5402 May 25 14:02 icon-96.png
-rw-r--r-- 1 alice staff 7011 May 25 14:02 icon-128.png
-rw-r--r-- 1 alice staff 11823 May 25 14:02 icon-192.png
-rw-r--r-- 1 alice staff 16245 May 25 14:02 icon-256.png
-rw-r--r-- 1 alice staff 27214 May 25 14:02 icon-384.png
-rw-r--r-- 1 alice staff 41718 May 25 14:02 icon-512.png
-rw-r--r-- 1 alice staff 109523 May 25 14:02 icon-1024.png
For a full macOS .icns you still need iconutil, but the input is a folder of icon_NxN.png and icon_NxN@2x.png images — exactly what this loop produces.
Strip EXIF before publishing
Privacy-conscious blog post: remove location, camera model, and software signature before uploading.
strip_exif() {
local f=$1 out=${1%.*}-clean.${1##*.}
# First convert through a re-encode to discard most EXIF
sips -s format jpeg -s formatOptions 90 "$f" --out "$out" >/dev/null
# Then explicitly delete properties sips can address
for prop in description copyright make model software artist creation; do
sips --deleteProperty "$prop" "$out" 2>/dev/null
done
# Finally strip ColorSync profile (privacy via fingerprint resistance)
sips -e "$out" >/dev/null
}
strip_exif vacation.heic
sips -g all vacation-clean.jpg | grep -vE 'pixelWidth|pixelHeight|format|space|samplesPerPixel|bitsPerSample|hasAlpha|profile'
Output:
/Users/alice/Pictures/vacation-clean.jpg
(All other properties stripped. For a truly forensic-grade wipe, follow with exiftool -all= vacation-clean.jpg.)
Convert iPhone HEIC export to JPEG with directory mirroring
Default iPhone exports are organised as Photos Library.photoslibrary/originals/0/0A1B/.... Mirror that into a flat dated structure.
SRC=$HOME/Pictures/iPhone\ Export
DST=$HOME/Pictures/Converted
find "$SRC" -iname '*.heic' -type f -print0 |
while IFS= read -r -d '' f; do
# Extract capture date from EXIF via sips
date=$(sips -g creation "$f" | awk '/creation:/{print $2}' | tr ':' '-')
out_dir="$DST/$date"
mkdir -p "$out_dir"
sips -s format jpeg -s formatOptions 90 \
"$f" --out "$out_dir/$(basename "${f%.heic}").jpg" >/dev/null
done
# Result: $DST/2026-05-24/IMG_4521.jpg, etc.
ls "$DST" | head -5
Output:
2026-05-21
2026-05-22
2026-05-23
2026-05-24
2026-05-25
Generate Open Graph 1200×630 from a hero image
The standard Open Graph image dimension is 1200×630 — neither a clean ratio of common camera output nor a clean ratio of phone screenshots. Two strategies: pad with a brand colour, or center-crop.
SRC=hero.png
# Strategy A: pad to 1200×630 with brand colour (keeps the whole hero visible)
sips -Z 1200 "$SRC" --out og-tmp.png >/dev/null
sips -p 630 1200 --padColor 0a0a0f og-tmp.png --out og-padded.png >/dev/null
rm og-tmp.png
# Strategy B: center-crop to 1200×630 (loses pixels at top/bottom)
W=$(sips -g pixelWidth "$SRC" | awk '/pixelWidth/{print $2}')
H=$(sips -g pixelHeight "$SRC" | awk '/pixelHeight/{print $2}')
# Compute the crop window
TARGET_W=1200; TARGET_H=630
SCALE_W=$(echo "scale=4; $TARGET_W / $W" | bc)
SCALE_H=$(echo "scale=4; $TARGET_H / $H" | bc)
# Pick the larger scale so both target dims fit
sips --resampleWidth 1800 "$SRC" --out og-tmp.png >/dev/null
sips -c 630 1200 og-tmp.png --out og-cropped.png >/dev/null
rm og-tmp.png
sips -g pixelWidth -g pixelHeight og-padded.png | tail -2
sips -g pixelWidth -g pixelHeight og-cropped.png | tail -2
Output:
pixelWidth: 1200
pixelHeight: 630
pixelWidth: 1200
pixelHeight: 630
Auto-orient phone photos by EXIF
iPhones store orientation in EXIF rather than rotating pixels. sips reads orientation but does not auto-apply it on resize. The recipe: read the property if present and apply the corresponding rotation.
auto_orient() {
local f=$1
# EXIF Orientation: 1=normal, 3=180, 6=90 CW, 8=270 CW
local orient=$(exiftool -s -s -s -Orientation -n "$f" 2>/dev/null)
case "$orient" in
3) sips -r 180 "$f" --out "${f%.*}-oriented.${f##*.}" ;;
6) sips -r 90 "$f" --out "${f%.*}-oriented.${f##*.}" ;;
8) sips -r 270 "$f" --out "${f%.*}-oriented.${f##*.}" ;;
1|"") cp "$f" "${f%.*}-oriented.${f##*.}" ;;
esac
}
for f in IMG_*.heic; do auto_orient "$f"; done
Output: (none — files written)
The cleaner cross-platform alternative is magick mogrify -auto-orient *.jpg, which combines the read-orientation and rotate-pixels steps into one. sips does not (yet) ship an equivalent flag.
Build a contact sheet from a folder
sips cannot create a montage on its own — the closest workaround is to resize every image to a thumbnail and rely on another tool to assemble. Below: thumbnail with sips, montage with magick.
mkdir -p thumbs
for f in shoot/*.heic; do
sips -Z 320 -s format jpeg -s formatOptions 80 \
"$f" --out "thumbs/$(basename "${f%.heic}").jpg" >/dev/null
done
# Compose into a 4-column contact sheet
magick montage thumbs/*.jpg -tile 4x -geometry 320x240+5+5 \
-background '#0a0a0f' -fill white \
contact-sheet.jpg
Output: (none — contact-sheet.jpg written)
Health check: scan a tree for corrupted or non-RGB images
A quick audit script that flags images that fail to decode (corrupted) or that have unusual properties (wrong colour space for the workflow).
ROOT=$HOME/Pictures
LOG=/tmp/image-audit.log
> "$LOG"
find "$ROOT" -type f \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.heic' \) -print0 |
while IFS= read -r -d '' f; do
out=$(sips -g format -g pixelWidth -g pixelHeight -g space "$f" 2>&1)
if [[ $? -ne 0 ]] || echo "$out" | grep -qi 'error'; then
echo "CORRUPT: $f" >> "$LOG"
continue
fi
space=$(echo "$out" | awk '/space:/{print $2}')
if [[ "$space" != "RGB" ]]; then
echo "NON-RGB ($space): $f" >> "$LOG"
fi
done
wc -l "$LOG"
head -10 "$LOG"
Output:
4 /tmp/image-audit.log
CORRUPT: /Users/alice/Pictures/old/IMG_1102.jpg
NON-RGB (Gray): /Users/alice/Pictures/scans/page-001.tif
NON-RGB (CMYK): /Users/alice/Pictures/print/cover.tif
NON-RGB (Gray): /Users/alice/Pictures/scans/page-002.tif
macOS Tahoe 26 — what changed for sips
macOS Tahoe 26.4 expanded the codec set that ImageIO (and therefore sips) can read but did not add new write-side formats. The headline addition is HE / HE RAW (intoPIX TicoRAW) decode, which lets sips -g all inspect TicoRAW captures from supported cameras and sips -s format jpeg re-encode them to JPEG for distribution. WebP write is still missing — sips -s format webp silently does nothing — and there is no JPEG XL or AVIF write support. Reach for cwebp, avifenc, or ImageMagick when you need those.
# Confirm whether the running sips can read TicoRAW
sips -g format capture.he 2>&1 | head -1
# Convert a TicoRAW capture to web-friendly JPEG (Tahoe 26.4+)
sips -s format jpeg -s formatOptions 90 capture.he --out capture.jpg
# Verify WebP write still silently fails — output stays as the source format
sips -s format webp logo.png --out logo.webp
sips -g format logo.webp | tail -1
Output:
/Users/alice/Pictures/capture.he
format: png
The format: png in the last line is the giveaway — sips ignored the -s format webp request and copied the source format through unchanged because no WebP encoder is registered. The same trap applies to avif and jxl. Apple has not announced a timeline for WebP/AVIF write support; if you need those, hand off to ImageMagick (magick input.png output.webp) or cwebp / avifenc directly.
Sources
SIPS Command reference — ss64.com macOS Tahoe 26.4 now supports HE / HE RAW — DPReview Forums How to Convert Images Between Formats on Mac (2026) — Zipic Blog macOS Tahoe 26 Release Notes — Apple Developer
See also
imagemagick— far richer image processing when sips runs out of features.ffmpeg— when you need to bridge from still frames to video or vice versa.macos-cli— broader macOS terminal reference includingosascript.codesign— bundled-with-macOS sibling for signing executables and apps.system_profiler— built-in macOS inventory tool with the same "no install required" ethos.exiftool(brew install exiftool) — when you need full EXIF/IPTC/XMP control beyond what sips exposes.