Image Contact Sheet
Build a PHP command-line tool that turns a folder of photos into one contact sheet: a single image with small thumbnails of every photo arranged in a grid, each labeled with its file name, like the sheets photographers use to preview a roll of film. You choose the number of columns and the thumbnail size, and big folders are split into several pages. The tool keeps each photo's proportions, skips files that aren't images, and reports what it did. It's a good first PHP project outside the web: you'll learn command-line scripts, reading folders, working with images using the GD extension, basic layout math, setting up a project with Composer, and testing with PHPUnit.
- Estimate
- ~9h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
PHP GD · Composer · PHPUnit
Project roadmap
- 01
Define the command
~1hCreate a project with composer init and a bin/contact-sheet script. Write README.md showing the usage: contact-sheet <folder> --columns=5 --thumb=200 --out=sheet.png, which image types are supported (JPEG, PNG, GIF, WebP), and what the output looks like. Check that the GD extension is available and show a clear message when it isn't. Done when: running the script with --help prints the usage.
- 02
Read and validate the input
~1.5hRead the options with getopt, check that the folder exists, the columns are between 1 and 20, and the thumbnail size is between 50 and 1000 pixels. List the files in the folder sorted by name, keep only real images (checked with getimagesize, not just the extension), and report skipped files. Done when: the tool lists the images it will use and rejects invalid options with a clear message.
- 03
Make thumbnails
~1.5hWrite a function that loads an image with the matching GD function (imagecreatefromjpeg and so on) and resizes it to fit inside a square of the thumbnail size while keeping its proportions, using imagecopyresampled. Free the memory of each image with imagedestroy after using it, since big photos use a lot of memory. Done when: a tall and a wide photo both fit the square without being stretched.
- 04
Build the sheet
~2hCalculate the grid: columns, rows, spacing and room under each thumbnail for its label. Create the sheet with imagecreatetruecolor, fill a background, center each thumbnail in its cell, and write the file name under it with imagestring (shortening long names with …). Save it as PNG or JPEG depending on the output file extension. Done when: a folder of photos becomes one tidy, labeled grid image.
- 05
Handle large folders and errors
~1.5hAdd a --per-page option: when there are more images, create sheet-1.png, sheet-2.png and so on. Skip images that fail to load (for example corrupted files) with a warning instead of stopping. Stop with a clear error when the folder has no images or the output can't be written. Done when: a folder with 50 images and one broken file produces several pages and a warning.
- 06
Test it
~1.5hInstall PHPUnit with Composer and write tests using small images generated in the test: the grid math (rows and page count), thumbnail sizes keeping proportions, label shortening, skipping non-images, and option validation. Done when: vendor/bin/phpunit passes.
Resources
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack