AI

Before/After Photo Composer: 9 Sizes in 3 Seconds

← Back to all posts

I run marketing for 4 plastic surgery practices in Chicago. Every time a surgeon sends over before/after patient photos, I need to resize and brand those photos for every channel we publish to:

Seven sizes. But some need a side-by-side composite and some need individual crops with labels. Real output is 9 files per photo pair.

I was doing this in Canva. One at a time. Four brands, each with different logos and surgeon names. A single photo pair took 20-30 minutes. We get 3-5 new pairs per week across the brands. That's an entire afternoon just resizing photos.

What I Built

Two Python tools. Built with Claude Code in about 3 hours across 2 sessions.

ba-composer.py does the horizontal formats, the side-by-side composites. Takes two photos and outputs:

ba-individual.py does the vertical formats, the tall crops for Stories and Pinterest. Takes one photo and:

Both tools know all 4 brands. Each brand has its own logo, practice name, and surgeon roster in a shared config file. I bundled the font (Lato) as .ttf so it doesn't depend on whatever's installed on the machine.

Day-to-Day

Drop the photos in a folder. Run one command. Batch mode auto-pairs before and after images based on filename, so if a file has "Skinny BBL" in the name, it detects the procedure automatically.

One command. 9 files. Plus an alt text CSV with procedure-specific accessibility descriptions for every image. That CSV feeds directly into email uploads and website gallery updates.

Things That Broke

The XSculpt logo was 19,650px wide. 138 million pixels. Pillow (the Python image library) threw a decompression bomb warning and refused to open it. My first instinct was to raise the pixel limit in code, but that felt wrong. Just resized the logo to 2,400px instead. Problem gone.

Rounded corners clipped unevenly on certain aspect ratios in the first version. The fix was making the corner radius scale proportionally to the output size instead of a fixed pixel value. Took maybe 3 tries to get it right.

Why It Holds Up

This isn't a one-off script. Adding a new brand is one entry in the config: logo path, practice name, surgeon list. Adding a new surgeon is one line. Adding a new output size is one tuple.

Last month a new surgeon joined CAS. I added his name to the config. Done. Every photo he sends from now on gets branded correctly without me touching anything else.

The alt text generation means I'm not writing image descriptions by hand. The folder structure matches what I already use for email campaigns, so outputs drop right into the existing workflow without renaming or moving files around.

The Math

Before: 20-30 minutes per photo pair in Canva. Manual. Easy to miss a size or forget to update a surgeon name.

After: ~3 seconds per photo pair. One command.

Four brands, 3-5 new pairs per week. That's 2-4 hours of production work replaced by a few terminal commands. Every week.

If You're Considering Something Like This

I'm not a developer. Claude Code wrote the Python, debugged the image processing errors, and structured the config. My job was knowing what I needed: the sizes, the branding rules, where the outputs go. If you have a repetitive visual production task with consistent rules across multiple brands, this approach works. Paid for itself in the first week.