Skip to content

Instantly share code, notes, and snippets.

@kennytrytek-wf
Last active October 8, 2025 20:28
Show Gist options
  • Save kennytrytek-wf/2204946ec7af5f13291159b32086f8dd to your computer and use it in GitHub Desktop.
Save kennytrytek-wf/2204946ec7af5f13291159b32086f8dd to your computer and use it in GitHub Desktop.
Split tall or wide images into files that can be printed. Good for infographics. AI-generated :D

Image Printer

A Python script that takes an image file and splits it into printable 8.5x11 inch pages.

Features

  • Automatic orientation detection: Uses landscape orientation for wide images, portrait for tall images
  • Smart scaling: Scales down large images to fit page dimensions while maintaining aspect ratio
  • Page splitting: Divides scaled images into page-sized pieces in collated reading order
  • High-quality output: Generates 300 DPI JPEG files suitable for printing
  • Flexible output: Supports custom output directories and maintains original file naming

Requirements

  • Python 3.6 or higher
  • Pillow (PIL) library

Installation

  1. Clone or download this repository
  2. Install the required dependencies:
pip install -r requirements.txt

Usage

Basic Usage

python image_printer.py your_image.jpg

This will create numbered page files in a ./pages/ directory.

Advanced Usage

python image_printer.py -o /path/to/output/ large_poster.png

Command Line Options

  • image_path: Path to the input image file (required)
  • -o, --output-dir: Directory to save output page files (default: ./pages/)

How It Works

  1. Load Image: The script loads your image and converts it to RGB format
  2. Determine Orientation:
    • If image width > height: Use landscape orientation (11" × 8.5")
    • Otherwise: Use portrait orientation (8.5" × 11")
  3. Calculate Scaling:
    • If the image is larger than a single page, it's scaled down proportionally
    • Scaling preserves aspect ratio and ensures the image fits within page boundaries
  4. Split into Pages:
    • The scaled image is divided into page-sized rectangles
    • Pages are numbered in reading order (left-to-right, top-to-bottom)
    • Each page is saved as a separate JPEG file

Output Files

Output files are named in the format: {original_name}_page_{number}.jpg

Examples:

  • family_photo_page_001.jpg
  • family_photo_page_002.jpg
  • blueprint_page_001.jpg

Supported Image Formats

The script supports all image formats supported by Pillow, including:

  • JPEG (.jpg, .jpeg)
  • PNG (.png)
  • TIFF (.tiff, .tif)
  • BMP (.bmp)
  • GIF (.gif)
  • And many more

Examples

Example 1: Small Image

If your image already fits on one page, you'll get a single output file.

Example 2: Large Landscape Image

A wide poster image will:

  • Use landscape page orientation (11" × 8.5")
  • Be scaled down if necessary
  • Be split into multiple pages arranged left-to-right, top-to-bottom

Example 3: Large Portrait Image

A tall image will:

  • Use portrait page orientation (8.5" × 11")
  • Be scaled down if necessary
  • Be split into multiple pages arranged left-to-right, top-to-bottom

Technical Details

  • Output DPI: 300 DPI (suitable for high-quality printing)
  • Page Dimensions: 8.5" × 11" (standard US letter size)
  • Output Format: JPEG with 95% quality
  • Color Mode: RGB (converted from any input color mode)

Troubleshooting

"No module named 'PIL'"

Install Pillow: pip install Pillow

"Error loading image"

  • Check that the file path is correct
  • Ensure the file is a valid image format
  • Verify you have read permissions for the file

Output directory issues

  • The script will create the output directory if it doesn't exist
  • Ensure you have write permissions for the specified output location

License

This project is open source. Feel free to modify and distribute as needed.

#!/usr/bin/env python3
"""
Image Printer - Split large images into printable 8.5x11 inch pages
This script takes an image file as input and outputs multiple image files
that fit on 8.5x11 inch sheets of paper for printing. The script automatically:
- Determines optimal page orientation (landscape vs portrait)
- Scales the image to fit within page boundaries
- Splits the image into numbered page sections in collated order
"""
import argparse
import math
import os
from pathlib import Path
from PIL import Image
import sys
# Page dimensions in inches
PAGE_WIDTH_INCHES = 8.5
PAGE_HEIGHT_INCHES = 11.0
# Margin size in inches (1 inch on all sides)
MARGIN_INCHES = 1.0
# DPI for output images (300 DPI is good for printing)
OUTPUT_DPI = 300
# Convert page dimensions to pixels
PAGE_WIDTH_PX = int(PAGE_WIDTH_INCHES * OUTPUT_DPI)
PAGE_HEIGHT_PX = int(PAGE_HEIGHT_INCHES * OUTPUT_DPI)
# Calculate printable area (page minus margins)
PRINTABLE_WIDTH_PX = int((PAGE_WIDTH_INCHES - 2 * MARGIN_INCHES) * OUTPUT_DPI)
PRINTABLE_HEIGHT_PX = int((PAGE_HEIGHT_INCHES - 2 * MARGIN_INCHES) * OUTPUT_DPI)
MARGIN_PX = int(MARGIN_INCHES * OUTPUT_DPI)
def get_page_dimensions(image_width, image_height):
"""
Determine the optimal page orientation and return printable area dimensions.
Args:
image_width (int): Width of the image in pixels
image_height (int): Height of the image in pixels
Returns:
tuple: (printable_width_px, printable_height_px) based on optimal orientation
"""
# If image is wider than tall, use landscape orientation
if image_width > image_height:
return PRINTABLE_HEIGHT_PX, PRINTABLE_WIDTH_PX # landscape: 9" x 6.5" printable
else:
return PRINTABLE_WIDTH_PX, PRINTABLE_HEIGHT_PX # portrait: 6.5" x 9" printable
def calculate_scale_factor(image_width, image_height, page_width, page_height):
"""
Calculate the scale factor to fill the printable area optimally.
The image will be scaled to fill either the width or height of the printable area,
whichever allows for larger scaling, then split as needed in the other dimension.
This maximizes paper usage by filling as much of the printable area as possible.
Args:
image_width (int): Original image width
image_height (int): Original image height
page_width (int): Printable area width in pixels
page_height (int): Printable area height in pixels
Returns:
float: Scale factor to maximize use of printable area
"""
# Calculate scale factors for both dimensions
width_scale = page_width / image_width
height_scale = page_height / image_height
# Use the larger scale factor to maximize printable area usage
# The image will be split in the other dimension if needed
scale_factor = max(width_scale, height_scale)
return scale_factor
def load_and_process_image(image_path):
"""
Load an image and determine processing parameters.
Args:
image_path (str): Path to the input image file
Returns:
tuple: (image, page_width, page_height, scale_factor)
"""
try:
# Load the image
image = Image.open(image_path)
# Convert to RGB if necessary (for consistent output)
if image.mode != 'RGB':
image = image.convert('RGB')
# Get image dimensions
img_width, img_height = image.size
# Determine page orientation and dimensions
page_width, page_height = get_page_dimensions(img_width, img_height)
# Calculate scale factor
scale_factor = calculate_scale_factor(img_width, img_height, page_width, page_height)
print(f"Original image size: {img_width}x{img_height}")
print(f"Page orientation: {'Landscape' if page_width > page_height else 'Portrait'}")
print(f"Printable area: {page_width}x{page_height} pixels (with 1\" margins)")
print(f"Scale factor: {scale_factor:.3f}")
return image, page_width, page_height, scale_factor
except Exception as e:
print(f"Error loading image: {e}")
sys.exit(1)
def split_image_into_pages(image, page_width, page_height, scale_factor, output_dir, base_name):
"""
Scale and split the image into page-sized pieces.
Args:
image (PIL.Image): The input image
page_width (int): Page width in pixels
page_height (int): Page height in pixels
scale_factor (float): Scale factor to apply
output_dir (str): Directory to save output files
base_name (str): Base name for output files
Returns:
int: Number of pages created
"""
# Scale the image if necessary
if scale_factor != 1.0:
orig_width, orig_height = image.size
new_width = int(orig_width * scale_factor)
new_height = int(orig_height * scale_factor)
image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
print(f"Scaled image to: {new_width}x{new_height}")
scaled_width, scaled_height = image.size
# Calculate how many pages we need in each direction
pages_horizontal = math.ceil(scaled_width / page_width)
pages_vertical = math.ceil(scaled_height / page_height)
total_pages = pages_horizontal * pages_vertical
print(f"Will create {pages_horizontal}x{pages_vertical} = {total_pages} pages")
# Create output directory if it doesn't exist
Path(output_dir).mkdir(parents=True, exist_ok=True)
page_number = 1
# Split the image in reading order (left to right, top to bottom)
for row in range(pages_vertical):
for col in range(pages_horizontal):
# Calculate the crop box for this page (within printable area)
left = col * page_width
top = row * page_height
right = min(left + page_width, scaled_width)
bottom = min(top + page_height, scaled_height)
# Crop the image
page_image = image.crop((left, top, right, bottom))
# Create a full-page white background with margins
full_page_width = PAGE_WIDTH_PX if page_width == PRINTABLE_WIDTH_PX else PAGE_HEIGHT_PX
full_page_height = PAGE_HEIGHT_PX if page_height == PRINTABLE_HEIGHT_PX else PAGE_WIDTH_PX
background = Image.new('RGB', (full_page_width, full_page_height), 'white')
# Calculate position to center the content within margins
paste_x = MARGIN_PX
paste_y = MARGIN_PX
# Paste the cropped image onto the background with margins
background.paste(page_image, (paste_x, paste_y))
page_image = background
# Save the page
output_filename = f"{base_name}_page_{page_number:03d}.jpg"
output_path = os.path.join(output_dir, output_filename)
page_image.save(output_path, 'JPEG', quality=95, dpi=(OUTPUT_DPI, OUTPUT_DPI))
print(f"Created: {output_filename}")
page_number += 1
return total_pages
def main():
"""Main function to handle command-line arguments and process the image."""
parser = argparse.ArgumentParser(
description="Split large images into printable 8.5x11 inch pages",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python image_printer.py large_poster.jpg
python image_printer.py -o ./output_pages/ family_photo.png
python image_printer.py --output-dir /tmp/pages/ blueprint.tiff
"""
)
parser.add_argument(
'image_path',
help='Path to the input image file'
)
parser.add_argument(
'-o', '--output-dir',
default='./pages/',
help='Directory to save output page files (default: ./pages/)'
)
args = parser.parse_args()
# Validate input file
if not os.path.isfile(args.image_path):
print(f"Error: Input file '{args.image_path}' not found.")
sys.exit(1)
# Get base name for output files
base_name = Path(args.image_path).stem
print(f"Processing image: {args.image_path}")
print(f"Output directory: {args.output_dir}")
print(f"Base name: {base_name}")
print("-" * 50)
# Load and process the image
image, page_width, page_height, scale_factor = load_and_process_image(args.image_path)
# Split the image into pages
total_pages = split_image_into_pages(
image, page_width, page_height, scale_factor, args.output_dir, base_name
)
print("-" * 50)
print(f"Success! Created {total_pages} page(s) in '{args.output_dir}'")
print(f"Files are numbered in collated order for easy printing.")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment