Here are some confused and confusing notes about compose methods.
convert dest src -compose OP -composite result
Result size etc will be of destination.
"-gravity" and "-geometry" position src with respect to dest.
If a mask is given, mask's alpha is ignored; treated as greyscale. Limits area modified (black in mask = no modification, ie result = dest. Mask is aligned with destination.
DP. = Duff-Porter
M. = Mathematical. With default channel (with sync), colours obey the operation but alpha is screened. With no sync, alpha channel obey the operation.
A. = Associative (ie if dest and src can be swapped, result is the same).
aOver. = alpha calculation as for Over.
Atop | DP. aDst. As SrcAtop |
Blend | aPlus. Interpolation. Use with "-define compose:args={src_percent}[,{dest_percent}]". dest_percent defaults to 100-src_percent. |
Blur | aDst. Use with -define compose:args='{Xscale}[x{Yscale}[+{angle}]]'. |
Bumpmap | M. aBumpMap. result = dest * grey(src) |
ChangeMask | aChangeMask. result.alpha = (src==dest) ? 0 : 1, where "==" is defined by fuzz. |
Clear | DP. aClear. result := transparent. |
ColorBurn | aOver. Blackout, but white stays white. result = 1 - ( (1-dest) / src). |
ColorDodge | aOver. Whiteout, but black stays black. result = dest / (1-src) |
Colorize | aHue. Hue followed by Saturate. |
Copy | aCopy. result := dest. Background outside src is unchanged. |
CopyBlack | aDst. result.black = src.black, if they exist. |
CopyBlue | aDst. |
CopyCyan | aDst. Synonym for CopyRed. |
CopyGreen | aDst. |
CopyMagenta | aDst. Synonym for CopyGreen. |
CopyOpacity | aSrc. result.alpha = src_has_alpha ? src.alpha : intensity(src) |
CopyRed | aDst. |
CopyYellow | aDst. Synonym for CopyBlue. |
Darken | M. aOver. src < dest ? src : dest; individual channels |
DarkenIntensity | M. aDarkenIntensity. src < dest ? src : dest; test is intensity; copies all channels |
Divide | M. aOver. As DivideDst. |
DivideDst | M. aOver. result = src/dest |
DivideSrc | M. aOver. result = dest/src |
Difference | M. aOver. result = abs (src - dest) |
Displace | aDisplace. |
Dissolve | aOver. As Over, but modifies alpha, from "-define compose:args={src_percent}[,{dst_percent}]". dest_percent defaults to 100. If 100 < src_percent <= 200, actually sets dest_percent = 200-src_percent; src_percent = 100. |
Distort | aDistort. |
Dst | DP. aDst. No-op. Result := dest. |
DstAtop | DP. aSrc. |
DstIn | DP. aIn. result.alpha = dest.alpha * src.alpha |
DstOut | DP. aDstOut. result.alpha = dest.alpha * (1-src.alpha) |
DstOver | DP. aOver. |
Exclusion | M. aOver. result = src + dest - 2*src*dest |
HardLight | aOver. src <= 0.5 ? 2*src*dest : 1 - 2*(1-src)*(1-dest). Like overlay, but src/dest swapped. |
HardMix | aOver. src <= 1-dest ? 0 : 1. Like overlay, but src/dest swapped. |
Hue | aHue. result.hue = src.hue. |
In | DP. aIn. As SrcIn |
Lighten | M. aOver. src > dest ? src : dest; individual channels |
LightenIntensity | M. aLightenIntensity. src > dest ? src : dest; test is intensity; copies all channels |
LinearBurn | aOver. Blackout. result = src + dest - 1. |
LinearDodge | aOver. Whiteout. result = src + dest, but alpha blending is as for Over. |
LinearLight | aOver. Strong shading, creating whiteout/blackout. result = 2*src + dest - 1. |
Luminize | aHue. result.luminance = src.luminance. |
Mathematics | aOver. result = A*src*dest + B*src + C*dest + D. Use with "-define compose:args='A,B,C,D'". |
Minus | M. aOver. As MinusDst. |
MinusDst | M. aOver. result = src - dest |
MinusSrc | M. aOver. result = dest - src |
Modulate | aDst. Use with "-define compose:args={brightness}[,{saturation}]". result.lightness = src.lightness * brightness. saturation (default 100) generally desaturates. |
ModulusAdd | M. aOver. result = dest + src; wrapped. |
ModulusSubtract | M. aOver. result = src - dest; wrapped |
Multiply | M. aOver. result = dest * src. Darkens. |
None | aDst. |
Out | aOut. As SrcOut |
Overlay | aOver. dest <= 0.5 ? 2*src*dest : 1 - 2*(1-src)*(1-dest). Thus dark dest darkens image; light dest lightens it. Dest black/white stays black/white; otherwise colour and tone influenced by src. Removes (?) transparency. |
Over | DP. aOver. As SrcOver |
PegtopLight | aOver. Similar to SoftLight but simpler. result = 2*src*dest + src^2*(1 - 2*dest) |
PinLight | aOver. Weird. |
Plus | M. aPlus. result = dest + src; clipped. Alpha is added. |
Replace | aCopy. |
Saturate | aHue. result.saturation = src.saturation. |
Screen | M. aOver. result = 1 - (1-src)*(1-dest). Lightens. |
SoftLight | aOver. Similar to HardLight, but softer. src<0.5 ? (2*src-1)*(dest-dest2)+dest : (2*src-1)*(dest0.5-dest)+dest. |
Src | DP. aSrc. result := dest. Background outside src becomes transparent black. |
SrcAtop | DP. aDst. Like Over but dest alpha is unchanged. |
SrcIn | DP. aIn. |
SrcOut | aOut. |
SrcOver | aOver. DP. |
VividLight | aOver. Refinement of LinearLight, avoiding shading at extremes. result = src <= 0.5 ? 1-(1-dest)/(2*src) : dest/(2*(1-src)). |
Xor | DP. aXor. Overlays, then result.alpha = dest.alpha XOR src.alpha |
"compose:outside-overlay=false" prevents Duff-Porter composition clearing the destination image outside the overlaid area.
See also SVG Compositing Specification.
Also see Blending Modes of Photoshop & Co..
See testCompose.bat.
"Outside" means the part of dest that isn't overlapped by src. "Inside" means the image where dest and src overlap.
aClear: result.a = 0
aDst: result.a = dest.a
aIn: Outside: result.a = 0. Inside: result.a = dest.a * src.a
aOver: Outside: result.a = dest.a. Inside: result.a = 1 - ((1 - dest.a) * (1 - src.a)) = 1 - (1 - src.a - dest.a + src.a * dest.a) = scr.a + dest.a - src.a * dest.a
aOut: Outside: result.a = 0. Inside: result.a = src.a * (1 - dest.a)
aSrc: Outside: result.a = 0. Inside: result.a = src.a
aPlus: Outside: result.a = dest.a. Inside: result.a = dest.a + src.a
aXor: Outside: result.a = dest.a. Inside: result.a = dest.a XOR src.a
aBumpMap aChangeMask aCopy aDarkenIntensity aDisplace aDistort aDstOut aHue aLightenIntensityFrom SVG Compositing Specification:
Dca' = f(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa) Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa)
Where:
Dca Premultiplied (by the corresponding alpha value) destination color component
Sca Premultiplied source color component
Da Destination opacity component
Sa Source opacity component
Da Destination opacity component
Operation | f(src,dest) | X | Y | Z | Dca' | Da' |
clear | 0 | 0 | 0 | 0 | 0 | 0 |
src | Sc | 1 | 1 | 0 | Sca | Sa |
dst | Dc | 1 | 0 | 1 | Dca | Da |
src-over | Sc | 1 | 1 | 1 | Sca + Dca*(1-Sa) | Sa + Da - Sa*Da |
dst-over | Dc | 1 | 1 | 1 | Dca + Sca*(1-Da) | Sa + Da - Sa*Da |
src-in | Sc | 1 | 0 | 0 | Sca * Da | Sa * Da |
dst-in | Dc | 1 | 0 | 0 | Dca * Sa | Sa * Da |
src-out | 0 | 0 | 1 | 0 | Sca * (1-Da) | Sa * (1-Da) |
dst-out | 0 | 0 | 0 | 1 | Dca * (1-Sa) | Da * (1-Sa) |
src-atop | Sc | 1 | 0 | 1 | Sca*Da + Dca*(1 - Sa) | Da |
dst-atop | Dc | 1 | 1 | 0 | Dca*Sa + Sca*(1 - Da) | Sa |
xor | 0 | 0 | 1 | 1 | Sca*(1 - Da) + Dca*(1 - Sa) | Sa + Da - 2*Sa*Da |
plus | Sc+Dc | 1 | 1 | 1 | Sca+Dca | Sa+Da (??) |
multiply | Sc*Dc | 1 | 1 | 1 | Sca*Dca + Sca*(1 - Da) + Dca*(1 - Sa) | Sa + Da - Sa*Da |
screen | Sc + Dc - (Sc*Dc) | 1 | 1 | 1 | Sca + Dca - Sca*Dca | Sa + Da - Sa*Da |
overlay | if 2 * Dc <= 1
f(Sc,Dc) = 2 * Sc * Dc otherwise f(Sc,Dc) = 1 - 2 * (1 - Dc) * (1 - Sc) |
1 | 1 | 1 | 2*Sca*Dca + Sca * (1 - Da) + Dca * (1 - Sa)
or Sca * (1 + Da) + Dca * (1 + Sa) - 2*Dca*Sca - Da*Sa |
Sa + Da - Sa*Da |
darken | min(Sc,Dc) | 1 | 1 | 1 | min(Sca*Da, Dca*Sa) + Sca * (1 - Da) + Dca * (1 - Sa) | Sa + Da - Sa*Da |
lighten | max(Sc,Dc) | 1 | 1 | 1 | max(Sca*Da, Dca*Sa) + Sca * (1 - Da) + Dca * (1 - Sa) | Sa + Da - Sa*Da |
color-dodge | if Sc == 1
f(Sc,Dc) = 1 otherwise f(Sc,Dc) = min(1, Dc/(1 - Sc)) |
1 | 1 | 1 | if Sca == Sa and Dca == 0
Dca' = Sca * (1-Da) otherwise if Sca == Sa Dca' = Sa * Da + Sca * (1-Da) + Dca * (1-Sa) otherwise if Sca < Sa Dca' = Sa * Da * min(1, Dca/Da * Sa/(Sa-Sca)) + Sca * (1-Da) + Dca * (1-Sa) |
Sa + Da - Sa*Da |
color-burn | if Sc == 0
f(Sc,Dc) = 0 otherwise f(Sc,Dc) = 1 - min(1, (1-Dc)/Sc) |
1 | 1 | 1 | if Sca == 0 and Dca == Da
Dca' = Sa * Da + Dca * (1-Sa) otherwise if Sca == 0 Dca' = Dca * (1-Sa) otherwise if Sca > 0 Dca' = Sa * Da * (1 - min(1, (1 - Dca/Da) * Sa/Sca)) + Sca * (1-Da) + Dca * (1-Sa) |
Sa + Da - Sa*Da |
hard-light | if 2 * Sc <= 1
f(Sc,Dc) = 2 * Sc * Dc otherwise f(Sc,Dc) = 1 - 2 * (1-Dc) * (1-Sc) |
1 | 1 | 1 | if 2 * Sca <= Sa
Dca' = 2*Sca*Dca + Sca * (1-Da) + Dca * (1-Sa) otherwise Dca' = Sa*Da - 2 * (Da-Dca) * (Sa-Sca) + Sca * (1-Da) + Dca * (1-Sa) = Sca * (1+Da) + Dca * (1+Sa) - Sa*Da - 2*Sca*Dca |
Sa + Da - Sa*Da |
soft-light | if 2 * Sc <= 1
f(Sc,Dc) = Dc - (1 - 2*Sc) * Dc * (1-Dc) otherwise if 2 * Sc > 1 and 4 * Dc <= 1 f(Sc,Dc) = Dc + (2*Sc - 1) * (4*Dc * (4*Dc + 1) * (Dc-1) + 7 * Dc) otherwise if 2 * Sc > 1 and 4 * Dc > 1 f(Sc,Dc) = Dc + (2*Sc - 1) * ((Dc)^0.5 - Dc) |
1 | 1 | 1 | if 2 * Sca <= Sa
Dca' = Dca * (Sa + (2*Sca - Sa) * (1-m)) + Sca * (1-Da) + Dca * (1-Sa) otherwise if 2 * Sca > Sa and 4 * Dca <= Da Dca' = Da * (2*Sca - Sa) * (16 * m^3 - 12 * m^2 - 3*m) + Sca - Sca * Da + Dca otherwise if 2 * Sca > Sa and 4 * Dca > Da Dca' = Da * (2*Sca - Sa) * (m^0.5 - m) + Sca - Sca * Da + Dca Where: m = Dca/Da |
Sa + Da - Sa*Da |
difference | abs(Dc-Sc) | 1 | 1 | 1 | Sca + Dca - 2 * min(Sca * Da, Dca * Sa) | Sa + Da - Sa*Da |
exclusion | Sc + Dc - 2 * Sc * Dc | 1 | 1 | 1 | (Sca * Da + Dca * Sa - 2*Sca*Dca) + Sca * (1-Da) + Dca * (1-Sa) | Sa + Da - Sa*Da |
testCompose.bat:
if "%IM%"=="" call imagepath setlocal enabledelayedexpansion set I=%IM% set SIZE=-size 80x80 set SIZE2=-size 100x100 %I%convert %SIZE% xc:red gradient: -compose CopyOpacity -composite tc_red.png %I%convert %SIZE2% xc:green gradient: -rotate 90 -compose CopyOpacity -composite tc_green.png rem %I%convert %SIZE% xc:red tc_red.png rem %I%convert %SIZE2% xc:green -rotate 90 tc_green.png set COMPLIST=%TEMP%\compList.txt %I%convert -list compose >%COMPLIST% echo Divide>>%COMPLIST% echo Minus>>%COMPLIST% cSort /i%COMPLIST% /o%COMPLIST% rem goto skipImages type %COMPLIST% for /F %%L in (%COMPLIST%) do ( %I%convert tc_green.png tc_red.png -gravity Center -compose %%L -composite ^ -write tca_%%L.png ^ -alpha Extract ^ tca_%%L_a.png ) :skipImages goto skipCompare del test_comp.lis goto skipListComp for /F %%L in (%COMPLIST%) do ( %I%compare -metric RMSE ^ tca_%%L_a.png ^ tca_Over_a.png ^ NULL: for /F "tokens=1,2 usebackq delims=() " %%R IN (`%I%compare ^ -metric RMSE ^ tca_%%L_a.png tca_Copy_a.png ^ NULL: 2^>^&1`) do ( echo answer: %%R %%S set COMP_INT=%%R set COMP_FLT=%%S echo %%R,%%L>>test_comp.lis ) ) cSort /itest_comp.lis /otest_comp.lis /k0,1 :skipListComp for /F %%L in (%COMPLIST%) do ( %I%compare -metric RMSE ^ tca_%%L_a.png ^ tca_Over_a.png ^ NULL: for /F "tokens=1,2 usebackq delims=() " %%R IN (`%I%compare -metric RMSE tca_%%L_a.png tca_Out_a.png NULL: 2^>^&1`) do ( echo answer: %%R %%S set COMP_INT=%%R set COMP_FLT=%%S echo %%R,%%L>>test_comp.lis ) ) cSort /itest_comp.lis /otest_comp.lis /k0,1 :skipCompare
All images on this page were created by the commands shown, using:
%IM%identify -version
Version: ImageMagick 6.9.5-3 Q16 x86 2016-07-22 http://www.imagemagick.org Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC License: http://www.imagemagick.org/script/license.php Visual C++: 180040629 Features: Cipher DPC Modules OpenMP Delegates (built-in): bzlib cairo flif freetype jng jp2 jpeg lcms lqr openexr pangocairo png ps rsvg tiff webp xml zlib
Source file for this web page is compose.h1. To re-create this web page, execute "procH1 compose".
This page, including the images, is my copyright. Anyone is permitted to use or adapt any of the code, scripts or images for any purpose, including commercial use.
Anyone is permitted to re-publish this page, but only for non-commercial use.
Anyone is permitted to link to this page, including for commercial use.
Page version v1.0 19-Apr-2014.
Page created 29-Nov-2017 13:59:56.
Copyright © 2017 Alan Gibson.