AI-Created Software

The following AI-generated aka vibe-coded software. The software is specific to my needs and my system and may not work for you or your system. Support is limited, but if you report a bug I'll certainly look into it. All code is provided in a zip file for you to review should you choose.

Image Blender with Mask

A desktop GUI tool for blending two images together — a “before” and an “after” — using a grayscale mask to control where the blend happens, and a slider to control how much. White areas of the mask reveal the after image, black areas keep the before image, and gray areas blend proportionally.

Typical uses: before/after photo edits, retouching comparisons, texture or terrain blending, compositing two renders, or any situation where you want to dial in a spatially-varying crossfade between two images and inspect the result at full resolution.

Requirements

  • Python 3
  • Pillow and NumPy
  • Tkinter (ships with most Python installs; on some Linux distributions you may need to install it separately, e.g. sudo apt install python3-tk)
pip install pillow numpy

Optionally, to enable dragging files onto the window:

pip install tkinterdnd2

Without it the app works normally — it just won’t accept dropped files.

Running

python image_blender_with_mask.py

Basic workflow

  1. Load Before Image — the reference image. Its resolution becomes the default working resolution for the rest of the app.
  2. Load After Image — the image that gets blended in.
    It’s automatically resampled to match the before image wherever needed.
  3. Load Mask Image — any image, automatically converted to grayscale. White reveals the after image, black keeps the before image, gray blends proportionally.
  4. Drag the Before / After slider at the bottom to control the overall blend strength: 0% is pure before, 100% is the full mask-weighted blend.

You can also drag and drop files onto the window (with tkinterdnd2 installed). Dropped images fill the Before, After, and Mask slots in that order; if all three are already loaded, you’ll be asked which slot to replace. Dropping a .ibwmproj file opens that project.

None of the three images need to be the same pixel size — each is resized as needed depending on which one you’re currently viewing at full resolution (see Zoom and viewing modes below).

Viewing the image

  • Fit to Screen — scales the image to fit the current window, without enlarging it past its native size. The button label shows the window’s current pixel dimensions.
  • Actual Size (Before) — shows the before image pixel-for-pixel at its native resolution; the after image and mask are scaled to match.
  • Actual Size (After) — shows the after image pixel-for-pixel at its native resolution; the before image and mask are scaled to match.
  • 2x (Smaller Image) — whichever of the two images has the smaller native resolution is shown at 2x its own native size.

Panning and zooming

  • Click and drag with the left mouse button to pan around the image when it’s larger than the visible window.
  • Mouse wheel zooms in and out in 10% steps, centered on the cursor position, from 10% up to 100%. If one of the loaded images has a larger native resolution than the one currently being shown at “native” size, the wheel can zoom in further — up to the point where the smaller image is upscaled to match the larger image’s actual pixel size.
  • Hold the B key at any time to momentarily see the pure before image, and release to return to the current blend. This never affects what gets saved or exported.
  • Zoom and pan reset to a sensible default whenever you switch view modes or load a new before image; otherwise your position and zoom level are preserved as you adjust the slider or reload images.

Pixel inspector

A readout directly below the image shows, for whatever pixel is under the cursor: its coordinate in the working image, the before and after RGB values, the mask value (as both 0–255 and a percentage), and the resulting blended RGB value. This is the quickest way to answer “what is the mask actually doing here?” without guessing from the overlay.

Mask controls

  • Toggle All-White Mask — temporarily replaces the mask with solid white (full after image everywhere), overriding whatever mask is loaded. Click again to return to the loaded mask.
  • Toggle All-Black Mask — same idea, but solid black (full before image everywhere). The two overrides are mutually exclusive.
  • Mask Overlay — overlays a semi-transparent colour visualization of the currently active mask on top of the preview, so you can see exactly where it’s light or dark relative to the image underneath. Colour and opacity are configurable in Mask Tools. This is a display-only aid — it never affects the saved result.

Mask Tools

Mask Tools… (also under the Mask menu) opens a panel of non-destructive adjustments. Everything updates the preview live, and none of it modifies your mask file on disk:

  • Source channel — build the mask from the image’s luminance, or from its individual Red, Green, Blue, or Alpha channel.
    Picking Alpha on an image without an alpha channel falls back to luminance.
  • Invert mask — swap which side of the mask reveals the after image.
  • Levels — black point and white point remap the mask’s range, so you can boost a flat or low-contrast mask without leaving the app.
  • Threshold — collapse the mask to hard black-and-white at a chosen level, for a crisp edge instead of a gradient.
  • Feather — Gaussian-blur the mask by a given radius to soften its edges.
  • Overlay colour and opacity — the overlay defaults to red at 50%, which is a poor choice over reddish imagery; green, blue, magenta, cyan, yellow, and white are also available.
  • Generate from Difference — build a mask automatically from where the before and after images actually differ, normalized so even a subtle edit produces a usable starting point.
    Useful as a base to then threshold or feather.
  • Reset — return every adjustment to its default.

All mask adjustments are saved into (and restored from) project files.

Saving and exporting

Save Project

Save Project… creates a self-contained project folder:

  1. You’re asked to pick a parent folder — the app creates a sub-folder inside it, named after the before image’s filename.
  2. Inside that sub-folder, it places:
    • The before, after, and mask source files, either linked or copied (see below).
    • An actual copy of the current blend result, saved as result.png, at the before image’s native resolution.
    • The project file (<name>.ibwmproj, JSON), recording the source paths, slider position, zoom mode/level, and all mask adjustments.

A before image must be loaded to save a project, since its filename drives the folder name.

Linked vs portable projects

By default source files are symlinked (with a hardlink fallback on systems where symlinks aren’t permitted), which keeps project folders tiny. But links break the moment the folder moves to another machine or drive.

Enable File → Portable export (copy files instead of links) to write real copies instead. A portable project folder can be moved, archived, or handed to someone else and still opens correctly — the loader falls back to files sitting beside the project file when the originally recorded paths no longer exist. The setting persists between sessions.

If your mask was generated from difference rather than loaded from disk, it’s written into the project folder as generated_mask.png so the project stays reproducible.

Load Project

Load Project… reopens a .ibwmproj file: it reloads the before, after, and mask images and restores the slider, zoom, and every mask adjustment. File → Recent Projects lists the last 10 projects you saved or opened.

Reload and auto-reload

Reload Images and Mask re-reads all three images from their current paths — useful when another application has just re-saved one of them. The slider, zoom, pan position, mask adjustments and overrides are all left untouched; only the pixel content refreshes.

File → Auto-reload when files change on disk turns this into a live link with your image editor: the app polls the source files once a second and reloads automatically when any of them changes.
Combined with an editor on a second monitor, you can tweak a mask and watch the blend update without touching the app.

Export

File → Export Image… writes the current blend with a choice of:

  • Output size — the before image’s native resolution, the after image’s native resolution, or the current on-screen view size.
  • Format — PNG, JPEG, TIFF, WEBP, or BMP.
  • Quality — for the lossy formats (JPEG, WEBP).

File → Export Slider Sweep… renders a series of frames stepping the slider across a range, for demonstrating an edit:

  • Choose a start %, end %, and frame count.
  • Output as a folder of numbered PNG frames, or a single animated GIF with a configurable frame duration.
  • Ping-pong plays the sweep forwards then backwards for a seamless loop.

Window memory

The app remembers its window size, position, and maximized state between sessions, saved to image-blender-with-mask.ini next to the script itself. If that file is missing or unreadable, it just falls back to a default window size.

Project file format

A .ibwmproj file is plain JSON:

{
  "format": "image-blender-with-mask-project",
  "version": 3,
  "before_image": "/absolute/path/to/before.png",
  "after_image": "/absolute/path/to/after.png",
  "mask_image": "/absolute/path/to/mask.png",
  "generated_mask": null,
  "slider_value": 42.5,
  "zoom_mode": "fit",
  "zoom_percent": 76.0,
  "portable": true,
  "mask_settings": {
    "channel": "Luminance",
    "invert": false,
    "black_point": 0.0,
    "white_point": 255.0,
    "threshold_enabled": false,
    "threshold": 128.0,
    "feather": 0.0
  },
  "overlay": { "color": "Red", "opacity": 50.0 }
}

Any of the three image fields may be null if that image wasn’t loaded when the project was saved. generated_mask names a mask file written into the project folder when the mask came from Generate from Difference rather than from disk.

Notes and limitations

  • Symlink creation on Windows often requires Developer Mode or administrator rights; without it, the app transparently falls back to hardlinks and tells you when it does.
  • “Maximized” window detection works reliably on Windows and most Linux window managers; macOS’s native window zoom doesn’t always report through Tkinter the same way, so restoring a maximized state there may not always take effect (size and position still will).
  • All processing happens in memory using Pillow and NumPy; there’s no hard limit on image size, but very large images will naturally take longer to resample when switching zoom modes. While you drag the slider the blend is computed at screen resolution rather than full resolution and re-rendered at full quality when you let go, so dragging stays responsive on large images.
  • Drag-and-drop requires the optional tkinterdnd2 package. Everything else works without it.
  • Auto-reload polls file modification times once a second. If your editor writes files in stages, a reload may briefly catch an intermediate state; press Reload Images and Mask to refresh again.
(1 votes, average: 5.00 out of 5)

Leave a Reply

Your email address will not be published. Required fields are marked *

Notify me of followup comments via e-mail.