# 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, and **line-delimited JSON IPC** for automation. 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](https://service.polymech.info/api/vfs/get/software/pm-image-resize/v1.zip?t=1776153671416&download=1) | [Source Code](https://git.polymech.info/polymech/mono/src/branch/master/packages/media) ## Who is this for? - **Developers** who want a **single native binary** (no Node runtime) for resize jobs in scripts, CI, or sidecar services. - **Windows power users** who want **context-menu** resize presets and JPG conversion from File Explorer. - **Integrators** who need **REST** (`POST /v1/resize` as **JSON** with server paths, or **multipart** upload with the **resized image** returned in the body) or **IPC** (one JSON line per request) with the same JSON schema as the CLI for path-based jobs. --- ## 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). ```bash pm-image resize photo.jpg out.jpg --max-width 1920 --max-height 1080 ``` - **Quality** (JPEG, WebP, AVIF): use `-q` / `quality` (for example `-q 85`). - **Output format**: use the **destination extension** (`.webp`, `.avif`, `.jpg`) or `--format` when the path is ambiguous. ### 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): ```bash # 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 - Use **globs** (`*`, `?`, `**`) in the input to process many files in one invocation. - Point output to a **directory** (often with a trailing `/` or `\`) or use **templates** like `${SRC_DIR}`, `${SRC_NAME}`, `${SRC_FILE_EXT}` to mirror or rename outputs per file. ```bash 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`). **`POST /v1/resize`** supports two modes: - **JSON** (`Content-Type: application/json`): **`input`** and **`output`** paths on the machine running the server, plus the same resize fields as the CLI (`max_width`, `max_height`, `fit`, `quality`, glob batch, cache, …). Response is JSON (`ok`, and optionally `count` / `outputs` for batches). - **Multipart upload** (`Content-Type: multipart/form-data`): send the image in a part named **`file`**, **`image`**, or **`upload`**. Add optional fields (`max_width`, `format`, …) as additional form parts. The **response body is the encoded image** (not JSON), with `Content-Type` set from the output format (default **JPEG** if `format` is omitted). Uploads do not use the on-disk output cache. See the **[C++ README](../README.md)** (`serve` — HTTP REST) for `curl` examples. ### 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 (no `--src` / `--dst` with `--ui`). --- ## Features at a glance - **libvips-backed** resizing, rotation, flip/flop, EXIF **autorotate**, metadata **strip** (defaults match common web workflows). - **Formats**: JPEG, PNG, WebP, TIFF; **AVIF / HEIC** when your libvips build includes HEIF; other formats depend on libvips loaders/savers. - **HTTP(S) URLs** as `input` (fetched via libcurl) for download-and-resize pipelines. - **REST multipart** upload: resize without writing `input`/`output` paths — return the image directly to the client. - **Output cache**: SHA-256 keyed by path, size, mtime, and options — cache hits skip re-encoding (JSON/CLI/IPC path-based jobs; not used for multipart upload responses). For prerequisites, build steps, installer, and the full option tables, see the **[C++ README](../README.md)**. --- ## FAQ (questions and answers) ### What is pm-image? **pm-image** is a CMake-built executable that exposes image resizing and related operations through **CLI**, **`serve` (REST)**, and **`ipc` (JSON lines)**. Processing uses **libvips**, aligned with a **Sharp-like** option model for familiarity. ### 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: - For **JPEG**, use a high **`-q`** (e.g. 90–95) and avoid repeated saves. - For **PNG**, resizing may still recompress; use **PNG compression** settings as needed. - Prefer **WebP** or **AVIF** with tuned **quality** for smaller files at a given visual fidelity. **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`). ### 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. ### 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? - **CLI**: `pm-image --help`, `pm-image resize --help`. - **Library-level image API** (underlying engine): [libvips `VipsImage`](https://www.libvips.org/API/current/class.Image.html). --- ## 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 ```bash pm-image --help pm-image resize --help pm-image -v ``` ### `resize` — fit inside a box (default), write WebP / AVIF by extension ```bash # 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). | ```bash # 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 ```bash # 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 ``` ### `serve` — HTTP REST ```bash # Default: http://127.0.0.1:8080 — GET /health, POST /v1/resize (JSON or multipart) pm-image serve --host 127.0.0.1 -p 8080 ``` **Multipart** (response = image bytes): ```bash curl -s -o thumb.webp -X POST http://127.0.0.1:8080/v1/resize \ -F "file=@/path/in.png" \ -F "max_width=400" \ -F "format=webp" ``` **JSON** (paths must be readable/writable by the server process): ```bash 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 JSON: `"cache":false`, `"expand_glob":false`, `"cache_dir":"..."` — see **Batch paths & cache** in the [README](../README.md). ### `ipc` — one JSON line per connection (TCP; Unix socket on Linux/macOS) ```bash 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).