Joins 2+ JPEGs side-by-side or stacked, re-encoding at the original quality so the output file size stays close to the sum of the inputs. For 2 images, it auto-detects the correct order and orientation by matching edge colors — no need to specify anything.
Also ships a drag-and-drop browser UI — run jpegconcat with no arguments to open it.
Via Homebrew (recommended):
brew tap pathanin/jpegconcat https://github.com/pathanin/jpegconcat
brew trust pathanin/jpegconcat
brew install jpegconcat
jpegconcat photo1.jpg photo2.jpg
Note (Homebrew 6.0+): Homebrew 6.0 requires taps to be trusted before installing. The
brew trust pathanin/jpegconcatstep above grants that trust. Without it the build fails silently inside the sandbox. Runbrew untrust pathanin/jpegconcatto revoke.
Manually (requires Python 3):
pip3 install Pillow numpy flask
python3 concat_jpeg.py photo1.jpg photo2.jpg
Keep the web/ folder next to concat_jpeg.py; the browser UI is served from it.
jpegconcat
Opens a drag-and-drop interface at http://localhost:5001. Drop images anywhere
on the page to build a grid, then click Download.
Grid building:
- Drop an image onto the left or right edge of a cell → inserts a new column
- Drop onto the top or bottom edge → inserts a new row
- Drop onto the center of a cell → replaces that image
- Drag one cell onto another → swap them
- Click × on a cell → removes it (grid compacts automatically; ⌘Z undoes)
- Click + on any edge of the grid → picks an image for a new column/row there
Per-image transforms (hover a cell, or focus it with Tab):
- ↺ ↻ or Shift+R / R — rotate 90° counter-clockwise / clockwise
- ↔ ↕ or H / V — flip horizontal / vertical
- Delete — remove the focused image
Other shortcuts: ⌘O add images · ⌘↵ download · ⌘Z undo remove
Custom port:
jpegconcat --port 8080
jpegconcat photo1.jpg photo2.jpg
Output is saved as concat.jpg in the same folder as your images.
If concat.jpg already exists, it saves as concat_2.jpg, concat_3.jpg, etc.
Override layout or order if needed:
jpegconcat a.jpg b.jpg --direction horizontal # force side-by-side
jpegconcat a.jpg b.jpg --direction vertical # force top/bottom
jpegconcat a.jpg b.jpg --order as-given # keep the order you typed
jpegconcat a.jpg b.jpg --output my_name.jpg # custom output path
More than 2 images:
jpegconcat a.jpg b.jpg c.jpg
The script says how it chose the order and direction (orientation heuristic, visual balance or a panoramic seam match, or filename order), then prints a size report and the encoding it used.