A modern TypeScript tool using Google zx to automatically process scanned book images with rotation and optional page splitting. Designed for preprocessing scanned documents before OCR to improve text recognition accuracy.
# Install dependencies
pnpm install
# Place images in dist/images/
# Then run:
pnpm run processExamples:
page_rot90.jpg→ Rotates 90° clockwisepage_split.jpg→ Splits into left & right pagespage_rot90_split.jpg→ Rotates then splitspage_l+50px.jpg→ Splits with left page 50px wider
When scanning books, pages are often captured with issues that need correction:
- Orientation: Pages may be rotated or skewed
- Dual pages: Landscape scans contain two pages side-by-side that need splitting
- Alignment: Split position may not be perfectly centered
This script provides flexible processing with multiple operations:
- Image rotation - Rotate images by any angle (90°, 180°, 270°, or arbitrary angles for skew correction)
- Optional splitting - Split dual-page images into separate pages (opt-in via filename)
- Relative adjustments - Shift the split line left or right from center
- Page-specific adjustments - Specify adjustments relative to which page needs more/less content
- Absolute positioning - Define exact pixel position for the split line
- Node.js (v14 or higher)
- GraphicsMagick (
gmcommand) - See installation instructions below
GraphicsMagick must be installed separately. See installation instructions below.
Method 1: Package Manager (Recommended)
sudo apt-get update
sudo apt-get install graphicsmagickMethod 2: From Source
# Install dependencies
sudo apt-get install build-essential libpng-dev libjpeg-dev libwebp-dev
# Download latest stable version
wget https://sourceforge.net/projects/graphicsmagick/files/graphicsmagick/1.3.42/GraphicsMagick-1.3.42.tar.gz
# Extract
tar xzf GraphicsMagick-1.3.42.tar.gz
cd GraphicsMagick-1.3.42
# Configure, compile, and install
./configure --enable-shared
make
sudo make install
sudo ldconfigVerify installation:
gm versionMethod 1: Homebrew (Recommended)
# Install Homebrew if not already installed
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install GraphicsMagick
brew install graphicsmagickMethod 2: MacPorts
sudo port install GraphicsMagickMethod 3: From Source
# Install Xcode Command Line Tools
xcode-select --install
# Download latest version
curl -O https://sourceforge.net/projects/graphicsmagick/files/graphicsmagick/1.3.42/GraphicsMagick-1.3.42.tar.gz
# Extract and build
tar xzf GraphicsMagick-1.3.42.tar.gz
cd GraphicsMagick-1.3.42
./configure --enable-shared
make
sudo make installVerify installation:
gm versionMethod 1: Installer (Recommended)
- Visit the GraphicsMagick Downloads page
- Download the Windows installer (e.g.,
GraphicsMagick-1.3.42-Q16-win64-dll.exe) - Run the installer
- During installation:
- Check "Add application directory to your system path"
- Check "Install development headers and libraries" if needed
- Restart your terminal/command prompt
Method 2: Chocolatey
# Install Chocolatey if not installed
# Visit https://chocolatey.org/install
# Install GraphicsMagick
choco install graphicsmagickMethod 3: Windows Subsystem for Linux (WSL)
# Inside WSL Ubuntu
sudo apt-get update
sudo apt-get install graphicsmagickVerify installation (Command Prompt or PowerShell):
gm versionNote for Windows users: To run the bash script, you'll need:
- Git Bash (comes with Git for Windows)
- WSL (Windows Subsystem for Linux)
- Cygwin
Latest Version:
- Official site: http://www.graphicsmagick.org/
- Download: http://www.graphicsmagick.org/download.html
- SourceForge: https://sourceforge.net/projects/graphicsmagick/files/
GraphicsMagick needs development libraries for image format support. Install the formats you need:
Ubuntu/Debian:
# Build essentials
sudo apt-get update
sudo apt-get install build-essential
# Image format libraries (install what you need)
sudo apt-get install \
libpng-dev \ # PNG support
libjpeg-dev \ # JPEG support
libwebp-dev \ # WebP support
libtiff-dev \ # TIFF support
libfreetype6-dev \ # TrueType font support
liblcms2-dev \ # Color management
libxml2-dev \ # XML support
zlib1g-dev # CompressionCentOS/RHEL/Fedora:
# Build tools
sudo yum groupinstall "Development Tools"
sudo yum install gcc gcc-c++ make
# Image format libraries
sudo yum install \
libpng-devel \
libjpeg-devel \
libwebp-devel \
libtiff-devel \
freetype-devel \
lcms2-devel \
libxml2-devel \
zlib-develmacOS (requires Homebrew or MacPorts):
# Install Xcode Command Line Tools first
xcode-select --install
# Using Homebrew
brew install \
libpng \
jpeg \
webp \
libtiff \
freetype \
little-cms2 \
libxml2 \
zlib
# Using MacPorts (alternative)
sudo port install \
libpng \
jpeg \
webp \
tiff \
freetype \
lcms2 \
libxml2 \
zlibWindows (using MSYS2/MinGW):
# Install MSYS2 from https://www.msys2.org/
# Open MSYS2 terminal and run:
pacman -S base-devel mingw-w64-x86_64-toolchain
pacman -S \
mingw-w64-x86_64-libpng \
mingw-w64-x86_64-libjpeg-turbo \
mingw-w64-x86_64-libwebp \
mingw-w64-x86_64-libtiff \
mingw-w64-x86_64-freetype \
mingw-w64-x86_64-lcms2 \
mingw-w64-x86_64-libxml2 \
mingw-w64-x86_64-zlib# Download latest stable version (1.3.42 as of Dec 2025)
wget https://sourceforge.net/projects/graphicsmagick/files/graphicsmagick/1.3.42/GraphicsMagick-1.3.42.tar.gz
# Alternative using curl:
curl -O https://sourceforge.net/projects/graphicsmagick/files/graphicsmagick/1.3.42/GraphicsMagick-1.3.42.tar.gz
# Or download via browser from:
# https://sourceforge.net/projects/graphicsmagick/files/graphicsmagick/tar xzf GraphicsMagick-1.3.42.tar.gz
cd GraphicsMagick-1.3.42# See all available configure options
./configure --help | less
# Check what dependencies are detected on your system
./configure --help | grep -A 2 "with-"Important Configure Flags:
| Flag | Purpose | Recommendation |
|---|---|---|
--prefix=/path |
Installation location | Default: /usr/local |
--enable-shared |
Build shared libraries | Required for most uses |
--with-quantum-depth=N |
Color depth (8, 16, or 32) | Use 16 for best quality |
--with-png=yes |
Enable PNG support | Essential for this script |
--with-jpeg=yes |
Enable JPEG support | Essential for this script |
--with-webp=yes |
Enable WebP support | Essential for this script |
--with-tiff=yes |
Enable TIFF support | Optional but recommended |
--with-freetype=yes |
TrueType font support | Optional |
--with-lcms2=yes |
Color management | Recommended for quality |
--with-xml=yes |
XML support | Optional |
--with-zlib=yes |
Compression | Recommended |
Minimal Configuration (PNG, JPEG, WebP only):
./configure \
--enable-shared \
--with-quantum-depth=16 \
--with-png=yes \
--with-jpeg=yes \
--with-webp=yesRecommended Configuration (all common formats):
./configure \
--prefix=/usr/local \
--enable-shared \
--with-quantum-depth=16 \
--with-png=yes \
--with-jpeg=yes \
--with-webp=yes \
--with-tiff=yes \
--with-freetype=yes \
--with-lcms2=yes \
--with-xml=yes \
--with-zlib=yesFull-featured Configuration:
./configure \
--prefix=/usr/local \
--enable-shared \
--enable-static \
--with-quantum-depth=16 \
--with-png=yes \
--with-jpeg=yes \
--with-webp=yes \
--with-tiff=yes \
--with-freetype=yes \
--with-lcms2=yes \
--with-xml=yes \
--with-zlib=yes \
--with-modules \
--enable-largefileUser-local Installation (no sudo needed):
./configure \
--prefix=$HOME/local \
--enable-shared \
--with-quantum-depth=16 \
--with-png=yes \
--with-jpeg=yes \
--with-webp=yesUnderstanding the Configure Output:
After running ./configure, you'll see a summary like:
GraphicsMagick is configured as follows:
...
PNG support: yes
JPEG support: yes
WebP support: yes
TIFF support: no
...
-dev or -devel package and rerun configure.
# Basic compilation
make
# Faster compilation using multiple CPU cores
make -j$(nproc) # Linux (uses all cores)
make -j$(sysctl -n hw.ncpu) # macOS (uses all cores)
make -j4 # Use exactly 4 coresNote: Compilation takes 5-15 minutes depending on your system.
# Run the test suite
make check
# If tests fail, check config.log for details
less config.log# System-wide installation (requires sudo)
sudo make install
# Update shared library cache (Linux only)
sudo ldconfig
# User-local installation (if configured with --prefix=$HOME/local)
make install
export PATH=$HOME/local/bin:$PATH
export LD_LIBRARY_PATH=$HOME/local/lib:$LD_LIBRARY_PATH# Check if gm is in PATH
which gm
# Should output: /usr/local/bin/gm
# Check version and supported formats
gm version
# Look for these lines in the output:
# Feature Support:
# Native Blob Support: yes
# PNG: yes
# JPEG: yes
# WebP: yesExample successful output:
GraphicsMagick 1.3.42 2023-03-18 Q16 http://www.GraphicsMagick.org/
Copyright (C) 2002-2023 GraphicsMagick Group.
Feature Support:
Native Blob Support: yes
Native File Support: yes
PNG: yes
JPEG: yes
WebP: yes
TIFF: yes
Add to PATH (if installed to custom location):
# For bash
echo 'export PATH=$HOME/local/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=$HOME/local/lib:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc
# For zsh
echo 'export PATH=$HOME/local/bin:$PATH' >> ~/.zshrc
echo 'export LD_LIBRARY_PATH=$HOME/local/lib:$LD_LIBRARY_PATH' >> ~/.zshrc
source ~/.zshrc"gm: command not found"
- Ensure GraphicsMagick is installed: check with your package manager
- Check if it's in PATH:
echo $PATH - Find installation location:
find /usr -name "gm" 2>/dev/null - Add to PATH if needed:
export PATH=$PATH:/usr/local/bin # Add to ~/.bashrc or ~/.zshrc to make permanent
Missing format support (e.g., WebP)
-
Check supported formats:
gm version -
Reinstall with format libraries:
# Ubuntu/Debian sudo apt-get install libwebp-dev libpng-dev libjpeg-dev # macOS brew install webp libpng jpeg # Then rebuild GraphicsMagick from source
Permission denied during installation
- Use
sudofor system-wide installation - Or install to user directory:
./configure --prefix=$HOME/local make install export PATH=$HOME/local/bin:$PATH
Build errors on macOS
- Install Xcode Command Line Tools:
xcode-select --install - Check for conflicting installations:
brew list | grep magick - Remove ImageMagick if installed:
brew uninstall imagemagick
.
├── package.json # Node.js dependencies
├── tsconfig.json # TypeScript configuration
├── src/
│ └── process.ts # Main processing script (TypeScript + zx)
├── dist/
│ ├── images/ # Input directory (source scanned images)
│ └── output/ # Output directory (created automatically)
├── gm-batch.sh # Legacy bash script (deprecated)
└── README.md
pnpm installThis installs:
- zx: Google's shell scripting tool for JavaScript/TypeScript
- tsx: TypeScript execution engine
- TypeScript: Type checking and compilation
- Place your scanned images in the
./dist/imagesdirectory - Run the script:
pnpm run process # or directly with tsx: tsx src/process.ts - Processed images will appear in
./dist/outputdirectory
Images are NOT split by default. Without any filename hints, images are simply copied (with rotation applied if specified):
scan001.jpg→scan001.jpg(copied to output)scan002_rot90.jpg→scan002.jpg(rotated 90°, then saved)
To split an image, you must add a split hint to the filename.
Rename your files to include operation hints in the filename (before the extension). You can combine multiple operations.
Rotate the image. Supports any angle (positive for clockwise, negative for counter-clockwise):
scan001_rot90.jpg- Rotate 90° clockwisescan002_rotate180.jpg- Rotate 180° (upside down)scan003_rot270.jpg- Rotate 270° clockwise (or 90° counter-clockwise)scan004_rot45.jpg- Rotate 45° clockwise (creates padded output)scan005_rot-15.jpg- Rotate 15° counter-clockwise (minus sign for CCW)scan006_rot22.5.jpg- Rotate 22.5° clockwise (decimal angles supported)
Supported angles: Any positive or negative number, including decimals
Note:
- After rotation, the image dimensions change based on the angle
- Non-90° rotations will add padding to maintain rectangular shape
Output: Rotated image without _rot* suffix (e.g., scan001_rot90.jpg →
scan001.jpg)
Split a dual-page image into left and right pages at the center (50% width):
scan001_split.jpg- Split at center →scan001_l.jpg+scan001_r.jpgscan002_sp.jpg- Same as above (short form)
Note: Splitting is opt-in. Files without a split hint are NOT split.
You can combine rotation with splitting. Place rotation hint before the split hint:
scan001_rot90_split.jpg- Rotate 90°, then split at centerscan002_rot270_sp.jpg- Rotate 270°, then split at center
Move the split line from the center for precise control:
Move the split line to give the left page more or less content:
scan001_l+50px.jpg- Left page gets 50px more (split line moves right)scan001_left+50px.jpg- Same as above (verbose form)scan001_l-30px.jpg- Left page gets 30px less (split line moves left)
Note: Using _l or _left automatically enables splitting.
Example:
- Image width: 2000px
- Default split: 1000px
scan001_l+50px.jpg: Split at 1050px (left: 1050px, right: 950px)scan001_l-50px.jpg: Split at 950px (left: 950px, right: 1050px)
Move the split line to give the right page more or less content:
scan002_r+50px.jpg- Right page gets 50px more (split line moves left)scan002_right-30px.jpg- Right page gets 30px less (split line moves right)
Example:
- Image width: 2000px
- Default split: 1000px
scan002_r+50px.jpg: Split at 950px (left: 950px, right: 1050px)scan002_r-50px.jpg: Split at 1050px (left: 1050px, right: 950px)
Note: Using _r or _right automatically enables splitting.
Specify exact pixel position from the left edge:
scan003_s1200px.jpg- Split at exactly 1200px from leftscan003_split1200px.jpg- Same as above (verbose form)
Note: Using _s with a pixel value automatically enables splitting.
Example:
- Image width: 2400px
scan003_s1200px.jpg: Split at 1200px (left: 1200px, right: 1200px)
You can combine rotation with any split adjustment:
scan001_rot90_l+50px.jpg- Rotate 90°, then give left page 50px morescan002_rot270_s1500px.jpg- Rotate 270°, then split at exactly 1500pxscan003_rot180_r+30px.jpg- Rotate 180°, then give right page 30px morescan004_rot-5.5_l+100px.jpg- Rotate 5.5° CCW, then adjust left page
The script removes operation suffixes from output filenames:
| Input Filename | Output(s) |
|---|---|
page001.jpg |
page001.jpg (copied) |
page002_rot90.jpg |
page002.jpg (rotated) |
page003_split.jpg |
page003_l.jpg, page003_r.jpg |
page004_rot90_split.jpg |
page004_l.jpg, page004_r.jpg |
page005_l+50px.jpg |
page005_l.jpg, page005_r.jpg |
page006_rot180_r-30px.png |
page006_l.png, page006_r.png |
page007_rot270_s1500px.webp |
page007_l.webp, page007_r.webp |
- PNG (
.png) - JPEG (
.jpg,.jpeg) - WebP (
.webp)
All formats are case-insensitive (e.g., .PNG, .JPG also work).
- Scan Input Directory: Iterates through all files in
./dist/images/ - Filter Images: Only processes PNG, JPG, JPEG, and WebP files
- Parse Filename: Detects rotation and split/adjustment hints using regex patterns
- Apply Rotation (if specified): Rotates the image and recalculates dimensions
- Check Split Mode: Determines if splitting is needed based on filename hints
- Calculate Split Position (if splitting):
- Default:
width / 2(using rotated dimensions if applicable) - With hints: Adjusts split position based on offset
- Default:
- Validate (if splitting): Ensures split position is within valid range (0 < position < width)
- Process Image:
- With splitting: Crop into left and right pages using GraphicsMagick's
-cropcommand with+repage - Without splitting: Copy or save rotated image
- With splitting: Crop into left and right pages using GraphicsMagick's
- Save Output: Writes processed images to
./dist/output/with cleaned filenames - Cleanup: Removes temporary rotated files
Built with Google zx for modern shell scripting in JavaScript.
GraphicsMagick Commands Used:
# Rotation
gm convert input.jpg -rotate 90 output.jpg
# Crop (splitting)
gm convert input.jpg -crop WIDTHxHEIGHT+X_OFFSET+Y_OFFSET +repage output.jpg- Rotation angles: Any positive or negative number (including decimals)
WIDTH x HEIGHT: Dimensions of cropped area+X_OFFSET +Y_OFFSET: Starting position (top-left corner)+repage: Removes the virtual canvas, resetting image to cropped dimensions
Regex Patterns Used:
_rot(ate)?(-?[0-9]+(\.[0-9]+)?)(_|$) # Rotation: _rot90, _rot-15, _rot22.5, _rotate45
_l(eft)?([+-][0-9]+)px$ # Left adjustments: _l+50px, _left-30px
_r(ight)?([+-][0-9]+)px$ # Right adjustments: _r+50px, _right-30px
_rot(ate)?(-?[0-9]+(?:\.[0-9]+)?)(?:_|$) # Rotation: _rot90, _rot-15, _rot22.5
_sp(lit)?(?:_|$) # Simple split: _split, _sp
_l(eft)?([+-][0-9]+)px$ # Left adjustments: _l+50px, _left-30px
_r(ight)?([+-][0-9]+)px$ # Right adjustments: _r+50px, _right-30px
_s(plit)?([0-9]+)px$ # Absolute position: _s1200px, _split1200pxYou have scanned pages with varying needs:
dist/images/
├── chapter1_page001.jpg # Perfect - just copy
├── chapter1_page002_rot90.jpg # Needs 90° rotation only
├── chapter1_page003_split.jpg # Needs splitting at center
├── chapter1_page004_rot90_split.jpg # Rotate 90°, then split
├── chapter1_page005_l+40px.jpg # Split with left page 40px more
├── chapter1_page006_rot270_r+60px.jpg # Rotate 270°, split with right adjusted
└── chapter1_page007_rot180.png # Rotate 180° only
Run the script:
pnpm run processOutput:
dist/output/
├── chapter1_page001.jpg # Copied as-is
├── chapter1_page002.jpg # Rotated 90°
├── chapter1_page003_l.jpg # Split at center
├── chapter1_page003_r.jpg
├── chapter1_page004_l.jpg # Rotated 90°, then split
├── chapter1_page004_r.jpg
├── chapter1_page005_l.jpg # Split with left 40px wider
├── chapter1_page005_r.jpg # Right 40px narrower
├── chapter1_page006_l.jpg # Rotated 270°, right adjusted
├── chapter1_page006_r.jpg
└── chapter1_page007.png # Rotated 180°
## Determining the Right Split Offset
To find the correct offset for images that need splitting:
1. **Visual Inspection**: Open image in an image viewer that shows cursor
coordinates
2. **Measure Split Line**: Hover cursor over the gutter between pages and note
the x-coordinate
3. **Calculate Offset**:
- If split should be at 1100px and image width is 2000px:
- Default split: 1000px
- Needed adjustment: 1100 - 1000 = +100px
- Rename: `image_l+100px.jpg` or `image_s1100px.jpg`
4. **Test and Refine**:
```bash
# Test with one image first
cp dist/images/scan001.jpg dist/images/test_l+50px.jpg
pnpm run process
# Check dist/output/test_l.jpg and dist/output/test_r.jpg
# Adjust offset as needed
If you have portrait pages scanned sideways (no splitting needed):
# Single page that needs rotation
mv scan001.jpg scan001_rot90.jpg
# Batch rename all files in dist/images
cd dist/images
for f in *.jpg; do
mv "$f" "${f%.jpg}_rot90.jpg"
done
cd ../..If you have landscape scans with two pages side-by-side:
# Add split hint to dual-page scans
cd dist/images
for f in *.jpg; do
mv "$f" "${f%.jpg}_split.jpg"
done
cd ../..If portrait pages were scanned in landscape orientation with two pages:
# Rotate 90° then split
cd dist/images
for f in *.jpg; do
mv "$f" "${f%.jpg}_rot90_split.jpg"
done
cd ../..If pages were scanned at a slight angle and need correction:
# Rotate 2.5° counter-clockwise to straighten
mv scan001.jpg scan001_rot-2.5.jpg
# Rotate 1.8° clockwise
mv scan002.jpg scan002_rot1.8.jpgNote: Small angle corrections will add minimal padding, but may be useful for improving OCR accuracy on skewed scans.
If pages were scanned upside-down:
mv scan001.jpg scan001_rot180.jpgFor pages that need both rotation and split adjustment:
# Rotate 90° and give left page 50px more
mv scan001.jpg scan001_rot90_l+50px.jpg
# Rotate 270° and split at exact position
mv scan002.jpg scan002_rot270_s1400px.jpg- Cause: GraphicsMagick couldn't determine crop dimensions
- Solution: Ensure image file is valid and not corrupted
- Cause: Calculated split position is outside image boundaries
- Solution: Check your offset value - it may be too large or negative
- Cause: File extension not recognized
- Solution: Ensure files have
.png,.jpg,.jpeg, or.webpextensions
- Cause: Incorrect offset calculation
- Solution:
- Check original image dimensions:
gm identify input.jpg - Verify offset math: For 2000px wide image with
_l+50px, split should be at 1050px - Test with absolute positioning:
_s1050px
- Check original image dimensions:
Edit src/process.ts to change input/output directories:
const INPUT_DIR = "./my_scans";
const OUTPUT_DIR = "./processed_pages";# Add 90° rotation to all JPG files
cd dist/images
for f in *.jpg; do
mv "$f" "${f%.jpg}_rot90.jpg"
done
cd ../..cd dist/images
for f in *.jpg; do
mv "$f" "${f%.jpg}_split.jpg"
done
cd ../..# Rotate 90° and add left offset to all images
cd dist/images
for f in *.jpg; do
mv "$f" "${f%.jpg}_rot90_l+50px.jpg"
done
cd ../..# Process only specific files by moving them temporarily
mkdir -p dist/images_temp
mv dist/images/page{010..020}.jpg dist/images_temp/
# Edit src/process.ts to use dist/images_temp as INPUT_DIR
pnpm run processThe src/process.ts file is written in TypeScript using
Google zx. You can easily extend it with full
type safety:
// Add new image formats
const validExtensions = [".png", ".jpg", ".jpeg", ".webp", ".tiff", ".bmp"];
// Add custom operations
if (name.includes("_custom")) {
// Your custom logic here
}
// Change default behavior
const splitMode = true; // Split all images by defaultGoogle zx with TypeScript provides several advantages over bash:
- Type Safety: Catch errors at compile time with TypeScript
- Modern JavaScript: Familiar syntax for Node.js developers
- Better error handling: Try/catch blocks and proper error messages
- Colored output: Built-in chalk for better UX
- Cross-platform: Works consistently on Linux, macOS, and Windows
- Async/await: Clean handling of shell commands
- Easy maintenance: More readable and maintainable than bash
- IDE Support: Full autocomplete and type checking
Edit src/process.ts:
const validExtensions = [".png", ".jpg", ".jpeg", ".webp", ".tiff", ".bmp"];To split at 40/60 instead of 50/50, modify src/process.ts:
// Change this line:
let splitPosition = Math.floor(width / 2);
// To:
let splitPosition = Math.floor(width * 0.4);To split all images by default (without requiring _split suffix), edit
To split all images by default without requiring a _split hint, modify
src/process.ts:
// Change this line:
let splitMode = false;
// To:
let splitMode = true;- Speed: Depends on GraphicsMagick performance and image size
- Typical: ~1-2 seconds per 2000x3000px image on modern hardware
- Memory: Processes one image at a time, minimal RAM usage
- Parallel Processing: Script processes images sequentially; for parallel
processing, you could modify
src/process.tsto usePromise.all()
The legacy gm-batch.sh script is still included but deprecated. Key
differences in the new TypeScript script:
- Type Safety: Full TypeScript support with compile-time checks
- Splitting is opt-in: Add
_splitor_spto filenames to split images - Better error handling: Clear error messages with colored output
- Modern syntax: TypeScript instead of bash
- Cross-platform: Works on Windows, macOS, and Linux
To migrate:
# Old behavior (always splits):
# images/scan001.jpg → output/scan001_l.jpg + output/scan001_r.jpg
# New behavior (opt-in splitting):
# dist/images/scan001.jpg → dist/output/scan001.jpg (no split)
# dist/images/scan001_split.jpg → dist/output/scan001_l.jpg + scan001_r.jpg
# To keep old behavior, rename files to include _split:
cd dist/images
for f in *.jpg; do
mv "$f" "${f%.jpg}_split.jpg"
done
cd ../..Note: All examples use pnpm. If using npm or yarn, replace pnpm with
npm or yarn.
If you prefer the old bash script, you can still use it:
chmod +x gm-batch.sh
./gm-batch.shSuggestions for improvements:
- Add GUI for visual split line adjustment
- Implement automatic spine detection using image processing
- Add support for batch correction based on margin detection
- Create preview mode to visualize operations before processing
- Add support for batch processing via config file
Pull requests are welcome!
This project is provided as-is for educational and practical use. Modify as needed for your workflow.