Image Blender with Mask

The following is 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.

A desktop tool for blending an after image into a before image, weighted by a grayscale mask and scaled by a single slider. White areas of the mask take the after image, black areas keep the before image, and grays mix the two. At 0% the result is the pure before image; at 100% it is the full mask-weighted blend.

It is built for comparing and dialing in edits: retouching, relighting, compositing tests, or any case where you want an edit applied only in some places and only by some amount.

Features

  • Live blend preview with a 0–100% slider, pan, and zoom from 10% to 800% (hard pixel edges above 100% for inspecting mask edges).
  • Comparison views: the Show switch picks the blend, a draggable before/blend wipe (W) or the mask on its own; hold B for the pure before image or M for the mask, and turn on Overlay (O) for a colored mask overlay.
  • Mask tools: choose the source channel (luminance, red, green, blue or alpha), invert, set black and white levels, apply a hard threshold, and feather the edge. All adjustments preview live and can be undone.
  • Generate a mask from the difference between the before and after images.
  • Full-precision masks: 16-bit and floating-point masks are read without clipping and processed in floating point. The processed mask can be exported as a 16-bit PNG or TIFF.
  • Linear-light blending as an option, for physically smoother mixes between very different colors.
  • Pixel inspector showing before, after, mask, blend weight and result values under the cursor, always at full resolution.
  • Projects that save the three sources (linked or copied), every setting, and a rendered result into one folder.
  • Export the result as PNG, JPEG, TIFF, WebP or BMP, keeping the before image’s color profile.
  • Slider sweeps: export a range of slider values as numbered PNG frames, an animated GIF, a lossless animated WebP, or an animated PNG, with easing and optional ping-pong.
  • File watching: automatically reload sources when another application saves them.
  • Drag and drop of images and projects (optional, see below).
  • Every action on screen: there is no menu bar. Each command is a button or switch above the image, and its tooltip names its keyboard shortcut.
  • Neutral gray interface that never tints how you see the images, drawn to match your display scaling. See Interface and display scaling.

Requirements

  • Python 3.8 or newer with Tkinter (included with the python.org installers; on Debian/Ubuntu install python3-tk)
  • Pillow and NumPy
  • Optional: tkinterdnd2 for drag and drop

Tested with Python 3.12 and Pillow 12.

Installation

pip install pillow numpy
pip install tkinterdnd2   # optional, enables drag and drop

The app is a single script, so there is nothing else to install. If a file named image-blender-with-mask.ico sits next to the script, it is used as the window icon.

Running

python image-blender-with-mask.py

Command line

Every option is named and takes a value, written --name VALUE or --name=VALUE, in any order.
--help lists them with their defaults. Script launchers that read the options (such as Scriptary) list --working-folder-path first.

Option What it does
--working-folder-path FOLDER The folder for the settings file and temporary files, created if needed. Blank or not given: the folder the app’s script is in.

A mistake on the command line, such as an unknown option or a folder that can’t be created, is reported with “Use –help for usage.” and exit status 2. Started without a console (pythonw.exe), the message is shown in a message box instead.

Quick start

  1. Open a before image (Ctrl+1), an after image (Ctrl+2) and a mask (Ctrl+3). You can also drag files onto the window.
  2. Move the slider, or use the Left and Right arrow keys, to set how strongly the after image is applied.
  3. Refine the mask in Mask tools if needed, and check the edges with Overlay (O), Show: Wipe (W) or by holding M.
  4. Export image (Ctrl+E) or Save project (Ctrl+S).

If you don’t have a mask, choose All white in the Mask switch to apply the after image uniformly, or use Generate from difference in Mask tools.

Using the app

The controls

Everything is in two strips above the image:

  • Files: Open before, Open after, Open mask, Reload sources and Watch files on the left; Export image, Export sweep, Portable, Recent, Load project and Save project on the right.
  • View and mask: View (with zoom − and +), Show, Mask (with Invert), Overlay, Linear light and Mask tools, then a summary of the mask’s settings, with Undo and Redo at the right end.

Hover over a control for what it does and its keyboard shortcut. A button is grayed out until it can act: the exports need a before and after image and a mask (or a mask override), Invert needs a loaded mask, and Recent needs a project opened before.

Loading images

The after image and mask are resampled to the before image’s size, so they don’t need to match it exactly. If the after image has a different aspect ratio, it is stretched to fit and a warning appears in the slot strip. Photos are turned upright according to their camera orientation.

Supported formats are PNG, JPEG, TIFF, WebP and BMP.

With tkinterdnd2 installed, you can drop files in two ways:

  • Onto a Before, After or Mask slot to fill exactly that slot.
  • Onto the image area to fill empty slots. Files whose names contain words like before, after, mask or matte go to the matching slot; the rest fill the remaining empty slots in order. If every slot is already full, you’re asked which slot to replace.

Dropping a project file opens that project.

Viewing

The View switch sets the base scale:

Mode Shows
Fit The whole image, scaled to the window
1:1 before The before image at actual size
1:1 after The after image at actual size
2× The smaller of the two images at double size

The mouse wheel, the − and + buttons beside the View switch, and the + and − keys zoom from any mode, keeping the point under the cursor in place. 0 returns to Fit. Drag with the mouse to pan.

The Show switch chooses what the image area shows: the Blend, a Wipe with the before image on the left of a divider and the blend on its right (W turns it on and off), or the Mask on its own, in gray. Holding B shows the pure before image and holding M the mask, for as long as the key is down, whatever Show is set to.

In wipe view, drag the divider to move it; drag anywhere else to pan.

The mask

The Mask switch chooses between the Loaded mask, All white and All black. Invert beside it (I) swaps where the after image is applied, the same as Invert in Mask tools. Linear light blends in linear light rather than on the files’ encoded values, for smoother mixes between very different colors. The overlay color and opacity are set in Mask tools and never affect saved output.

Mask tools offers:

Setting Effect
Channel Which channel of the mask file is used
Invert Swaps where the after image is applied
Black / white point Stretches the mask’s tonal range
Threshold Turns the mask into a hard-edged selection at a chosen level
Feather Blurs the mask edge by the given radius in pixels

The Mask tools window opens where you last closed it. While you drag a Mask tools slider, the preview updates at screen resolution. The full-resolution mask is rebuilt in the background a moment after you stop. Save mask writes the adjusted mask at its own resolution as a 16-bit PNG or TIFF.

Every mask change, including loading a new mask or generating one, can be undone with Undo (at the right end of the view controls) or Ctrl+Z, and redone with Redo, Ctrl+Shift+Z or Ctrl+Y. The buttons are grayed out when there is nothing to undo or redo. A continuous slider drag counts as one step.
The last 100 changes are kept, until you close the app.

Pixel inspector

The bar below the slider shows the values under the cursor: image coordinates, before and after RGB, the mask value and the blend weight it produces, and the resulting RGB. These are computed from the full-resolution sources, whatever the zoom level.

Watching files

Turn on Watch files to reload any source that changes on disk, such as a mask you are painting in another editor.
Sources are checked once a second, on a separate thread, so a sleeping or network drive doesn’t freeze the window. A file that disappears or can’t be read is reported in the slot strip, and the app retries on the next check.

Ctrl+R reloads all sources on demand. The slider, zoom and mask settings are kept.

Projects

Save project asks for a folder and creates a sub-folder inside it named after the before image. That sub-folder contains:

  • the project file (<name>.ibwmproj, plain JSON)
  • links to the three source files, or copies of them if Portable is on (beside Recent)
  • generated_mask.png, if the mask was generated rather than loaded from a file
  • result.png, the rendered blend at the before image’s size

Hover over Save project or Load project for a summary of the files each writes or expects.

Projects restore the images, the slider value, the zoom, all mask settings, the mask override, the overlay settings and the linear-light option. Recently opened projects are listed under Recent, which also has Clear recent.

Turn on Portable when you want to move or share a project. Linked projects stay small but depend on the original files staying where they are. On systems where symbolic links aren’t allowed, hard links are used instead.

The title bar shows • while there are unsaved changes, and the app offers to save before you close it or open another project.

Exporting

Single image

Export image (Ctrl+E) saves the blend at the before image’s size, the after image’s size, or the current zoomed-out view size.

Format Notes
PNG Lossless
JPEG Adjustable quality (95 to start with), without chroma subsampling
TIFF Lossless, LZW-compressed
WebP Adjustable quality (95 to start with)
BMP Uncompressed; no color profile

The file extension you type decides the format, so result.jpg is always saved as a JPEG. Every export is written to a temporary file beside the target first and then put in its place, so a failed export never leaves a half-written file over an earlier one. The before image’s ICC color profile is embedded in every format except BMP, and its camera data (EXIF) in PNG, JPEG and WebP, with the orientation reset since the result is already upright.

Slider sweep

Export sweep (Ctrl+Shift+E) renders a series of slider values between a start and end percentage. It can export:

  • PNG frames: numbered sweep_000.png, sweep_001.png… files in a folder. If the folder already contains frames from an earlier sweep, you’re offered the chance to delete them first.
  • Animated GIF, animated WebP (lossless) or animated PNG, each as a single file with a chosen frame duration.

Easing controls how the slider values are spaced across the frames: linear, ease in, ease out, or ease in-out.
Ping-pong plays the sweep forward and then back.

A progress bar tracks rendering, and Cancel stops the export. Animations hold every frame in memory while they are encoded, so you’re warned first if that would need more than about 2 GB.

Keyboard shortcuts

On macOS, use Cmd in place of Ctrl.

Keys Action
Ctrl+1 / Ctrl+2 / Ctrl+3 Load before / after / mask
Ctrl+O Load project
Ctrl+S Save project
Ctrl+E Export image
Ctrl+Shift+E Export slider sweep
Ctrl+R Reload sources
Ctrl+Z Undo mask change
Ctrl+Shift+Z or Ctrl+Y Redo mask change
Left / Right Slider −1% / +1%
Shift+Left / Shift+Right Slider −10% / +10%
Home / End Slider to 0% / 100%
+ / − Zoom in / out
0 Fit to window
Hold B Show the pure before image
Hold M Show the mask on its own
O Toggle the mask overlay
W Toggle the wipe comparison
I Invert the mask

Each button’s tooltip shows its shortcut. Single-key shortcuts act in the main window only. No shortcut acts while you are typing in a field (there, Ctrl+Z undoes your typing) or while a dialog such as Export is open. The Ctrl shortcuts work the same with Caps Lock on.

Interface and display scaling

Every color in the interface is a neutral gray, with the same red, green and blue values, so nothing next to the images tints how you see them. The only colors on screen come from the images themselves and the mask overlay. A chosen option is shown filled in light gray, and anything that needs your attention, such as a missing source file, is shown in brighter text with a ⚠ sign.

Everything is drawn to match the display scaling set in Windows or Linux, not only the text: buttons, spacing, sliders, badges and the wipe divider. At 150% they are all half as large again as at 100%. On Windows the app tells the system it handles scaling itself, so text is drawn sharply at the screen’s own resolution instead of being stretched. On macOS, sizes follow the system’s points.

When the window is narrow, the file buttons use shorter labels, and when that isn’t enough, the exports and the project buttons move onto a second row. The view and mask controls take as many rows as they need, up to three: the first row keeps the mask summary, and Undo and Redo at its right end; and the key hint under the slider is shortened, its full text in a tooltip. At the smallest window size (700 × 600 at 100% scaling) nothing is cut off.

Settings file

Window size and position, where Mask tools and the other popup windows were last closed, recent projects, and preferences such as portable export and file watching are stored in image-blender-with-mask.ini in the working folder (see Command line), and saved when the app closes.
If a saved window position is no longer on a monitor (on Windows, each monitor is checked), the window opens at its saved size in a default position instead; a popup window opens centered over the main window.

Until November 2026 the default working folder was %APPDATA%\image-blender-with-mask on Windows (~/Library/Application Support/image-blender-with-mask on macOS, ~/.config/image-blender-with-mask elsewhere); now it is the app’s own folder. The first time the app starts with no settings of its own there, it copies the settings file from that old folder, which is then left as it was and can be deleted. The oldest versions kept a settings file of another layout next to the script; that one is converted in place the same way. --settings-file-path is gone: use --working-folder-path instead.

If the settings can’t be read (for example, after editing the file by hand), the app starts with the defaults; a value it doesn’t understand falls back to its default. If the working folder can’t be created, the app runs without saving settings and says so on the console. If the settings file can’t be written, the app says so in a message box and carries on.

Troubleshooting

Drag and drop doesn’t work. Install tkinterdnd2 with pip install tkinterdnd2 and restart the app. Without it, the drop hint is not shown and files must be opened with the Open buttons.

“Tkinter is not available”. Your Python was built without Tk; the app says so and exits. On Debian or Ubuntu run sudo apt install python3-tk; on other systems, use the python.org installer or your package manager’s Tk package.
--help works without it.

My settings are gone after updating. Settings now live in the working folder, by default the app’s own folder (see Settings file). They are copied from the old folder only when the working folder has no settings yet; if you started the new version with --working-folder-path pointing somewhere else first, copy the values across by hand, or run with --working-folder-path set to the old folder.

The taskbar shows the app as Python, or a pinned shortcut opens a second button. On Windows the app now has its own taskbar ID, so a shortcut pinned by an earlier version belongs to Python. Unpin it, start the app, and pin its own button again.

A linked project shows missing files. The original source files were moved or deleted. Restore them, or re-save the project with Portable turned on while the files are still available.

The window opens smaller than you left it, once, after updating. On Windows with display scaling, versions before the app became DPI-aware saved the window size in scaled-down units. Resize or maximize the window once and the new size is remembered.

The mask looks inverted or too faint. Check the source channel and the invert setting in Mask tools, and try the black and white points. Holding M shows exactly the mask that is being applied.

Testing

The tests use pytest and drive the real window on images they make themselves; they don’t touch your files or settings.

pip install pytest
python -m pytest          # from the app's folder

They need a display: without one (on Linux), they start Xvfb and openbox themselves if installed. To test at 150% display scaling, start Xvfb :98 -screen 0 3000x1800x24 -dpi 144 and run DISPLAY=:98 python -m pytest.

They cover the image and mask functions without a window (invert, levels, threshold, feather, blending in both modes, 16-bit and alpha masks, EXIF orientation, project files, a failed export leaving the old file), blending in the window (the slider, the mask, a 16-bit mask kept at full precision), a file that fails to open, export (quality, chroma subsampling, the color profile and camera data), projects (a round trip, a damaged project file left alone, and the Save and Load project tooltips naming the files), settings (saved and restored, a hand-edited file, settings from the old folder and the oldest layout taken over once, a failed save reported), popup windows reopening where they were closed, the command line (with --working-folder-path first and the script’s folder as the default), the neutral-gray styles, buttons and switches at one height, Export as the one solid button, the crosshair over the image and scrollbars shown only when needed, controls fitting at the smallest window, the switches with real clicks, Ctrl shortcuts while typing and with Caps Lock on, the hold keys waiting while a dialog is open, file watching asking the disk off the main thread (a changed file reloaded, a missing one reported), the Undo and Redo buttons, every former menu command as a working button or switch, both strips wrapping at three window widths, tooltips (one for a whole file cell, above a control at the bottom of the window, none when blank), closing without leftover jobs, and the icon. The 38 tests took about 9 to 11 seconds, and all passed at 100% and at 150% display scaling, with Python 3.12, Pillow 13.0, NumPy 2.5 and pytest 9.2 under Linux.

Limitations

  • Before and after are blended as their files store them. Export both from darktable with the same output color profile; the result carries the before image’s profile. Linear light assumes an sRGB-like tone curve.
  • Camera RAW files can’t be opened: export the before and after from darktable instead, since only the same processing gives images that line up pixel for pixel.
  • The Windows-only parts (display scaling awareness, the taskbar ID and the icon) aren’t covered by the tests, which run under Linux.
Download Release:

⬇️ Image Blender with Mask.zipLast Updated: November 4, 2026
(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.