snibgo's ImageMagick pages

Displacement by masked SRT

A method for graduated distortion.

IM provides an operator -distort SRT to scale, rotate and translate an entire image. We might want to apply this distortion to part of the image, and graduate the effect between that part and unaffected parts.

The general method is:

  1. Make a same-size grayscale mask that is black where we want no effect, white where we want full effect, and gray for a transition between the two.
  2. Make an identity absolute displacement map.
  3. Distort the entire map as required.
  4. Blend the distorted and identity maps with the mask.
  5. Displace the image with the map from the previous step.

Where the mask is gray, each result pixel will come from somewhere on the straight line between the source pixel with the same coordinates, and the source pixel corresponding to the full distortion.

This method needs a two-dimensional (WWxHH) mask. For a similar method that instead uses two look-up tables (WWx1 and HHx1) see Specify scaling by LUTs.

Sample input

For the source, we use an image with a grid so we can see what is happening.

set SRC=dms_src.png

call %PICTBAT%gridOver ^
  toes.png %SRC% 10 10 1 yellow

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

echo WW=%WW% HH=%HH% 
WW=267 HH=233 
dms_src.pngjpg

Masks

We make some sample masks:

%IMG7%magick ^
  -size %WW%x%HH% ^
  gradient: ^
  dms_msk1.png
dms_msk1.pngjpg
call %PICTBAT%mEllipMsk ^
  dms_msk2.png ^
  %WW%x%HH% "0.7p,0.6p" 0.4px0.3p
dms_msk2.pngjpg
call %PICTBAT%mPntEdgeMsk ^
  dms_msk3.png ^
  %WW%x%HH% "0.7p,0.6p" . both 10 90
dms_msk3.pngjpg
%IMG7%magick ^
  toes.png ^
  -colorspace Gray ^
  -blur 0x10 ^
  -auto-level ^
  -sigmoidal-contrast 5,50%% ^
  dms_msk4.png
dms_msk4.pngjpg

Each mask has a transition between black and white. If there were no transition, the result would contain sudden "jumps" in displacement -- a lack of first-order continuity.

Masks can be made or modified using methods shown in the Gradients Cookbook.

Displace the image

The script mskdSrt.bat performs the remaining steps. It takes parameters:

Parameter Description
%1 input image to be distorted
%2 input grayscale mask
%3 output file
%4 up to 7 quoted comma-separated numbers

The comma-separated numbers are:

Parameter Description
CX,CY Centre of effect.
Each number may be suffixed with one of %cCpP,
which mean the number is a percentage or proportion of the width or height.
Default: 0.5p,0.5p, half width and height.
ScaleX,ScaleY Scale factors for the two directions.
Default: 1.
Angle Rotation, degrees clockwise.
Default: 0.
dX,dY Deltas, which are added to CX and CY to make the last two parameters to IM's -distort SRT.
Each number may be suffixed with one of %cCpP,
which mean the number is a percentage or proportion of the width or height.
Default: 0.

Trailing numbers can be omitted.

The seven parameters are very similar to the seven-parameter version of IM's -distort SRT, but:

The output will be the same size as the input. Depending on the effect, parts of the input may not be present in the output.

In the examples, we set the centre of effect to be the same as the centre of the mask.

Scale (magnifying) effect:

call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk1.png ^
  dms_out_s1.png ^
  "0.7p,0.6p,1.3,1.3"
dms_out_s1.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk2.png ^
  dms_out_s2.png ^
  "0.7p,0.6p,1.3,1.3"
dms_out_s2.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk3.png ^
  dms_out_s3.png ^
  "0.7p,0.6p,1.3,1.3"
dms_out_s3.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk4.png ^
  dms_out_s4.png ^
  "0.7p,0.6p,1.3,1.3"
dms_out_s4.pngjpg

Scale (magnifying) in just the y-direction:

call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk1.png ^
  dms_out_sy1.png ^
  "0.7p,0.6p,1,1.3"
dms_out_sy1.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk2.png ^
  dms_out_sy2.png ^
  "0.7p,0.6p,1,1.3"
dms_out_sy2.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk3.png ^
  dms_out_sy3.png ^
  "0.7p,0.6p,1,1.3"
dms_out_sy3.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk4.png ^
  dms_out_sy4.png ^
  "0.7p,0.6p,1,1.3"
dms_out_sy4.pngjpg

When we magnify where the mask is white, and the mask edge is black so there is no change at the image edge, then the transition area will include image reduction.

Magnify in the y-direction, and reduce in the x-direction:

call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk1.png ^
  dms_out_sxsy1.png ^
  "0.7p,0.6p,0.7,1.3"
dms_out_sxsy1.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk2.png ^
  dms_out_sxsy2.png ^
  "0.7p,0.6p,0.7,1.3"
dms_out_sxsy2.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk3.png ^
  dms_out_sxsy3.png ^
  "0.7p,0.6p,0.7,1.3"
dms_out_sxsy3.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk4.png ^
  dms_out_sxsy4.png ^
  "0.7p,0.6p,0.7,1.3"
dms_out_sxsy4.pngjpg

Rotation effect:

call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk1.png ^
  dms_out_r1.png ^
  "0.7p,0.6p,1,1,20"
dms_out_r1.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk2.png ^
  dms_out_r2.png ^
  "0.7p,0.6p,1,1,20"
dms_out_r2.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk3.png ^
  dms_out_r3.png ^
  "0.7p,0.6p,1,1,20"
dms_out_r3.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk4.png ^
  dms_out_r4.png ^
  "0.7p,0.6p,1,1,20"
dms_out_r4.pngjpg

In the transition area, where the mask is between black and white, we do not get a reduced rotation. This is because each destination pixel is set to an input colour that lies on a straight line between that coordinate and the full-effect distortion coordinate. As a rotation does not move pixels in straight lines, the chosen coordinate will not represent a reduced rotation that corresponds to the grayscale lightness.

The other transformations (scale and translation) do move pixels in straight lines, so partial transformations are correct.

Translation effect:

call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk1.png ^
  dms_out_t1.png ^
  "0.7p,0.6p,1,1,0,-0.08p,0.05p"
dms_out_t1.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk2.png ^
  dms_out_t2.png ^
  "0.7p,0.6p,1,1,0,-0.08p,0.05p"
dms_out_t2.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk3.png ^
  dms_out_t3.png ^
  "0.7p,0.6p,1,1,0,-0.08p,0.05p"
dms_out_t3.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk4.png ^
  dms_out_t4.png ^
  "0.7p,0.6p,1,1,0,-0.08p,0.05p"
dms_out_t4.pngjpg

Scale, rotate and translate effect:

call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk1.png ^
  dms_out_srt1.png ^
  "0.7p,0.6p,1.3,1.3,20,-0.08p,0.05p"
dms_out_srt1.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk2.png ^
  dms_out_srt2.png ^
  "0.7p,0.6p,1.3,1.3,20,-0.08p,0.05p"
dms_out_srt2.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk3.png ^
  dms_out_srt3.png ^
  "0.7p,0.6p,1.3,1.3,20,-0.08p,0.05p"
dms_out_srt3.pngjpg
call %PICTBAT%mskdSrt ^
  %SRC% ^
  dms_msk4.png ^
  dms_out_srt4.png ^
  "0.7p,0.6p,1.3,1.3,20,-0.08p,0.05p"
dms_out_srt4.pngjpg

Scripts

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

mEllipMsk.bat

rem Makes elliptical mask, with gradation.
rem %1 output file
rem %2 WWxHH image width and height, pixels, eg 1920x1080
rem %3 quoted CX,CY ellipse centre
rem %4 ERXxERY ellipse radius width and height, pixels, eg 150x100
rem %5 angle of rotation of ellipse, degrees [0]
rem %6 RF, thickness of gradation, 0.0 < RF <= 1.0 [0.5]

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

@setlocal

rem @call echoOffSave

set OUTFILE=%1

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

set ELL_CENT=%3
if [%ELL_CENT%]==[.] set ELL_CENT=
if [%ELL_CENT%]==[] (
  set /A CX=%mem__X%/2
  set /A CY=%mem__Y%/2
  set ELL_CENT="!CX!,!CY!"
)
call parseCommaList %ELL_CENT% mem_argc mem_argv
if ERRORLEVEL 1 exit /B 1
call propOf %mem__X% %mem_argv[0]% mem_argv[0]
if ERRORLEVEL 1 exit /B 1
call propOf %mem__Y% %mem_argv[1]% mem_argv[1]
if ERRORLEVEL 1 exit /B 1

set ELL_RAD=%~4
if "%ELL_RAD%"=="." set ELL_RAD=
if "%ELL_RAD%"=="" (
  set /A RX=%mem__X%/4
  set /A RY=%mem__Y%/4
  set ELL_RAD=!RX!x!RY!
)
call parseXxY2 %mem__X% %mem__Y% mem_er_ %ELL_RAD%

set ANG=%5
if "%ANG%"=="." set ANG=
if "%ANG%"=="0.0" set ANG=0
if "%ANG%"=="" set ANG=0

if "%ANG%"=="" (
  set ROT=
) else (
  set ROT=-distort SRT 1,%ANG%
  set ROT=-define gradient:angle=%ANG%
)

set RF=%6
if "%RF%"=="." set RF=
if "%RF%"=="" set RF=0.5

set mem_

%IMG7%magick ^
  -size %mem__X%x%mem__Y% ^
  -define gradient:center=%mem_argv[0]%,%mem_argv[1]% ^
  -define gradient:radii=%mem_er__X%,%mem_er__Y% ^
  %ROT% ^
  radial-gradient: ^
  -level 0,%%[fx:QuantumRange*%RF%] ^
  %OUTFILE%

call echoRestore

@endlocal

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

rem @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

parseCommaList.bat

rem Given %1 is a (quoted) comma- or space-separated list,
rem sets environment variables %2 to the number of values
rem and %3 (as an array) to the values.

set LIST=%~1

set pclNUM=%2
if "%pclNUM%"=="." set pclNUM=
if "%pclNUM%"=="" set pclNUM=argc

set pclVALS=%3
if "%pclVALS%"=="." set pclVALS=
if "%pclVALS%"=="" set pclVALS=argv

call :doParse %LIST%
set /A %pclNUM%=%pclN%

rem echo %0: pclVALS=%pclVALS%

exit /B 0

:: --------------------------------------------
:: Subroutine

:doParse

set pclN=0
:loop
if "%1"=="" exit /B 0

rem echo %0: 1=%1 2=%2 3=%3
set %pclVALS%[%pclN%]=%1
set /A pclN+=1
shift /1

goto loop

exit /B 0

parseXxY2.bat

rem Parses %4, default %1 and %2. Returns %3_X and %3_Y.
@rem
@rem %4 is one of these formats:
@rem   {blank}
@rem   .
@rem   {number}
@rem   {number}x
@rem   x{number}
@rem   {number}x{number}
@rem
@rem A number can be suffixed with %, c or p or C or P.
@rem

@set pxxy=%4
@set pxxyFirst=%pxxy:~0,1%
@rem echo pxxyFirst=%pxxyFirst%

@if "%pxxyFirst%"=="x" set pxxy=%1%pxxy%

@if "%pxxy%"=="." set pxxy=
@if "%pxxy%"=="" set pxxy=%1x%2

@for /F "usebackq tokens=1-2 delims=xX" %%X in ('%pxxy%') do @(
  @rem echo %%X,%%Y
  @set pxxyX=%%X
  @set pxxyY=%%Y
)
@if "%pxxyY%"=="" set pxxyY=%2


set CH_LAST=%pxxyX:~-1%

if "%CH_LAST%"=="^%" set CH_LAST=c

if /I "%CH_LAST%"=="c" (
  for /F "usebackq" %%L in (`%IM%identify ^
    -precision 19 ^
    -format "pxxyX=%%[fx:%1*%pxxyX:~0,-1%/100]" ^
    xc:`) do set %%L

) else if /I "%CH_LAST%"=="p" (
  for /F "usebackq" %%L in (`%IM%identify ^
    -precision 19 ^
    -format "pxxyX=%%[fx:%1*%pxxyX:~0,-1%]" ^
    xc:`) do set %%L
)


set CH_LAST=%pxxyY:~-1%

if "%CH_LAST%"=="^%" set CH_LAST=c

if /I "%CH_LAST%"=="c" (
  for /F "usebackq" %%L in (`%IM%identify ^
    -precision 19 ^
    -format "pxxyY=%%[fx:%2*%pxxyY:~0,-1%/100]" ^
    xc:`) do set %%L

) else if /I "%CH_LAST%"=="p" (
  for /F "usebackq" %%L in (`%IM%identify ^
    -precision 19 ^
    -format "pxxyY=%%[fx:%2*%pxxyY:~0,-1%]" ^
    xc:`) do set %%L
)




@rem echo pxxyX=%pxxyX% pxxyY=%pxxyY%

set %3_X=%pxxyX%
set %3_Y=%pxxyY%

propOf.bat

rem Given %1 is a number,
rem %2 is a number possibly suffixed with % or c or p or C or P,
rem sets variable %3 to result.
@rem All can be floating-point.
@rem
@rem Eg if %1 is 300
@rem then %2 might be 60 or 20% or 20c or 0.2p, and the result is 60.
@rem
@rem See also propOf.bat

setlocal

set VAR_S=%2
set OUTV=%VAR_S%
set CH_LAST=%VAR_S:~-1%

if "%CH_LAST%"=="^%" set CH_LAST=c

if /I "%CH_LAST%"=="c" (
  for /F "usebackq" %%L in (`%IM%identify ^
    -precision 16 ^
    -format "OUTV=%%[fx:%1*%VAR_S:~0,-1%/100]" ^
    xc:`) do set %%L

) else if /I "%CH_LAST%"=="p" (
  for /F "usebackq" %%L in (`%IM%identify ^
    -precision 16 ^
    -format "OUTV=%%[fx:%1*%VAR_S:~0,-1%]" ^
    xc:`) do set %%L
)

echo OUTV=%OUTV%

@endlocal & set %3=%OUTV%

propOfProp.bat

rem Like propOf.bat but result is proportion of %1.

rem Given %1 is a number,
rem %2 is a number possibly suffixed with % or c or p or C or P,
rem sets variable %3 to result.
@rem All can be floating-point.
@rem
@rem Eg if %1 is 300
@rem then %2 might be 60 or 20% or 20c or 0.2p, and the result is 0.2.

setlocal

set VAR_S=%2
set OUTV=%VAR_S%
set CH_LAST=%VAR_S:~-1%

if "%CH_LAST%"=="^%" set CH_LAST=c

if /I "%CH_LAST%"=="c" (
  for /F "usebackq" %%L in (`%IM%identify ^
    -precision 16 ^
    -format "OUTV=%%[fx:%VAR_S:~0,-1%/100]" ^
    xc:`) do set %%L

) else if /I "%CH_LAST%"=="p" (
  set OUTV=%VAR_S:~0,-1%
) else (
  for /F "usebackq" %%L in (`%IM%identify ^
    -precision 16 ^
    -format "OUTV=%%[fx:%VAR_S%/%1]" ^
    xc:`) do set %%L
)

echo OUTV=%OUTV%

@endlocal & set %3=%OUTV%

mskdSrt.bat

rem %1 input image to be distorted
rem %2 input grayscale mask, white for full effect
rem %3 output file
rem %4 up to 7 quoted comma-separated numbers:
rem     X,Y centre of effect
rem     ScaleX,ScaleY
rem     Angle
rem     dX,dY

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

@setlocal

rem @call echoOffSave

call %PICTBAT%setInOut %1 ms

set INMSK=%2

if not "%3"=="" if not "%3"=="." set OUTFILE=%3

set CSNUMS=%~4
if "%CSNUMS%"=="." set CSNUMS=
if "%CSNUMS%"=="" set CSNUMS=0.5p,0.5p

set WW=
for /F "usebackq" %%L in (`%IMG7%magick identify ^
  -format "WW=%%w\nHH=%%h\nW_2=%%[fx:w/2]\nH_2=%%[fx:h/2]\n" ^
  %INFILE%`) do set %%L

if "%WW%"=="" (
  echo %0: Can't read INFILE [%INFILE%]
  exit /B 1
)

call parseCommaList "%CSNUMS%" ms_argc ms_argv

if "%ms_argv[0]%"=="" set %ms_argv[0]=%W_2%
if "%ms_argv[1]%"=="" set %ms_argv[1]=%H_2%
if "%ms_argv[2]%"=="" set %ms_argv[2]=1
if "%ms_argv[3]%"=="" set %ms_argv[3]=1
if "%ms_argv[4]%"=="" set %ms_argv[4]=0
if "%ms_argv[5]%"=="" set %ms_argv[5]=0
if "%ms_argv[6]%"=="" set %ms_argv[6]=0

if ERRORLEVEL 1 exit /B 1
call propOf %WW% %ms_argv[0]% ms_argv[0]
if ERRORLEVEL 1 exit /B 1
call propOf %HH% %ms_argv[1]% ms_argv[1]
if ERRORLEVEL 1 exit /B 1
call propOf %WW% %ms_argv[5]% ms_argv[5]
if ERRORLEVEL 1 exit /B 1
call propOf %HH% %ms_argv[6]% ms_argv[6]
if ERRORLEVEL 1 exit /B 1

set ms_

set SSFACT=2

set ms_argv[5a]=%%[fx:!ms_argv[0]!*%SSFACT%+!ms_argv[5]!*%SSFACT%]
set ms_argv[6a]=%%[fx:!ms_argv[1]!*%SSFACT%+!ms_argv[6]!*%SSFACT%]

for %%I in (0,1,5,6) do (
  set ms_argv[%%I]=%%[fx:!ms_argv[%%I]!*%SSFACT%]
)


set ms_


%IMG7%magick ^
  %INFILE% ^
  -resize 200%% ^
  -set option:MYSIZE %%[fx:w]x%%[fx:h] ^
  ( +clone ^
    -sparse-color bilinear ^
0,0,#008,^
0,%%[fx:h-1],#0f8,^
%%[fx:w-1],0,#f08,^
%%[fx:w-1],%%[fx:h-1],#ff8 ^
    +write mpr:IDENT ^
    +delete ^
  ) ^
  ( mpr:IDENT ^
    ( +clone ^
      -distort SRT %ms_argv[0]%,%ms_argv[1]%,%ms_argv[2]%,%ms_argv[3]%,%ms_argv[4]%,%ms_argv[5a]%,%ms_argv[6a]% ^
    ) ^
    ( %INMSK% -resize 200%% ) ^
    -compose Over -composite ^
  ) ^
  -compose Distort -composite ^
  -resize 50%% ^
  %OUTFILE%

call echoRestore

@endlocal

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

%IM%identify -version
Version: ImageMagick 6.9.9-50 Q16 x64 2018-06-02 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 gslib heic jng jp2 jpeg lcms lqr lzma openexr pangocairo png ps raw rsvg tiff webp xml zlib

To improve internet download speeds, some images may have been automatically converted (by ImageMagick, of course) from PNG to JPG.

Source file for this web page is dispmsksrt.h1. To re-create this web page, execute "procH1 dispmsksrt".


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 10-July-2019.

Page created 12-Jul-2019 12:27:49.

Copyright © 2019 Alan Gibson.