snibgo's ImageMagick pages

Gradients Cookbook

This page is mostly about two-dimensional greyscale gradients, ranging from black to white, that have different values for both x and y dimensons. They are useful as masks for processing photographs, for video transitions, and a variety of graphics effects.

Introduction

I use ImageMagick gradients as masks for processing photographs and for video transitions. Gradients are usually monochrome images with smooth transitions from black through gray to white.

For one-dimensional gradients, see Clut cookbook.

The scripts are all Windows "bat" syntax, and readily translatable to other languages.

The environment variable %IMG7% is set to the directory that contains the IM magick program.

The dimensions of the mask are generally taken from the photograph or video frame:

FOR /F "tokens=1,2" %%i ^
IN ('%IMG%magick identify -ping -format "%%w %%h" photo.jpg') ^
DO (
  set WIDTH=%%i
  set HEIGHT=%%j
)

... or ...

FOR /F "usebackq" %%L IN (`%IMG7%magick identify -ping -format "WIDTH=%%w\nHEIGHT=%%h" %SRC%`) DO set %%L

Masks are used to blend still photographs, such as two versions of one image, with different saturations:

%IMG7%magick ^
  {photo1} ^
  {photo2} ^
  {mask} ^
  -alpha off ^
  -compose ^
  {outphoto}

... or ...

%IMG7%magick ^
  {photo1} ^
  ( {photo2} {mask} -alpha off -compose Copy-Opacity -composite ) ^
  -compose Over -composite ^
  {outphoto}

Where the mask is black, Copy-Opacity makes the result transparent, so photo1 becomes visible. Where the mask is white the result is opaque, so photo2 is visible.

For videos, using clippings option TransitionMask, we modulate the influence of the mask over time:

%IMG7%magick ^
  {clip1_frame} ^
  ( {clip2_frame} ^
    ( {mask} -alpha off -level %lev1%x%lev2%%% ) ^
    -compose Copy_Opacity -composite ^
  ) ^
  -compose Over -composite ^
  {outclip_frame}

... where 0 <= lev1 <= lev2 <= 100.

The above command is equivalent to:

%IMG7%magick ^
  {clip2_frame} ^
  ( {mask} -alpha off -level %lev1%x%lev2%%% ) ^
  -compose Copy_Opacity -composite ^
  {clip1_frame} ^
  -compose Dst_Over -composite ^
  {outclip_frame}

Basics

The basic gradient is white at the top, black at the bottom:

set WIDTH=300
set HEIGHT=200

%IMG7%magick ^
  -size %WIDTH%x%HEIGHT% ^
  gradient: ^
  gr_baseGrad.png
gr_baseGrad.png

50% gray occurs at the position mid-way between black and white. Similarly for all percentages. So thresholding at x% results in x% of pixels being black, and modulating a video threshold at a constant speed results in a constant speed of transition.

For a sideways transition, we rotate, so we need to invert the initial width and height.

%IMG7%magick ^
  -size %HEIGHT%x%WIDTH% ^
  gradient: ^
  -rotate 90 ^
  gr_baseGradS.png
gr_baseGradS.png

This is used for a basic left-to-right transition:

%IMG7%magick ^
  -size %WIDTH%x%HEIGHT% ^
  xc:Red ^
  xc:Green ^
  ( gr_baseGradS.png -level 20%%x30%% ) ^
  -composite ^
  gr_baseEx.png
gr_baseEx.png

A radial-gradient transitions from the centre outwards.

%IMG7%magick ^
  -size %WIDTH%x%HEIGHT% ^
  radial-gradient: ^
  gr_rad.png
gr_rad.png

Note that "radial-gradient:" applies only to max(width,height) from the image centre. To fade all the way to the corners, start with a square image that is as wide as the diagonal we want. The contours of the gradient are circular.

FOR /F %%i ^
IN ('%IMG7%magick identify ^
  -format "%%[fx:int(sqrt(%WIDTH%*%WIDTH%+%HEIGHT%*%HEIGHT%)+0.5)]" ^
  xc:') ^
DO set DIM=%%i

%IMG7%magick ^
  -size %DIM%x%DIM% ^
  radial-gradient: ^
  -gravity Center -crop %WIDTH%x%HEIGHT%+0+0 +repage ^
  gr_rad2.png
gr_rad2.png

A related gradient has equal values at the centre of each edge, so the contours are elliptical.

FOR /F %%i ^
IN ('%IMG7%magick identify ^
  -format "%%[fx:max(%WIDTH%,%HEIGHT%)]" ^
  xc:') ^
DO set MAX=%%i

FOR /F %%i ^
IN ('%IMG7%magick identify ^
  -format "%%[fx:int(%MAX%*sqrt(2)+0.5)]" ^
  xc:') ^
DO set DIM=%%i

%IMG7%magick ^
  -size %DIM%x%DIM% ^
  radial-gradient: ^
  -gravity Center -crop %MAX%x%MAX%+0+0 +repage ^
  -resize "%WIDTH%x%HEIGHT%^!" ^
  gr_rad3.png
gr_rad3.png

We can create a radial gradient of diameter 100, on a larger image, centering the gradient at (230,130). The parameter to "-extent" is WxH-X-Y where (X,Y) is the required coordinate of the top-left of the image so far. So X = 230-100/2 = 180 and Y = 130-100/2 = 80.

%IMG7%magick ^
  -size 100x100 ^
  radial-gradient: ^
  -background #000 ^
  -extent %WIDTH%x%HEIGHT%-180-80 ^
  gr_rad4.png
gr_rad4.png

We can readily chop and rearrange masks:

%IMG7%magick ^
  gr_baseGrad.png ^
  -crop 2x1@ ^
  ( -clone 0 -negate ) ^
  -delete 0 ^
  +append +repage ^
  gr_baseGrad2.png
gr_baseGrad2.png
%IMG7%magick ^
  gr_baseGradS.png ^
  -crop 1x2@ ^
  ( -clone 0 -negate ) ^
  -delete 0 ^
  -append +repage ^
  gr_baseGradS2.png
gr_baseGradS2.png
%IMG7%magick ^
  gr_baseGradS2.png ^
  ( +clone -negate )^
  +append +repage ^
  -resize "%WIDTH%x%HEIGHT%^!" ^
  gr_baseGradS4.png
gr_baseGradS4.png
set NUM=3
set ANG=90

%IMG7%magick ^
  -size %WIDTH%x%HEIGHT% ^
  gradient: ^
  -function Sinusoid %NUM%,%ANG%,0.5,0.5 ^
  gr_sinus.png
gr_sinus.png
set NUM=3
set ANG=90

%IMG7%magick ^
  -size %WIDTH%x%HEIGHT% ^
  xc: ^
  -sparse-color barycentric "0,0 gray80 %%[fx:w-1],%%[fx:h-1] gray20" ^
  -function Sinusoid %NUM%,%ANG%,0.5,0.5 ^
  -function Sinusoid %NUM%,%ANG%,0.5,0.5 ^
  gr_sinus2.png
gr_sinus2.png
%IMG7%magick ^
  gr_baseGradS.png ^
  ( +clone -negate ) ^
  +append +repage ^
  -resize "%WIDTH%x%HEIGHT%^!" ^
  -depth 16 ^
  gr_barnDoor.png
gr_barnDoor.png
%IMG7%magick ^
  gr_sinus.png ^
  ( gr_barnDoor.png -level 20%%,40%% ) ^
  -compose CopyOpacity -composite ^
  -write gr_sb.png ^
  -background Gray -alpha Remove ^
  gr_sinusBd.png

This might be useful for a shimmy effect, where pixels are displaced to left or right.

gr_sinusBd.png

We can quantise (this one calls for a sound FX of a cell-door slamming at each transition). This is also useful for checking that a complex gradient is equally spaced, or that it proceeds in a straight line.

%IMG7%magick ^
  gr_baseGradS2.png ^
  -posterize 10 ^
  gr_baseQ.png
gr_baseQ.png

The patches at each end are smaller because "-posterize" uses gray levels of 0%, 11.1%, 22.2% etc, so levels of 0 to 5.5% go into the first band, where the second band takes levels of 5.5% to 16.6%.

If we want ten levels of the same width from black to white, we can use a trick from the Clut Cookbook:

%IMG7%magick ^
  gr_baseGradS2.png ^
  ( -size 1x256 gradient: -rotate 90 ^
    -fx "int(u*10)/9" ^
  ) ^
  -interpolate NearestNeighbor ^
  -clut ^
  gr_baseQ2.png
gr_baseQ2.png

The script could be simpler, by applying "-fx" directly to the source file istead of via a clut. But that would be slower: one "-fx" per source pixel insted of one per clut pixel, and a clut is (usually) much smaller than source files.

"-interpolate NearestNeighbor" ensures that every pixel is one of the ten levels, avoiding any interpolation at a boundary. However, boundary interpolation (aka anti-aliasing) may be preferred.

Or, more simply, we can use "-colors". But this doesn't give us ten colours. It merely guarantees there will be ten colours or fewer.

%IMG7%magick ^
  gr_baseGradS2.png ^
  +dither -colors 10 ^
  gr_baseQ3.png
gr_baseQ3.png

Arcs

We can bend linear gradients into arcs.

FOR /F %%i ^
IN ('%IMG7%magick identify -format "%%[fx:max(%WIDTH%,%HEIGHT%)/2]" xc:') ^
DO (
  set RMAX=%%i
)

set /A POL_WI=RMAX*3
set /A POL_HT=RMAX

Note we invert the usual height and width, because we will rotate.

%IMG7%magick ^
  -size %POL_HT%x%POL_WI% ^
  gradient: ^
  -rotate 90 ^
  -distort Arc ^"180 0 %HEIGHT% 0^" ^
  +repage ^
  gr_arc180Mask.png

%IMG7%magick identify gr_arc180Mask.png 
gr_arc180Mask.png PNG 402x202 402x202+0+0 16-bit Grayscale Gray 95771B 0.000u 0:00.001
gr_arc180Mask.png
%IMG7%magick ^
  -size %POL_HT%x%POL_WI% ^
  gradient: ^
  -rotate 90 ^
  -distort Arc ^"90 45 %HEIGHT% 0^" ^
  -flip ^
  +repage ^
  gr_arc90Mask.png

%IMG7%magick identify gr_arc90Mask.png 
gr_arc90Mask.png PNG 202x202 202x202+0+0 16-bit Grayscale Gray 53498B 0.000u 0:00.001
gr_arc90Mask.png
%IMG7%magick ^
  gr_arc90Mask.png ^
  ( +clone -flop ) ^
  +append +repage ^
  gr_arc902Mask.png
gr_arc902Mask.png
%IMG7%magick ^
  gr_arc90Mask.png ^
  ( +clone -flop ) ^
  +swap ^
  +append +repage ^
  gr_arc902bMask.png
gr_arc902bMask.png

The "rising curtain" effect, gr_arc902Mask.png, will have straight lines that meet in the centre-line at an angle. This can be seen when we posterize it:

%IMG7%magick ^
  gr_arc902Mask.png ^
  -posterize 10 ^
  gr_arc902MaskQ.png
gr_arc902MaskQ.png

If we prefer a curved line, we can use a modified version of gr_arc90Mask.png, using an absolute displacement map, displacing only horizontally. The map is of a kind of ripple such that f(0)=0, f'(0)=1, f(1)=1 but f'(1)=1. The first quarter of a sin curve is such a function.

FOR /F "tokens=1,2" %%i ^
IN ('%IMG7%magick identify -ping -format "%%w %%h" gr_arc90Mask.png') ^
DO (
  set wi=%%i
  set ht=%%j
)

We write and display gr_preSin.png merely for comparison with gr_qtrSin.png.

%IMG7%magick ^
  -size %wi%x%ht% ^
  gradient: -rotate 90 ^
  -write gr_preSin.png ^
  -function sinusoid 0.25,0,1,0 ^
  gr_qtrSin.png

gr_qtrSin.png is the absolute displacement map

gr_preSin.png
gr_qtrSin.png

Apply the absolute displacement map.

%IMG7%magick ^
  gr_arc90Mask.png ^
  gr_qtrSin.png ^
  -fx "p{v*w,j}" ^
  gr_arc90qsMask.png
gr_arc90qsMask.png

Demonstrate it:

%IMG7%magick ^
  gr_arc90qsMask.png ^
  -posterize 10 ^
  gr_arc90qsMaskD.png
gr_arc90qsMaskD.png

gr_qtrSin is used as an absolute displacement mask. IM has no operators to process absolute displacement masks, so we need to use "-fx", which is slow. As we don't do this processing for every frame, speed doesn't matter. If we needed the processing for every frame, we might convert it to a relative displacement mask. See Displacement maps.

With greyRectMask.bat, we can choose the grey levels for the corners:

call %PICTBAT%greyRectMask.bat ^
  %WIDTH% %HEIGHT% 75 90 20 30
greyRectMask.png

A diagonal gradient is simple, eg top-left white to bottom-right black:

%IMG7%magick ^
  -size %WIDTH%x%HEIGHT% xc:white ^
  -sparse-color barycentric "0,0 white %%[fx:w-1],%%[fx:h-1] Black" ^
  gr_diag.png
gr_diag.png
call %PICTBAT%ellipMaskCornCol.bat ^
  %WIDTH% %HEIGHT% 10 10 10  75 75 75
ellipMaskCornCol.png
call %PICTBAT%ellipMaskCorn.bat ^
  %WIDTH% %HEIGHT% 10 75
ellipMaskCorn.png

We can simulate pond ripples. Note that "radial-gradient:" applies only to max(width,height) from the image centre, so we build a square image that is as wide as the diagonal we want.

We can vary ang from zero to 360 for one cycle, or zero to (360 * %NUM%) = (360*3) = 1080 for three cycles, from centre to corner.

set NUM=3
set ANG=90

FOR /F %%i ^
IN ('%IMG7%magick identify ^
  -format "%%[fx:int(sqrt(%WIDTH%*%WIDTH%+%HEIGHT%*%HEIGHT%)+0.5)]" ^
  xc:') ^
DO set DIM=%%i

%IMG7%magick ^
  -size %DIM%x%DIM% ^
  radial-gradient: ^
  -function Sinusoid %NUM%,%ANG%,0.5,0.5 ^
  -gravity Center -crop %WIDTH%x%HEIGHT%+0+0 +repage ^
  gr_pond.png
gr_pond.png

The next mask is useful for burning-in (darkening) the bottom edge of a photo, with the effect increasing slightly towards the corners.

call %PICTBAT%baseMask.bat ^
  %WIDTH% %HEIGHT% 25
baseMask.png

A clock

The resulting height and width will be twice the polar argument RMAX, plus one or two so we should crop the results (not shown here).

for /F "usebackq" %%i in (`%IMG7%magick identify ^
  -format "%%[fx:max(%WIDTH%,%HEIGHT%)/2]" ^
  xc:`) do set RMAX=%%i

set /A POL_WI=RMAX*3
set /A POL_HT=RMAX

rem Note we invert the usual height and width, because we will rotate.

%IMG7%magick ^
  -size %POL_HT%x%POL_WI% gradient: ^
  -rotate -90 ^
  +distort Polar ^"%RMAX%^" ^
  +repage ^
  gr_clock.png

%IMG7%magick identify -ping -format "%%w %%h" gr_clock.png 
302 302
gr_clock.pngjpg
%IMG7%magick -size %POL_HT%x%POL_WI% gradient: ^
  -rotate -90 ^
  +distort Polar ^"%RMAX%,0 0.5,0.5^" ^
  +repage ^
  gr_clock2.png

%IMG7%magick identify -ping -format "%%w %%h" gr_clock2.png 
301 301
gr_clock2.pngjpg
%IMG7%magick -size %POL_HT%x%POL_WI% gradient: ^
  -rotate 90 ^
  ( +clone ) ( +clone ) +append +repage ^
  +distort Polar ^"%RMAX%,0 0.5,0.5^" ^
  +repage -flop ^
  gr_clock3.png

%IMG7%magick identify -ping -format "%%w %%h" gr_clock3.png 
301 301
gr_clock3.pngjpg
%IMG7%magick -size %POL_HT%x%POL_WI% gradient: ^
  -function Sinusoid 4,90 ^
  -rotate 90 ^
  +distort Polar ^"%RMAX%,0 0.5,0.5^" ^
  +repage -flop ^
  gr_clock4.png

%IMG7%magick identify -ping -format "%%w %%h" gr_clock4.png 
301 301
gr_clock4.pngjpg

Aside: arctan

An alternative method for the basic gradient uses "-fx atan2":

%IMG7%magick ^
  -size %WIDTH%x%WIDTH% gradient: -rotate -90 ^
  ( +clone -rotate -90 ) ^
  +write gr_2grad.png ^
  -fx "atan2(u-0.5,v-0.5)/2/pi+0.5" ^
  gr_clock2b.png

%IMG7%magick ^
  -size %WIDTH%x%WIDTH% gradient: -rotate 180 ^
  ( +clone -rotate -90 ) ^
  +write gr_2grad.png ^
  -fx "atan2(u-0.5,v-0.5)/2/pi+0.5" ^
  -evaluate AddModulus 75%% ^
  gr_clock2b.png

%IMG7%magick identify -ping -format "%%w %%h" gr_clock2b.png 
300 300
gr_clock2b.pngjpg

Current "-fx" is fast. In old versions of IM (prior to about 7.1.0-20) "-fx" was too slow for large images. An alternative uses -function ArcTan, generalised to find the arctan(x,y) for any pair of input files, is:

rem Note: 1/pi = 0.3183098861837907
rem This needs HDRI.

%IM7DEV%magick ^
  gr_2grad-0.png gr_2grad-1.png ^
  -evaluate Subtract 50%% ^
  ( -clone 1 -threshold 0 +write mpr:MASK +delete ) ^
  -define compose:clamp=off ^
  -compose DivideSrc -composite ^
  -function ArcTan 0.3183098861837907,0,0.5,0.5 ^
  -write-mask mpr:MASK -evaluate AddModulus 50%% +write-mask ^
  -evaluate AddModulus 75%% ^
  gr_clock2c.png
gr_clock2c.pngjpg

The Dst and Src to the divide range from -50% to +50%. The -function ArcTan expression is:

y = range/pi * atan (slope * pi * (u - center)) + bias
  =   0.5/pi * atan (pi/pi *      (u -    0  )) + 0.5
  = 1/(2*pi) * atan(u) + 0.5

atan(u) returns between -pi/2 and +pi/2 radians (-90 and +90 degrees). We multiply by 1/(2*pi) to get a range -0.25 to +0.25, then add 0.5 to get a range +0.25 to +0.75. Where the Src is negative, the answer so far is wrong by pi radians (180 degrees), and we rectify this by adding 0.5 when Src is less than or equal to 0%.

However, when Src==0, DivideSrc returns merely 100%, so the arctan returns 45°, which is wrong. We could special-case this, but it gets a bit messy. Instead, we write a process module: arctan2.

%IM7DEV%magick ^
  gr_2grad-0.png gr_2grad-1.png ^
  -evaluate Subtract 50%% ^
  -process 'arctan2 b 0' ^
  -evaluate AddModulus 25%% ^
  gr_clock2d.png
gr_clock2d.pngjpg

We use this process module in the script slopeXYdirn.bat. See "direction" in the Slopes page.

%IMG7%magick ^
  gr_2grad-0.png gr_2grad-1.png ^
  gr_2grad_tmp.miff

call %PICTBAT%slopeXYdirn ^
  gr_2grad_tmp.miff ^
  gr_clock2e.png ^
  . SUB 25
gr_clock2e.pngjpg

These can usefully be swirled. The swirl effect doesn't extend beyond the inscribed circle, so it might be wise to create a larger image then crop to within that circle: make the width and height of the square equal to the diagonal of the required image.

%IMG7%magick ^
  gr_clock2.png ^
  -filter Point -interpolate Integer ^
  -swirl 180 ^
  gr_clock2s.png
gr_clock2s.pngjpg
%IMG7%magick ^
  gr_clock2.png ^
  -filter Point -interpolate Integer ^
  -swirl 540 ^
  gr_clock2sb.png
gr_clock2sb.pngjpg
%IMG7%magick ^
  gr_clock3.png ^
  -filter Point -interpolate Integer ^
  -swirl 180 ^
  gr_clock3s.png
gr_clock3s.pngjpg
%IMG7%magick ^
  gr_clock4.png ^
  -filter Point -interpolate Integer ^
  -swirl 180 ^
  gr_clock4s.png
gr_clock4s.pngjpg

Spirals

A different spiral is available by using morphology distance to create the transition. This is somewhat slow.

We create the polygon carefully so it will tile exactly. We want only two colours, so switching off interpolation (+antialias, -filter Point -interpolate Integer) would be good. But this leads to slight weirdness, so we threshold and level.

set wi=300
set ht=300

set /A wim1=%wi%-1
set /A htm1=%ht%-1

set /A swi=%wi%/2
set /A sht=%ht%/2

set /A swip1=%swi%+1

set /A shtm1=%sht%-1
set /A shtm2=%sht%-2

%IMG7%magick ^
  -size %wi%x%ht% ^
  xc:Black ^
  -fill White ^
  -draw ^"polygon 0,0 %wim1%,%htm1% %swi%,%htm1% 0,%shtm1% ^
          polygon %swip1%,0 %wim1%,0 %wim1%,%shtm2%^" ^
  gr_poly.png

  rem -fill rgb(50%%,50%%,50%%) ^
gr_poly.png

If we wanted more than a single turn of the spiral, we would append:

%IMG7%magick ^
  gr_poly.png ^
  ( +clone ) ^
  ( +clone ) ^
  +append +repage ^
  gr_poly3.png
gr_poly3.png

If we just wanted spirals, without the morphology transition, we might want "-virtual-pixel tile" before the distort. But that breaks spiral arms at the edges so morphology can't reach the end segments.

%IMG7%magick ^
  gr_poly.png ^
  +distort Polar ^"%RMAX%,0 0.5,0.5^" ^
  +repage ^
  -alpha off ^
  gr_spiral.png

rem  -channel RGB -threshold 25%% +level 0,50%% ^
gr_spiral.png
%IMG7%magick ^
  gr_spiral.png -rotate 90 ^
  gr_spiral.png ^
  -compose Difference -composite ^
  -write gr_spiral2a.png ^
  -channel RGB -threshold 50%% ^
  -alpha off ^
  gr_spiral2.png
gr_spiral2.png
FOR /F "tokens=1,2" %%i ^
IN ('%IMG7%magick identify -ping -format "%%w %%h" gr_spiral2.png') ^
DO (
  set wi=%%i
  set ht=%%j
)

set /A swi=%wi%/2
set /A sht=%ht%/2

rem set /A cxplus=%swi%+5
rem set /A cyplus=%sht%+5
rem set /A cymin=%sht%-5

%IMG7%magick ^
  gr_spiral2.png ^
  -draw "point %swi% %sht%" ^
  -alpha off ^
  gr_spiral2.png

%IMG7%magick ^
  gr_spiral2.png ^
  -negate ^
  -draw "point %swi% %sht%" ^
  -alpha off ^
  gr_spiral2n.png
gr_spiral2n.png

The centre of each mask, (swi,sht), must be black so the morphology will straddle both arms. This also provides a good starting point for the morphology.

"Euclidean:2,10": radius 2 isn't noticably worse than 4 or 7. Increment 10 allows for a spiral length of 6553 pixels.

For 2 Mpix (video) images, each morphology takes about 12 minutes. If the spiral was perfectly symmetrical, we could do half of one morphology, and rotate/negate as required.

%IMG7%magick ^
  -size %wi%x%ht% ^
  xc: -draw "point %swi% %sht%" ^
  -write-mask gr_spiral2.png ^
  -morphology IterativeDistance:-1 Euclidean:2,10 ^
  +write-mask ^
  -alpha off ^
  -fill black -opaque white -auto-level ^
  -draw "point %swi% %sht%" ^
  gr_spiral4.png
gr_spiral4.png
%IMG7%magick ^
  -size %wi%x%ht% ^
  xc: -draw "point %swi% %sht%" ^
  -write-mask gr_spiral2n.png ^
  -morphology IterativeDistance:-1 Euclidean:2,10 ^
  +write-mask ^
  -alpha off ^
  -fill black -opaque white -auto-level ^
  -transparent Black ^
  -draw "point %swi% %sht%" ^
  gr_spiral4n.png
gr_spiral4n.png
%IMG7%magick ^
  ( gr_spiral4.png -negate ) ^
  gr_spiral4n.png ^
  -composite ^
  gr_spiralMask.png
gr_spiralMask.png

Phew. Got there in the end. If this was a final image, we wouldn't want the aliasing. For a video F/X mask, we do, because otherwise we would get weirdness at the edges.


A similar effect is possible, much faster, by compositing the spiral over a radial gradient.

FOR /F "tokens=1,2" %%i ^
IN ('%IMG7%magick identify -ping -format "%%w %%h" gr_spiral2.png') ^
DO (
  set wi=%%i
  set ht=%%j
)

%IMG7%magick ^
  -size %wi%x%wi% ^
  radial-gradient: ^
  gr_spGrad.png

%IMG7%magick ^
  gr_spGrad.png ^
  ( -clone 0 gr_spiral2.png -alpha off ^
    -compose CopyOpacity -composite ^
  ) ^
  ( -clone 0 -negate ^
    ( gr_spiral2.png -negate -alpha off ) ^
    -compose CopyOpacity -composite ^
  ) ^
  -delete 0 ^
  -compose Over -composite ^
  gr_spFast.png
gr_spFast.png

Rectangles

This mask retains the aspect ratio at all gradations. We create a quarter-mask that can then be appended.

set /A semiWi=%WIDTH%/2
set /A semiHt=%HEIGHT%/2

%IMG7%magick ^
  ( -size %semiWi%x%semiHt% gradient: -rotate 180 ) ^
  ( -size %semiHt%x%semiWi% gradient: -rotate 90 ) ^
  -compose Darken -composite ^
  gr_semiMask.png
gr_semiMask.png
%IMG7%magick ^
  gr_semiMask.png ^
  ( +clone -flop ) ^
  +append +repage ^
  ( +clone -flip ) ^
  -append +repage ^
  gr_rectMask.png
gr_rectMask.png
%IMG7%magick ^
  ( gr_semiMask.png -rotate 180 ) ^
  ( +clone -flop ) ^
  +append +repage ^
  ( +clone -flip ) ^
  -append +repage ^
  gr_crossMask.png
gr_crossMask.png
%IMG7%magick ^
  -size %WIDTH%X%HEIGHT% ^
  xc:white ^
  -draw ^"polygon %semiWi%,%semiHt% 0,0 %WIDTH%,0 ^" ^
  -draw ^"polygon %semiWi%,%semiHt% 0,%HEIGHT% %WIDTH%,%HEIGHT% ^" ^
  gr_rectM.png
gr_rectM.png
%IMG7%magick ^
  gr_rectMask.png ^
  ( +clone -negate gr_rectM.png -alpha off -compose Copy-Opacity ) ^
  -compose Over -composite ^
  gr_rectNeg.png
gr_rectNeg.png

Swirl can be used, with care. Posterized to show the effect at transitional corners:

%IMG7%magick ^
  gr_rectMask.png ^
  -swirl 90 ^
  -posterize 10 ^
  gr_rectMaskS.png
gr_rectMaskS.png

Scripted gradients

Many of the above gradients are (approximately) symmetrical about the centre. This can be changed by suitable cropping, or by a Shepards distortion:

call %PICTBAT%offCentre.bat ^
  gr_spiralMask.png -10 21 gr_spiralOc.png ^
  -filter Point -interpolate Integer
gr_spiralOc.png
call %PICTBAT%mDiamondMask.bat ^
  gr_DiamondMask.png ^
  %WIDTH% %HEIGHT% 6 4
gr_DiamondMask.png
set mbmSEED=1234

call %PICTBAT%mBlobMask.bat ^
  gr_blobMask.png ^
  %WIDTH% %HEIGHT% 6 4 5
gr_blobMask.png
call %PICTBAT%mBlobMask.bat ^
  gr_blobMask2.png ^
  %WIDTH% %HEIGHT%
gr_blobMask2.png
%IMG7%magick ^
  gr_blobMask2.png ^
  -shade 135x45 ^
  -auto-level ^
  gr_blobMask3.png

set mbmSEED=
gr_blobMask3.png

Transitioning shapes

From an arbitrary black-on-white shape, we can create a gradient mask outwards to the image's edges, or white-on-black for a gradient inwards.

shapeA.png:

shapeA.png
FOR /F %%i ^
IN ('%IMG7%magick identify ^
  -format "%%[fx:int(QuantumRange/max(w,h)+0.5)]" ^
  shapeA.png') ^
DO (
  set INC=%%i
)

%IMG7%magick ^
  shapeA.png ^
  -morphology Distance Euclidean:4,%INC% ^
  -auto-level ^
  -evaluate Multiply 4 ^
  gr_shapeAm.png

rem   -evaluate Multiply 2 ^
gr_shapeAm.png

shapeB.png:

shapeB.png
FOR /F %%i ^
IN ('%IMG7%magick identify ^
  -format "%%[fx:int(QuantumRange/max(w,h)*4+0.5)]" ^
  shapeB.png') ^
DO (
  set INC=%%i
)

%IMG7%magick ^
  shapeB.png ^
  -morphology Distance Euclidean:4,%INC% ^
  -auto-level ^
  gr_shapeBm.png
gr_shapeBm.png

Where are the two fades equal? (Not necessarily 50%, or even a constant level.)

%IMG7%magick ^
  gr_shapeAm.png ^
  gr_shapeBm.png ^
  -compose Minus -composite ^
  -threshold 1 ^
  gr_shapeThresh.png

Check:

%IMG7%magick ^
  gr_shapeThresh.png ^
  ( shapeA.png -transparent White -fill Red -opaque Black ) ^
  -composite ^
  ( shapeB.png -transparent White -fill Green -opaque Black ) ^
  -composite ^
  gr_shapeThreshD.png
gr_shapeThresh.png
gr_shapeThreshD.png

Use Am where threshold is white, negated, levelled so darkest is 50%, transparent outwards to the boundary:

%IMG7%magick ^
  ( gr_shapeAm.png ^
    gr_shapeThresh.png ^
    -compose Multiply -composite ^
    -auto-level -evaluate Divide 2 -negate ^
  ) ^
  gr_shapeThresh.png ^
  -compose CopyOpacity -composite ^
  gr_shapeAml.png
gr_shapeAml.png

Bm where threshold is black, and levelled so lightest is 50%:

%IMG7%magick ^
  gr_shapeBm.png ^
  ( gr_shapeThresh.png -negate ) ^
  -compose Multiply -composite ^
  -auto-level -evaluate Divide 2 ^
  gr_shapeBml.png
gr_shapeBml.png

Place Aml over Bml; blur to hide the join:

%IMG7%magick ^
  gr_shapeBml.png ^
  gr_shapeAml.png ^
  -composite ^
  -blur x10 ^
  gr_shapeTrans.png
gr_shapeTrans.png

Alternatively, overlay Am negated over Bm:

%IMG7%magick ^
  gr_shapeBm.png ^
  ( gr_shapeAm.png -negate ) ^
  -compose Overlay -composite ^
  gr_shapeTrans2.png
gr_shapeTrans2.png

Demonstrate it:

%IMG7%magick ^
  gr_shapeTrans.png ^
  -posterize 10 ^
  ( shapeA.png -transparent White -fill Red -opaque Black ) ^
  -composite ^
  ( shapeB.png -transparent White -fill Green -opaque Black ) ^
  -composite ^
  gr_shapeTransQ.png
gr_shapeTransQ.png

Demonstrate the alternative:

%IMG7%magick ^
  gr_shapeTrans2.png ^
  -posterize 10 ^
  ( shapeA.png -transparent White -fill Red -opaque Black ) ^
  -composite ^
  ( shapeB.png -transparent White -fill Green -opaque Black ) ^
  -composite ^
  gr_shapeTrans2Q.png
gr_shapeTrans2Q.png

Another method of transitions between shapes:

Make versions with the transition areas transparent:

%IMG7%magick ^
  shapeA.png ^
  -transparent White ^
  -fill White -opaque Black ^
  gr_shapeAt.png

%IMG7%magick ^
  shapeB.png ^
  -transparent White ^
  gr_shapeBt.png
gr_shapeAt.png
gr_shapeBt.png

Make a black-white-gray version:

%IMG7%magick ^
  ( shapeA.png ^
    -fill rgb(50%%,50%%,50%%) -opaque White ^
    -fill White -opaque Black ) ^
  ( shapeB.png -transparent White ) ^
  -composite ^
  gr_shapeBWG.png
gr_shapeBWG.png

Make a gray version, with the transition area transparent:

%IMG7%magick ^
  ( shapeA.png ^
    -transparent White ^
    -fill rgb(50%%,50%%,50%%) -opaque Black ^
  ) ^
  ( shapeB.png ^
    -transparent White ^
    -fill rgb(50%%,50%%,50%%) -opaque Black ^
  ) ^
  -composite ^
  gr_shapeG.png
gr_shapeG.png

Make a white-black-gray version.

The blur amount is critical: too small doesn't get a full gradation of grays, too large loses shape.

The gamma gives a more even transition.

%IMG7%magick ^
  ( shapeA.png ^
    -fill rgb(50%%,50%%,50%%) -opaque White ^
    -fill White -opaque Black ) ^
  ( shapeB.png -transparent White ) ^
  -composite ^
  -blur 0x15 ^
  gr_shapeG.png ^
  -composite ^
  -auto-level ^
  -evaluate Pow 2 ^
  gr_shapeAt.png -composite ^
  gr_shapeBt.png -composite ^
  gr_shapeABgray.png
gr_shapeABgray.png

Demonstrate it:

%IMG7%magick ^
  gr_shapeABgray.png ^
  -posterize 10 ^
  ( shapeA.png -transparent White -fill Red -opaque Black ) ^
  -composite ^
  ( shapeB.png -transparent White -fill Green -opaque Black ) ^
  -composite ^
  gr_shapeABgrayQ.png
gr_shapeABgrayQ.png

No amount of conventional blur both provides a full gradation of grays and retains detail. So we can use an unconventional blur that does both.

call %PICTBAT%detblur gr_shapeBWG.png gr_shapeBWGd.png 6
gr_shapeBWGd.png
%IMG7%magick ^
  gr_shapeBWGd.png ^
  gr_shapeG.png ^
  -composite ^
  -auto-level ^
  -sigmoidal-contrast 10x50%% ^
  -evaluate Pow 2.5 ^
  gr_shapeBWGda.png
gr_shapeBWGda.png

Demonstrate it:

%IMG7%magick ^
  gr_shapeBWGda.png ^
  -posterize 10 ^
  ( shapeA.png -transparent White -fill Red -opaque Black ) ^
  -composite ^
  ( shapeB.png -transparent White -fill Green -opaque Black ) ^
  -composite ^
  gr_shapeBWGdaQ.png
gr_shapeBWGdaQ.png

An alternative method uses a fan compose. From an image that contains black, white and other pixels, the script fanBW.bat replaces pixels that are neither black nor white with graduated gray. For example:

Prepare an image with black, white and others:

%IMG7%magick ^
  shapeB.png -fill Gray(50%) -opaque White ^
  ( shapeA.png -negate -transparent Black ) ^
  -compose Over -composite ^
  gr_shapeBW2.png
gr_shapeBW2.png

Use fanBW:

call %PICTBAT%fanBW ^
  gr_shapeBW2.png ^
  gr_shapeBW2_out.png
gr_shapeBW2_out.png

Another example using fanBW.bat:

Prepare an image with black, white and others:

%IMG7%magick ^
  -size 400x300 xc:#88f ^
  -fill White -draw "circle 100,100,50,100" ^
  -fill Black -draw "rectangle 50,250,350,260" ^
  gr_shapeBW2b.png
gr_shapeBW2b.png

Use fanBW:

call %PICTBAT%fanBW ^
  gr_shapeBW2b.png ^
  gr_shapeBW2b_out.png
gr_shapeBW2b_out.png

1D to 2D: making gradients from cluts

A clut ("Colour Look-Up Table") is an image of a one-dimensional array of colours, often representing a gradient. See the Clut Cookbook.

We can transform a clut into a two-dimensional gradient.

Method 1: Make a 1D clut then scale in the other dimension to 2D.

%IMG7%magick ^
  xc: -bordercolor Black -border 2x0 ^
  -filter gaussian ^
  -resize "%WIDTH%x1^!" ^
  -scale "%WIDTH%x%HEIGHT%^!" ^
  gr_filtgauss.png
gr_filtgauss.png

Method 2: For a symmetrical clut we might want a rotation of half the clut. Make a 1D clut, crop the left half, rotate anti-clockwise, scale it in the other dimension, turn in a polar distortion. The output is square. Suppose we want the output radius to be OUT_RAD, so the output width and height will be 2*OUT_RAD+1.

set OUT_RAD=150
set /A outH=2*%OUT_RAD%
set /A outW=3*%OUT_RAD%

We write gr_filtgauss2.png only for illustration. This isn't normally needed.

%IMG7%magick ^
  xc: -bordercolor Black -border 2x0 ^
  -filter gaussian ^
  -resize "%outH%x1^!" ^
  -crop %OUT_RAD%x1+0+0 +repage ^
  -rotate -90 ^
  -scale "%outW%x%OUT_RAD%^!" ^
  -write gr_filtgauss2.png ^
  +distort Polar ^"%OUT_RAD%,0 0.5,0.5^" ^
  +repage ^
  gr_filtgauss3.png
gr_filtgauss2.png gr_filtgauss3.png

The pixel colours from the circle (in this case, black) are spread to the corners. "-background Khaki -virtual-pixel HorizontalTile" might seem useful but we get a background colour at the centre pixel. If desired, we can isolate the circle:

%IMG7%magick ^
  gr_filtgauss3.png ^
  ( +clone ^
    -fill Black -colorize 100 ^
    -fill White -draw "circle %OUT_RAD%,%OUT_RAD% %OUT_RAD%,0" ^
  ) ^
  -alpha off ^
  -compose CopyOpacity -composite ^
  gr_filtgauss3c.png
gr_filtgauss3c.png

Method 3: When we want a rotation of the entire clut, rotated around x=0. As method 2, but we don't crop, and the resize is different.

set OUT_RAD=150
set /A outH=%OUT_RAD%
set /A outW=3*%OUT_RAD%

%IMG7%magick ^
  xc: -bordercolor Black -border 2x0 ^
  -filter gaussian ^
  -resize "%outH%x1^!" ^
  -rotate -90 ^
  -scale "%outW%x%OUT_RAD%^!" ^
  +distort Polar ^"%OUT_RAD%,0 0.5,0.5^" ^
  +repage ^
  gr_filtgauss4.png
gr_filtgauss4.png

Method 4: use two cluts, one for width the other for height, scale them up to the required size and combine them. When combining, we generally want at least the following conditions:

For example, using cluts that start and end at zero:

set WW=400
set HH=500
set PKx=150
set PKy=100

set P1h=%PKx%/%WW%
set S1h=%WW%/%PKx%
set S2h=%WW%/(%PKx%-%WW%)

set P1v=%PKy%/%HH%
set S1v=%HH%/%PKy%
set S2v=%HH%/(%PKy%-%HH%)

%IMG7%magick ^
  ( -size 1x%WW% gradient: -rotate 90 ^
    -fx "u<%P1h%?u*%S1h%:1+(u-%P1h%)*%S2h%" ^
    -function sinusoid 0.5,-90,0.5,0.5 ^
    -scale "%WW%x%HH%^!" ^
  ) ^
  ( -size 1x%HH% gradient: -flip ^
    -fx "u<%P1v%?u*%S1v%:1+(u-%P1v%)*%S2v%" ^
    -function sinusoid 0.5,-90,0.5,0.5 ^
    -scale "%WW%x%HH%^!" ^
  ) ^
  -compose Darken -composite ^
  gr_peak.png
gr_peak.png

As previous, but Multiply.

%IMG7%magick ^
  ( -size 1x%WW% gradient: -rotate 90 ^
    -fx "u<%P1h%?u*%S1h%:1+(u-%P1h%)*%S2h%" ^
    -function sinusoid 0.5,-90,0.5,0.5 ^
    -scale "%WW%x%HH%^!" ^
  ) ^
  ( -size 1x%HH% gradient: -flip ^
    -fx "u<%P1v%?u*%S1v%:1+(u-%P1v%)*%S2v%" ^
    -function sinusoid 0.5,-90,0.5,0.5 ^
    -scale "%WW%x%HH%^!" ^
  ) ^
  -compose Multiply -composite ^
  gr_peak2.png
gr_peak2.png

As previous, but geometric mean.

%IMG7%magick ^
  ( -size 1x%WW% gradient: -rotate 90 ^
    -fx "u<%P1h%?u*%S1h%:1+(u-%P1h%)*%S2h%" ^
    -function sinusoid 0.5,-90,0.5,0.5 ^
    -scale "%WW%x%HH%^!" ^
  ) ^
  ( -size 1x%HH% gradient: -flip ^
    -fx "u<%P1v%?u*%S1v%:1+(u-%P1v%)*%S2v%" ^
    -function sinusoid 0.5,-90,0.5,0.5 ^
    -scale "%WW%x%HH%^!" ^
  ) ^
  -compose Multiply -composite ^
  -evaluate Pow 0.5 ^
  gr_peak2a.png
gr_peak2a.png

As previous, but arithmetic mean.

%IMG7%magick ^
  ( -size 1x%WW% gradient: -rotate 90 ^
    -fx "u<%P1h%?u*%S1h%:1+(u-%P1h%)*%S2h%" ^
    -function sinusoid 0.5,-90,0.5,0.5 ^
    -scale "%WW%x%HH%^!" ^
  ) ^
  ( -size 1x%HH% gradient: -flip ^
    -fx "u<%P1v%?u*%S1v%:1+(u-%P1v%)*%S2v%" ^
    -function sinusoid 0.5,-90,0.5,0.5 ^
    -scale "%WW%x%HH%^!" ^
  ) ^
  -evaluate-sequence Mean ^
  gr_peak3.png
gr_peak3.png

This is useful, so we make a general-purpose script: mPntEdgeMsk.bat. This also has a parameter that can smooth the start or end of the transition, or both.


Transforming to colour

"+level-colors" for a simple gradient.

%IMG7%magick ^
  gr_clock4s.png ^
  +level-colors red,lime ^
  gr_col1.png
gr_col1.pngjpg

"-clut" for more complexity.

%IMG7%magick ^
  gr_clock4s.png ^
  ( -size 1x1 ^
    xc:#004 xc:#404 xc:#800 xc:#f00 xc:#f80 xc:#ff0 xc:#ffa ^
    +append +repage ^
  ) ^
  -clut ^
  gr_col2.png

As the input is greyscale, "-hald-clut" would be of no extra benefit.

gr_col2.pngjpg

Greyscale gradients can be combined into channels.

%IMG7%magick ^
  -size %WIDTH%x%HEIGHT% ^
  gradient: ^
  radial-gradient: ^
  -size %HEIGHT%x%WIDTH% ^
  ( gradient: -rotate 90 ) ^
  -combine ^
  gr_col3.png
gr_col3.pngjpg

The same, but combining in a different colorspace.

%IMG7%magick ^
  -size %WIDTH%x%HEIGHT% ^
  gradient: ^
  radial-gradient: ^
  -size %HEIGHT%x%WIDTH% ^
  ( gradient: -rotate 90 ) ^
  -set colorspace Lab -combine -colorspace sRGB ^
  gr_col4.png
gr_col4.pngjpg

Gradients beween two colours

We can easily construct a gradient between two colours, as a straight line between the colours in the sRGB colorspace cube:

%IMG7%magick ^
  -size 11x1 ^
  gradient:rgb(100%%,0,0)-rgb(0,100%%,0) ^
  -scale 5000%% ^
  gr_g2c_1.png
gr_g2c_1.png

The intermediate values are linear interpolations between the end-points, so the central colour is (50%,50%,0). That tuple in the sRGB colorspace is darker than either of the endpoints.

The end-points we have chosen (red and green) are fully saturated, so they have the same values in linear RGB and non-linear sRGB. Hence, we can push the output through an RGB->sRGB transformation, so the gradient operates in RGB space:

%IMG7%magick ^
  -size 11x1 ^
  gradient:rgb(100%%,0,0)-rgb(0,100%%,0) ^
  -set colorspace RGB ^
  -colorspace sRGB ^
  -scale 5000%% ^
  gr_g2c_2.png
gr_g2c_2.png

The central colour is again (50%,50%,0), but that tuple in linear RGB space is closer to the average lightness of the endpoints.

More generally, we can use any pair of colours in any colorspace. We specify the colours with two tuples or named colours in that colorspace, create the gradient, set the image to the colorspace, and convert to sRGB or whatever we want.

If we don't know the tuple values of our desired colour in the required colorspace, we can use IM to do the conversion. IM doesn't contain facilities to do this directly, so we go via a script, twoColVals.bat, that creates an image with those colours, converts it to the colorspace, and captures the values so we can use those in the "gradient:". With Lab values, IM is inconsistent: sometimes it writes and expects a range of 0 to 100%, sometimes -50% to +50%. To avoid that problem, the script uses "-set colorspace sRGB" to pretend the result is sRGB.

call %PICTBAT%twoColVals sRGB #f00 #0f0 Lab mylab

set mylab 
mylab[0]=srgb(53.24079571030747%,81.40880707827878%,76.35419646944381%)
mylab[1]=srgb(87.73472071221485%,16.20285647697795%,82.61934224078736%)

These are really Lab values, not sRGB values.

Now we can create a gradient between those colours in Lab colorspace:

%IMG7%magick ^
  -size 11x1 ^
  gradient:%mylab[0]%-%mylab[1]% ^
  -set colorspace Lab ^
  -colorspace sRGB ^
  -scale 5000%% ^
  gr_g2c_3.png
gr_g2c_3.png

The result is more perceptually uniform than the sRGB or RGB gradients. The central colour has exactly the average lightness (in Lab terms) of the endpoints.

Another useful result is in xyY colorspace:

call %PICTBAT%twoColVals ^
  sRGB #f00 #0f0 xyY myxyy

%IMG7%magick ^
  -size 11x1 ^
  gradient:%myxyy[0]%-%myxyy[1]% ^
  -set colorspace xyY ^
  -colorspace sRGB ^
  -scale 5000%% ^
  gr_g2c_4.png
gr_g2c_4.png

Gradients from grids

We can define a small NxM image, and enlarge it with "-filter Hermite" retaining the aspect ratio. The result will have the original values in a grid, with interpolated values between them.

This is an extension of Clut cookbook: cluts from resize, but with a different filter.

We also crop the image.

set N=4
set M=4

%IMG7%magick ^
  -size 4x4 xc:gray(50%%) ^
  -fill gray(10%%) -draw "point 1,1" ^
  -fill gray(90%%) -draw "point 2,2" ^
  -fill gray(20%%) -draw "point 1,3" ^
  -filter Hermite ^
  -resize "600x600^!" ^
  -crop "%%[fx:w*(%N%-1)/%N%+2]x%%[fx:h*(%M%-1)/%M%+2]+%%[fx:w/%N%/2-1]+%%[fx:h/%M%/2-1]" ^
  +repage ^
  gr_grgrd.png
gr_grgrd.png

Miscellaneous

Masks can be combined:

%IMG7%magick ^
  gr_baseGrad.png ^
  gr_blobMask2.png ^
  -compose Overlay -composite ^
  gr_combMask.png
gr_combMask.png

A mask may be clutted to transform black-white into a number of ramps; in this case 4. "-interpolate nearest-neighbor" ensures we don't get grey anti-aliasing at the black/white boundaries.

%IMG7%magick -size 1x1000 gradient: ^
  -rotate 90 ^
  -duplicate 3 ^
  +append +repage ^
  gr_ramp_clut.png

%IMG7%magick -size %WIDTH%x%HEIGHT% radial-gradient: ^
  -interpolate nearest-neighbor ^
  gr_ramp_clut.png -clut ^
  gr_ramp.png
gr_ramp.png

The previous result can give us the three contours at 25% intervals:

%IMG7%magick ^
  gr_ramp.png ^
  -morphology edgein diamond:1 ^
  gr_rampCont.png
gr_rampCont.png

We might want fill a rectangle with a gradient, with black at top-left and white bottom-right, increasing lightness across then down:

set WW=300
set HH=200
set /A WH=%WW%*%HH%

%IMG7%magick ^
  -size %WH%x1 ^
  gradient:Black-White ^
  -crop %WW%x ^
  -append +repage ^
  gr_reading.png
gr_reading.png

If we have a white shape on black background, we can make each line of the shape a gradient with black at the left and white at the right. Annoyingly, "-auto-level" doesn't ignore transparent pixels; it merely ignores the alpha channel. So we fill in transparent pixels with the average of each row.

shapeB.png:

shapeB.png
for /F "usebackq" %%L in (`%IMG7%magick identify ^
  -format "WW=%%w\nHH=%%h\nWm1=%%[fx:w-1]\nHm1=%%[fx:h-1]" ^
  shapeB.png`) do set %%L

%IMG7%magick ^
  shapeB.png ^
  ( +clone ^
    -sparse-color Bilinear ^
      "0,0,Black %%[fx:w-1],0,White" ^
  ) ^
  +swap ^
  -alpha off ^
  -compose CopyOpacity -composite ^
  ( +clone ^
    -scale "1x%HH%^!" ^
    -scale "%WW%x%HH%^!" ^
  ) ^
  -compose DstOver -composite ^
  -crop x1 ^
  -auto-level ^
  -append +repage ^
  +repage ^
  gr_sh_grad.png
gr_sh_grad.png

We put this in a script, sh2grad.bat. The script can also rotate the input before processing, and de-rotate afterwards.

The script sh2gradCol.bat calls sh2grad.bat for the red and green channels, setting blue to 50%, and marks pixels outside the shape with black. The result is an absolute displacement map from the rectangle to the shape.

call %PICTBAT%sh2gradCol ^
  shapeB.png gr_sh_grad2.png
gr_sh_grad2.png

The result has many pixels with red==0 and green==0, so these will all be displaced from the top-left corner of the rectangle. Similarly for the other corners.

Scripts

For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.

greyRectMask.bat

rem Generates a mask width %1 height %2, corners coloured with percentages of grey:
rem   %3 top-left
rem   %4 top-right
rem   %5 bottom-left
rem   %6 bottom-right
rem Width and height must be at least 2.
rem Useful percentages: 0=black, 100=white
@rem
@rem Updated:
@rem   5-August-2022 for IM v7.
@rem

"%IMG7%magick" -size %1x%2 xc: ^
  -sparse-color Bilinear "0,0 rgb(%3%%,%3%%,%3%%) %%[fx:w-1],0 rgb(%4%%,%4%%,%4%%) 0,%%[fx:h-1] rgb(%5%%,%5%%,%5%%) %%[fx:w-1],%%[fx:h-1] rgb(%6%%,%6%%,%6%%)" ^
  greyRectMask.png

ellipMaskCornCol.bat

@%PICTBAT%ellipMaskCornColbat,h

ellipMaskCorn.bat

rem Generates a grayscale elliptical mask,
rem   width %1 height %2,
rem   centre %3 [default white] fading to %4 [black] at corners.
rem Colours are percentages gray, eg 0=white, 50=mid gray, 100=white
rem The image is contained within the ellipse, so only the corners are the background grey.
@rem
@rem Updated:
@rem   5-August-2022 for IM v7.
@rem

set WI=%1

set HT=%2
if "%HT%"=="" set HT=%1

set SIZ=%WI%
if %SIZ% LSS %HT% set SIZ=%HT%

set INCOL=%3
if "%INCOL%"=="" set INCOL=100

set OUTCOL=%4
if "%OUTCOL%"=="" set OUTCOL=0

for /F %%i in ('%IMG7%magick ^
  xc: ^
  -format "%%[fx:int(%SIZ%*sqrt(2)+0.5)]" ^
  info:') do set SQ_DIM=%%i

%IMG7%magick -size %SQ_DIM%x%SQ_DIM% ^
  radial-gradient:rgb(%INCOL%%%,%INCOL%%%,%INCOL%%%)-rgb(%OUTCOL%%%,%OUTCOL%%%,%OUTCOL%%%) ^
  -gravity Center ^
  -crop %SIZ%x%SIZ%+0+0 +repage ^
  -resize "%WI%x%HT%^!" ^
  ellipMaskCorn.png

%IMG7%magick identify ellipMaskCorn.png

baseMask.bat

rem Generates a mask darker at the bottom, especially the corners,
rem   width %1 height %2,
rem   only dark at bottom %3 percent of image.
@rem
@rem Updated:
@rem   5-August-2022 for IM v7.
@rem

call %PICTBAT%ellipMaskCorn %1 %2

"%IMG7%magick" ^
  -size %1x%2 gradient: -level 0x%3%% ^
  ellipMaskCorn.png ^
  -compose Screen -composite ^
  baseMask.png

offCentre.bat

rem Given image %1 and percentage offset (%2,%3),
rem intended range (-50,-50) to (50,50),
rem creates image %4
rem with centre shifted by the offset.
rem Optional %5 %6 %7 %8 %9: extra parameters for convert.
@rem
@rem Updated:
@rem   5-August-2022 for IM v7.
@rem

rem SETLOCAL

FOR /F "tokens=1,2" %%i IN ('%IMG7%magick identify -ping -format "%%w %%h" %1') DO (
  set wi=%%i
  set ht=%%j
)

set opts=%5 %6 %7 %8 %9
rem eg rem -filter Point -interpolate Integer

set /A offX=%2
set /A offY=%3

set /A wim1=%wi%-1
set /A htm1=%ht%-1

set /A cx=%wi%/2
set /A cy=%ht%/2

set /A cxpo=%wi%/2+offX*%wi%/100
set /A cypo=%ht%/2+offY*%ht%/100

echo %cxpo%
echo %cypo%

set pinL=0
set pinT=0
set pinR=0
set pinB=0

if %offX% geq 0 set pinL=1
if %offY% geq 0 set pinT=1
if %offX% leq 0 set pinR=1
if %offY% leq 0 set pinB=1

set /A pinTL=%pinT%+%pinL%
set /A pinTR=%pinT%+%pinR%
set /A pinBL=%pinB%+%pinL%
set /A pinBR=%pinB%+%pinR%

echo %pinTL% %pinTR% %pinBL% %pinBR%

rem We pin the 4 corners, the centre-edges, and the edges at cxpo and cypo.

set pin=%cx%,%cy%,%cxpo%,%cypo%

rem Do corners
if %pinTL% gtr 0 set pin=%pin% 0,0,0,0
if %pinTR% gtr 0 set pin=%pin% %wim1%,0,%wim1%,0
if %pinBL% gtr 0 set pin=%pin% 0,%htm1%,0,%htm1%
if %pinBR% gtr 0 set pin=%pin% %wim1%,%htm1%,%wim1%,%htm1%

rem Do edges
if %pinL% gtr 0 set pin=%pin% 0,%cypo%,0,%cypo% 0,%cy%,0,%cy%
if %pinT% gtr 0 set pin=%pin% %cxpo%,0,%cxpo%,0 %cx%,0,%cx%,0
if %pinR% gtr 0 set pin=%pin% %wim1%,%cypo%,%wim1%,%cypo% %wim1%,%cy%,%wim1%,%cy%
if %pinB% gtr 0 set pin=%pin% %cxpo%,%htm1%,%cxpo%,%htm1% %cx%,%htm1%,%cx%,%htm1%

echo %pin%

%IMG7%magick ^
  %1 ^
  %opts% ^
  -distort Shepards ^"%pin%^" ^
  %4

rem ENDLOCAL

mDiamondMask.bat

rem Makes a tiled diamond gradient mask.
rem %1 is output filename.
rem %2 and %3 are overall width and height.
rem %4 and %5 are repetitions horizontally and vertically (default 1).
@rem
@rem Updated:
@rem   5-August-2022 for IM v7.
@rem

set outName=%1
if "%outName%"=="" set outName=diamondMask.png

set numWi=%4
if "%numWi%"=="" set numWi=1

set numHt=%5
if "%numHt%"=="" set numHt=1

set /A oneWi=%2/%numWi%
set /A oneHt=%3/%numHt%

echo %oneWi% %oneHt%

set /A outWi=%numWi%*%oneWi%
set /A outHt=%numHt%*%oneHt%

echo %outWi% %outHt%

set /A semiHt=%oneHt%/2
set /A oneHt=%semiHt%*2
set /A semiWi=%oneWi%/2
set /A outHt=%numHt%*%oneHt%

echo %outWi% %outHt%

set /A oneWim1=%oneWi%-1
set /A oneHtm1=%oneHt%-1

%IMG7%magick ^
  -size %oneWi%x%oneHt% ^
  xc:White ^
  -fill Black ^
  -draw ^"polygon %semiWi%,0 %oneWim1%,%semiHt% %semiWi%,%oneHtm1% 0,%semiHt%^" ^
  +repage ^
  %TEMP%\dmMask.png


rem We could use -crop 1x2@ instead of two clones and crops, but we want exact control of the size.

%IMG7%magick ^
  -size %oneWi%x%oneHt% ^
  gradient: ^
  -write %TEMP%\dm0.png ^
  ( -clone 0 -crop %oneWi%x%semiHt%+0+%semiHt% ) ^
  ( -clone 0 -crop %oneWi%x%semiHt%+0+0 ) ^
  -delete 0 ^
  -append ^
  +repage ^
  %TEMP%\dm1.png

%IMG7%magick ^
  %TEMP%\dm0.png ^
  ( %TEMP%\dm1.png -alpha set %TEMP%\dmMask.png -alpha off -compose Copy-Opacity -composite ) ^
  -compose Over -composite ^
  %TEMP%\dmOne.png

rem This starts tiling top-left, so any partial tiles will be at right and bottom.
rem We could use -tile-offset, or generate over-size then trim.

%IMG7%magick ^
  -size %2x%3 ^
  tile:%TEMP%\dmOne.png ^
  %outName%

mBlobMask.bat

rem Makes a tiled blob gradient mask.
rem %1 is output filename.
rem %2 and %3 are overall width and height.
rem %4 and %5 are repetitions horizontally and vertically (default 1).
rem %6 is blur sigma (default 10).
rem %7 0 for greyscale, 1 for colour
@rem
@rem Also uses:
@rem   mbmSEED if given, use this as seed.
@rem
@rem Updated:
@rem   25-May-2016 added mbmSEED feature.
@rem   5-August-2022 for IM v7.
@rem


@if "%3"=="" findstr /B "rem @rem" %~f0 & exit /B 1

@setlocal enabledelayedexpansion

@call echoOffSave

call %PICTBAT%setInOut %1 mbm


set OUTFILE=%1
if "%OUTFILE%"=="" set OUTFILE=blobMask.png

set numWi=%4
if "%numWi%"=="." set numWi=
if "%numWi%"=="" set numWi=1

set numHt=%5
if "%numHt%"=="." set numHt=
if "%numHt%"=="" set numHt=1

set blurSig=%6
if "%blurSig%"=="." set blurSig=
if "%blurSig%"=="" set blurSig=10

set IsCol=%7
if "%IsCol%"=="." set IsCol=
if "%IsCol%"=="" set IsCol=0

set sSEED=
if not "%mbmSEED%"=="" set sSEED=-seed %mbmSEED%

set TEMP_FILE=%TEMP%\bmOne.miff

set /A oneWi=%2/%numWi%
set /A oneHt=%3/%numHt%

echo %oneWi% %oneHt%

set /A semiHt=%oneHt%/2
set /A oneHt=%semiHt%*2
set /A semiWi=%oneWi%/2

set /A oneWim1=%oneWi%-1
set /A oneHtm1=%oneHt%-1

if %IsCol%==0 (
  set sCOL=-modulate 100,0,100
) else (
  set sCOL=-channel RGB
)

rem This starts tiling top-left, so any partial tiles will be at right and bottom.
rem We could use -tile-offset, or generate over-size then trim.

goto skip

%IMG7%magick ^
  -size %oneWi%x%oneHt% ^
  xc: ^
  %sSEED% +noise Random ^
  -virtual-pixel Tile ^
  -blur 0,%blurSig% ^
  -modulate 100,0,100 ^
  -auto-level ^
  -auto-gamma ^
  %TEMP_FILE%

%IMG7%magick ^
  -size %2x%3 ^
  tile:%TEMP_FILE% ^
  %OUTFILE%
:skip

%IMG7%magick ^
  -size %oneWi%x%oneHt% ^
  xc: ^
  %sSEED% +noise Random ^
  -virtual-pixel Tile ^
  -blur 0,%blurSig% ^
  %sCOL% ^
  -auto-level ^
  -auto-gamma ^
  +channel ^
  +write mpr:NSE +delete ^
  -size %2x%3 ^
  tile:mpr:NSE ^
  %OUTFILE%

call echoRestore

@endlocal & set mbmOUTFILE=%OUTFILE%

detblur.bat

rem %1 is input image file
rem %2 is output image file
rem %3 is number of iterations
@rem
@rem Updated:
@rem   5-August-2022 for IM v7.
@rem

setlocal ENABLEDELAYEDEXPANSION

set INFILE=%1

set OUTFILE=%2

set NITER=%3
if "%NITER%"=="" set NITER=2

if /I %NITER% LSS 1 goto bad

set /A nClone=0
set /A nBlur=1

set strDB=

for /L %%i in (1,1,%NITER%) do (
  set strDB=!strDB! ^( -clone !nClone! -gaussian-blur x!nBlur! -auto-level ^)
  set /A nClone+=1
  set /A nBlur*=2
)

echo %strDB%

%IMG7%magick ^
  %1^
  %strDB% ^
  -evaluate-sequence Mean ^
  +depth ^
  %2

goto :eof

:bad
echo Call with: infile outfile niter

sh2grad.bat

rem Given %1 is white shape on black background,
rem replaces shape with each line gradient
rem with black at left of shape, white at right of shape.
rem %2 output.
rem %3 rotate degrees clockwise before processing (and de-rotate after).
@rem
@rem Updated:
@rem   5-August-2022 for IM v7.
@rem


@if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1

@setlocal enabledelayedexpansion

@call echoOffSave

call %PICTBAT%setInOut %1 s2g

if not "%2"=="" set OUTFILE=%2

set nROT=%3
if "%nROT%"=="." set nROT=
if "%nROT%"=="" set nROT=0

if %nROT%==0 (
  set IN_ROT=
  set OUT_ROT=
) else (
  set IN_ROT=-rotate %nROT% +repage
  set OUT_ROT=-rotate -%nROT% +repage
  set OUT_ROT=!OUT_ROT:--=!
)

set TMP_IMG=s2g_tmp.miff

%IMG7%magick ^
  %INFILE% ^
  -background Black ^
  %IN_ROT% ^
  +depth ^
  %TMP_IMG%

for /F "usebackq" %%L in (`%IMG7%magick identify ^
  -format "WW=%%w\nHH=%%h" ^
  %TMP_IMG%`) do set %%L

%IMG7%magick ^
  %TMP_IMG%^
  ( +clone ^
    -sparse-color Bilinear ^
      "0,0,Black %%[fx:w-1],0,White" ^
  ) ^
  +swap ^
  -alpha off ^
  -compose CopyOpacity -composite ^
  ( +clone ^
    -scale "1x%HH%^!" ^
    -scale "%WW%x%HH%^!" ^
    -alpha Opaque ^
  ) ^
  -compose DstOver -composite ^
  -crop x1 ^
  -auto-level ^
  -append ^
  +repage ^
  -background Black ^
  %OUT_ROT% ^
  %OUTFILE%

call echoRestore

@endlocal & set s2gOUTFILE=%OUTFILE%

sh2gradCol.bat

rem Given %1 is white shape on black background,
rem replaces shape with each absolute displacement map
rem from rectangle to shape.
rem %2 output.
@rem
@rem Updated:
@rem   5-August-2022 for IM v7.
@rem

@if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1

@setlocal enabledelayedexpansion

@call echoOffSave

call %PICTBAT%setInOut %1 s2gc

if not "%2"=="" set OUTFILE=%2

call %PICTBAT%sh2grad %INFILE% s2gc_red.miff
if ERRORLEVEL 1 exit /B 1

call %PICTBAT%sh2grad %INFILE% s2gc_grn.miff -90
if ERRORLEVEL 1 exit /B 1

%IMG7%magick ^
  s2gc_red.miff ^
  s2gc_grn.miff ^
  ( +clone -fill gray(50%%) -colorize 100 ) ^
  -combine ^
  %INFILE% ^
  -alpha off ^
  -compose CopyOpacity -composite ^
  -background Black -compose Over -layers Flatten ^
  %OUTFILE%
if ERRORLEVEL 1 exit /B 1

call echoRestore

@endlocal & set s2gcOUTFILE=%OUTFILE%

slopeXYdirn.bat

rem Given %1 is slopeXY structure (thus contains 2 images),
rem returns %2 conventional RGB image
rem with each channel set to direction.
rem %3 if SWAP, swap the two inputs.
rem %4 if SUB, subtract 50% before taking the arctan.
rem %5 percentage for addmodulus.
@rem
@rem Updated:
@rem   5-August-2022 for IM v7.
@rem

@if "%2"=="" findstr /B "rem @rem" %~f0 & exit /B 1

@setlocal

@call echoOffSave

call %PICTBAT%setInOut %1 sxyd

if not "%2"=="" set OUTFILE=%2

set SWAP=%3
if "%SWAP%"=="." set SWAP=
if "%SWAP%"=="" set SWAP=0

set SUBHALF=%4
if "%SUBHALF%"=="." set SUBHALF=
if "%SUBHALF%"=="" set SUBHALF=0

set nADDMOD=%5
if "%nADDMOD%"=="." set nADDMOD=
if "%nADDMOD%"=="" set nADDMOD=0

if /I "%SWAP%"=="SWAP" (
  set sSWAP=+swap
) else (
  set sSWAP=
)

if /I "%SUBHALF%"=="SUB" (
  set sSUBHALF=-evaluate Subtract 50%%
) else (
  set sSUBHALF=
)

echo %0: sSWAP=%sSWAP% sSUBHALF=%sSUBHALF% nADDMOD=%nADDMOD%

%IM7DEV%magick ^
  %INFILE% ^
  %sSWAP% ^
  %sSUBHALF% ^
  -process 'arctan2 b 0' ^
  -evaluate AddModulus %nADDMOD%%% ^
  +depth ^
  -depth 32 ^
  -define quantum:format=floating-point ^
  %OUTFILE%

if ERRORLEVEL 1 exit /B 1

call echoRestore

endlocal & set sxydOUTFILE=%OUTFILE%

slopeXYdirn.bat

rem Given %1 is slopeXY structure (thus contains 2 images),
rem returns %2 conventional RGB image
rem with each channel set to direction.
rem %3 if SWAP, swap the two inputs.
rem %4 if SUB, subtract 50% before taking the arctan.
rem %5 percentage for addmodulus.
@rem
@rem Updated:
@rem   5-August-2022 for IM v7.
@rem

@if "%2"=="" findstr /B "rem @rem" %~f0 & exit /B 1

@setlocal

@call echoOffSave

call %PICTBAT%setInOut %1 sxyd

if not "%2"=="" set OUTFILE=%2

set SWAP=%3
if "%SWAP%"=="." set SWAP=
if "%SWAP%"=="" set SWAP=0

set SUBHALF=%4
if "%SUBHALF%"=="." set SUBHALF=
if "%SUBHALF%"=="" set SUBHALF=0

set nADDMOD=%5
if "%nADDMOD%"=="." set nADDMOD=
if "%nADDMOD%"=="" set nADDMOD=0

if /I "%SWAP%"=="SWAP" (
  set sSWAP=+swap
) else (
  set sSWAP=
)

if /I "%SUBHALF%"=="SUB" (
  set sSUBHALF=-evaluate Subtract 50%%
) else (
  set sSUBHALF=
)

echo %0: sSWAP=%sSWAP% sSUBHALF=%sSUBHALF% nADDMOD=%nADDMOD%

%IM7DEV%magick ^
  %INFILE% ^
  %sSWAP% ^
  %sSUBHALF% ^
  -process 'arctan2 b 0' ^
  -evaluate AddModulus %nADDMOD%%% ^
  +depth ^
  -depth 32 ^
  -define quantum:format=floating-point ^
  %OUTFILE%

if ERRORLEVEL 1 exit /B 1

call echoRestore

endlocal & set sxydOUTFILE=%OUTFILE%

mPntEdgeMsk.bat

rem Make a mask white at point, black at edges.
rem %1 output file
rem %2 WWxHH image width and height, pixels, eg 1920x1080
rem %3 quoted CX,CY centre
rem %4 composite method [gm]
rem %5 smoothing: none, start, end, or both [none]
rem %6 L1, percentage start of gradation [0]
rem %7 L2, percentage start of gradation [100]

@if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1

@setlocal

@call echoOffSave

call %PICTBAT%setInOut %1 pem

set OUTFILE=%1

set IMGSIZE=%2
if "%IMGSIZE%"=="." set IMGSIZE=
if "%IMGSIZE%"=="" set IMGSIZE=600x400
call parseXxY2 600 400 pem_ %IMGSIZE%

set CENT=%3
if [%CENT%]==[.] set CENT=
if [%CENT%]==[] (
  set CX=0.5
  set CY=0.5
  set CENT="!CX!,!CY!"
)
call parseCommaList %CENT% pem_argc pem_argv
if ERRORLEVEL 1 exit /B 1
call propOfProp %pem__X% %pem_argv[0]% pem_argv[0]
if ERRORLEVEL 1 exit /B 1
call propOfProp %pem__Y% %pem_argv[1]% pem_argv[1]
if ERRORLEVEL 1 exit /B 1

set WW=%pem__X%
set HH=%pem__Y%

set CX=%pem_argv[0]%
set CY=%pem_argv[1]%

set pem_

set P1h=%CX%
set S1h=1/%CX%
set S2h=1/(%CX%-1)

set P1v=%CY%
set S1v=1/%CY%
set S2v=1/(%CY%-1)

set MTHD=%4
if "%MTHD%"=="." set MTHD=
if "%MTHD%"=="" set MTHD=gm

set SMTH=%5
if "%SMTH%"=="." set SMTH=
if "%SMTH%"=="" set SMTH=none

set L1=%6
if "%L1%"=="." set L1=
if "%L1%"=="" set L1=0

set L2=%7
if "%L2%"=="." set L2=
if "%L2%"=="" set L2=100

set sLEV=
if %L1% NEQ 0 if %L2% NEQ 100 (
  set sLEV=-level %L1%%%,%L2%%%
)

if /I "%MTHD%"=="Darken" (
  set COMPOS=-compose Darken -composite
) else if /I "%MTHD%"=="Lighten" (
  set COMPOS=-compose Lighten -composite
) else if /I "%MTHD%"=="Mean" (
  set COMPOS=-evaluate-sequence Mean
) else if /I "%MTHD%"=="Multiply" (
  set COMPOS=-compose Multiply -composite
) else if /I "%MTHD%"=="gm" (
  set COMPOS=-compose Multiply -composite -evaluate Pow 0.5
) else (
  echo %0: Bad MTHD [%MTHD%]
  exit /B 1
)

if /I "%SMTH%"=="none" (
  set sSMTH=
) else if /I "%SMTH%"=="start" (
  set sSMTH=-function sinusoid 0.25,-90,1,1
) else if /I "%SMTH%"=="end" (
  set sSMTH=-function sinusoid 0.25,0,1,0
) else if /I "%SMTH%"=="both" (
  set sSMTH=-function sinusoid 0.5,-90,0.5,0.5
) else (
  echo %0: Bad SMTH [%SMTH%]
  exit /B 1
)

%IMG7%magick ^
  ( -size 1x%WW% gradient: -rotate 90 ^
    -fx "u<%P1h%?u*%S1h%:1+(u-%P1h%)*%S2h%" ^
    %sSMTH% ^
    -scale "%WW%x%HH%^!" ^
  ) ^
  ( -size 1x%HH% gradient: -flip ^
    -fx "u<%P1v%?u*%S1v%:1+(u-%P1v%)*%S2v%" ^
    %sSMTH% ^
    -scale "%WW%x%HH%^!" ^
  ) ^
  %COMPOS% ^
  %sLEV% ^
  %OUTFILE%

call echoRestore

@endlocal

fanBW.bat

rem %1 input with back, white and other.
rem %2 output, replacing "other" with graduated gray.
rem Method: fan composition.

set INFILE=%1
set OUTFILE=%2

goto skip

%IMG7%magick ^
  %INFILE% ^
  -alpha off ^
  ( -clone 0 ^
    -channel RGB -negate +channel ^
    -fill White +opaque Black ^
    -morphology Distance Euclidean:4 ^
    -channel RGB -negate +channel ^
    -auto-level ^
  ) ^
  ( -clone 0 ^
    -fill White +opaque Black ^
    -morphology Distance Euclidean:4 ^
    -auto-level ^
  ) ^
  -delete 0 ^
  ( -clone 1 -evaluate Divide 2 ) ^
  ( -clone 0-1 ^
    -compose Mathematics ^
      -define compose:args=0,0.5,-0.5,0.5 ^
      -composite ^
  ) ^
  -delete 0-1 ^
  -compose DivideSrc -composite ^
  %OUTFILE%

:skip

%IMG7%magick ^
  %INFILE% ^
  -alpha off ^
  ( -clone 0 ^
    -channel RGB -negate +channel ^
    -fill White +opaque Black ^
    -morphology Distance Euclidean:4 ^
    -channel RGB -negate +channel ^
    -auto-level ^
  ) ^
  ( -clone 0 ^
    -fill White +opaque Black ^
    -morphology Distance Euclidean:4 ^
    -auto-level ^
    -evaluate Divide 2 ^
  ) ^
  -delete 0 ^
  ( -clone 0-1 ^
    -compose Mathematics ^
      -define compose:args=0,1,-0.5,0.5 ^
      -composite ^
  ) ^
  -delete 0 ^
  -compose DivideSrc -composite ^
  %OUTFILE%

All images on this page were created by the commands shown, using:

%IMG7%magick -version
Version: ImageMagick 7.1.0-42 Q16-HDRI x64 396d87c:20220709 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI OpenCL 
Delegates (built-in): bzlib cairo freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib
Compiler: Visual Studio 2022 (193231332)
%IM7DEV%magick -version
Version: ImageMagick 7.1.0-20 Q32-HDRI x86_64 2021-12-29 https://imagemagick.org
Copyright: (C) 1999-2021 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules OpenMP(4.5) 
Delegates (built-in): bzlib cairo fontconfig fpx freetype jbig jng jpeg lcms ltdl lzma pangocairo png raqm rsvg tiff webp wmf x xml zip zlib
Compiler: gcc (11.2)

Source file for this web page is gradients.h1. To re-create this web page, execute gradients.bat.


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 v2.1 6-Jan-2014.

Page created 05-Aug-2022 18:51:08.

Copyright © 2022 Alan Gibson.