Image

pm-image: Fast image resizing for CLI, servers, and Windows Explorer

pm-image is a native C++ image toolkit built on libvips — the same high-performance engine behind tools like Sharp (Node.js). One binary gives you a command-line interface, an HTTP REST server, line-delimited JSON IPC for automation, and AI image editing via Gemini. On Windows, optional Explorer integration adds right-click resize and convert workflows without opening another app.

Whether you batch photos for the web, power a local resize API, or shrink folders of RAW and HEIC files from the desktop, pm-image keeps pipelines predictable: decode → process → encode, with Sharp-like options (fit modes, quality, metadata stripping, smart crop) and optional disk caching so repeat jobs stay instant.


Download - Windows - AMD 64 | Source Code

Who is this for?


How to resize images (quick start)

1. Command line — one file

Install or build pm-image, then run resize with input and output paths. By default, the image fits inside your max width and height without enlarging (unless you allow enlargement).

pm-image resize photo.jpg out.jpg --max-width 1920 --max-height 1080

2. Fit modes — not every resize is "shrink to fit"

Goal What to use
Fit inside a box (keep aspect ratio, no crop) Default behavior with --max-width / --max-height; optional --fit inside style semantics via fit in JSON.
Square avatar or thumbnail (crop) Same --max-width and --max-height (e.g. 512), --fit cover, optional --position attention or entropy for smarter crops.
Square with padding (no crop) --fit contain plus --background '#rrggbb' for letterboxing.
Exact dimensions by stretching --fit fill (distorts if aspect ratios differ).

Examples (see the package README for full flag lists):

# Thumbnail: 400×400 cover crop
pm-image resize in.jpg thumb.jpg --fit cover --max-width 400 --max-height 400

# Padded square on a dark canvas
pm-image resize wide.jpg square.jpg --fit contain --max-width 800 --max-height 800 --background '#111111'

3. Batch paths and folders

pm-image resize './photos/**/*.jpg' ./out/
pm-image resize --src './shots/*.jpg' --dst '${SRC_DIR}/${SRC_NAME}_medium.jpg' --max-width 800

4. HTTP API

Start the server (serve), then POST JSON to /v1/resize with input, output, and the same resize fields as the CLI (max_width, max_height, fit, quality, etc.). Paths must be readable and writable by the server process.

5. Windows — resize from Explorer

After pm-image register-explorer (or the NSIS installer), use the PM-Media menu on images or folders for preset widths, in place or copy, plus convert to JPG. Override preset widths with --widths when registering.

6. Optional: Windows GUI

On Windows, pm-image resize --ui opens a native dialog to pick files and options. pm-image resize --ui-next opens the newer Win32++ ribbon UI with a drag-drop queue and settings panel; optional --src or positional input paths pre-seed the queue.


AI image editing (transform)

The transform subcommand uses a generative-AI model (currently Google Gemini) to edit an image based on a text prompt. It reads the input, sends image + prompt to the API, and writes the result.

pm-image transform photo.jpg -p "remove the background"
pm-image transform photo.jpg out.png -p "make it black and white" --model gemini-3-pro-image-preview
Flag Default Notes
input (positional) required Input image path
output (positional) auto from input + prompt Output path
-p, --prompt required Editing prompt
--provider google AI provider
--model gemini-3-pro-image-preview Model name
--api-key env IMAGE_TRANSFORM_GOOGLE_API_KEY API key
--aspect-ratio auto 1:1, 16:9, 4:3, 3:4, 9:16, 21:9
--image-size 1K 512, 1K, 2K, 4K

If --api-key is omitted, the value of the IMAGE_TRANSFORM_GOOGLE_API_KEY environment variable is used.


Features at a glance

For prerequisites, build steps, installer, and the full option tables, see the C++ README.


FAQ (questions and answers)

What is pm-image?

pm-image is a CMake-built executable that exposes image resizing, AI image editing, and related operations through CLI, serve (REST), and ipc (JSON lines). Processing uses libvips, aligned with a Sharp-like option model for familiarity. AI editing uses Google Gemini.

Is pm-image the same as Sharp?

No — Sharp is a Node.js library; pm-image is a standalone native program. Both lean on libvips, so concepts like fit, position, kernel, and quality map closely. See the README's "Sharp-like options" table for field names (without_enlargement, strip_metadata, etc.).

How do I resize an image to an exact width?

Use --max-width (and optionally --max-height). The image scales down (or up if you allow enlargement) to respect those bounds and the chosen fit mode. For a fixed width-only workflow, set a large max_height or use JSON/resize options that match your desired behavior.

How do I resize without losing quality?

Resizing always re-encodes for raster formats; "lossless" depends on format:

without enlargement defaults to true, so small images are not upscaled unless you opt in.

How do I batch resize images in a folder?

Use a glob for input and a directory or template for output. Multiple matches are processed in one command; see Batch paths & cache in the README for rules on trailing slashes and ${SRC_*} variables.

Can I resize images from URLs?

Yes. Pass an http:// or https:// URL as input. Redirects are followed; timeouts and redirect limits are configurable (--url-timeout, --url-max-redirects).

Can pm-image edit images with AI?

Yes. Use pm-image transform <input> -p "your prompt" to edit images using Google Gemini. You can control the output aspect ratio, image size, and model. An API key is required (via --api-key or the IMAGE_TRANSFORM_GOOGLE_API_KEY environment variable).

Does pm-image work on Windows?

Yes. Use the vips dev bundle (npm run setup:vips from the package), build pm-image, and optionally install NSIS output for pm-image-setup.exe, PATH, DLLs, and Explorer scripts. register-explorer adds context menus for resize and convert. Two GUI modes are available: --ui (classic dialog) and --ui-next (ribbon UI with drag-drop queue).

How does caching work?

When enabled, outputs are stored under a cache directory (default under the process working directory), keyed by a SHA-256 hash of input identity, file metadata, and all resize options. Identical jobs reuse cached bytes without running libvips again.

What is IPC for?

ipc accepts one JSON object per line over TCP (or a Unix socket on non-Windows), ideal for local daemons or tools that want a simple request/response channel without HTTP overhead.

Where is the full API reference?


Related documentation

CLI examples

Paths below use Unix style; on Windows run pm-image.exe and use .\ or full paths as needed.

Help and version

pm-image --help
pm-image resize --help
pm-image -v

resize — fit inside a box (default), write WebP / AVIF by extension

# Max 800×600, stay inside the box, Lanczos3 (default), write JPEG quality 85 (default)
pm-image resize photo.jpg out.jpg --max-width 800 --max-height 600

# Same, explicit quality
pm-image resize photo.jpg out.jpg --max-width 800 --max-height 600 -q 90

# WebP output (quality applies)
pm-image resize photo.jpg thumb.webp --max-width 400 --max-height 400 -q 82

# AVIF output (quality applies; needs HEIF/AVIF support in your libvips build)
pm-image resize photo.png out.avif --max-width 1200 --max-height 1200 -q 50

# Force output format when the path has no extension you trust
pm-image resize in.tif /tmp/out --format webp --max-width 512

resize — square images (1:1)

Use the same --max-width and --max-height (that value is the square side in pixels). Pick --fit:

fit Result
cover Fills the square; crops overflow (default crop: --position centre, or attention / entropy for smart crop).
contain Full image inside the square; letterboxing on two sides if needed (--background).
fill Stretches to the square (ignores aspect ratio).
# 512×512 crop-to-square (avatars, thumbnails)
pm-image resize portrait.jpg avatar.jpg --fit cover --max-width 512 --max-height 512

# 1080×1080 WebP, smart crop on subject
pm-image resize product.png grid.webp --fit cover --max-width 1080 --max-height 1080 --position attention -q 85

# Square canvas, no crop — padded bands with a colour
pm-image resize panoramic.jpg square.jpg --fit contain --max-width 800 --max-height 800 --background '#111111'

# Exact square by stretching (rare)
pm-image resize any.jpg out.jpg --fit fill --max-width 256 --max-height 256

REST / IPC JSON: e.g. "max_width": 512, "max_height": 512, "fit": "cover", "position": "attention".

resize — cover (crop), contain (letterbox), rotate / flip

# Cover: fill 1200×630, crop centre (use --position attention for smart crop)
pm-image resize wide.jpg social.jpg --fit cover --max-width 1200 --max-height 630

# Contain: fit inside 800×600 canvas, letterbox with a background
pm-image resize logo.png padded.png --fit contain --max-width 800 --max-height 600 --background '#1a1a1a'

# EXIF autorotate (default), then rotate 90° CCW, vertical flip
pm-image resize img.jpg rotated.jpg --max-width 1024 --rotate 90 --flip

transform — AI image editing

# Remove background using Gemini
pm-image transform photo.jpg -p "remove the background"

# Convert to black and white, custom output path
pm-image transform photo.jpg bw.png -p "make it black and white"

# Specify aspect ratio and size
pm-image transform landscape.jpg -p "add a sunset sky" --aspect-ratio 16:9 --image-size 2K

serve — HTTP REST

# Default: http://127.0.0.1:8080 — GET /health, POST /v1/resize with JSON body
pm-image serve --host 127.0.0.1 -p 8080

Example resize request (paths must be readable/writable by the server process):

curl -s http://127.0.0.1:8080/health
curl -s -X POST http://127.0.0.1:8080/v1/resize \
  -H 'Content-Type: application/json' \
  -d '{"input":"/path/in.png","output":"/path/out.webp","max_width":400,"quality":80}'

Optional: "cache":false, "expand_glob":false, "cache_dir":"..." — see Batch paths & cache above.

ipc — one JSON line per connection (TCP; Unix socket on Linux/macOS)

pm-image ipc --host 127.0.0.1 -p 9333 --cache-dir ./cache/images
# elsewhere: send a single line, read one line back, e.g.
# {"input":"/tmp/a.jpg","output":"/tmp/b.webp","max_width":320,"format":"webp","cache":true}

Same JSON fields as REST (input, output, globs, expand_glob, cache, cache_dir, resize options).