We can push pixels to new locations while pinning others in place.
This page does not consider how the user might specify the displacement. A trimap can specify which pixels are pinned, or pushed to new locations, or are free to move or not. I can't see an elegant graphical method for specifying new locations for pushed pixels. This could be simple text coordinates, of course.
We demonstrate with a photograph that has an overlaid grid.
goto :eof call %PICTBAT%gridOver ^ toes.png pop_src.png 10 10 set SRC=pop_src.png |
![]() |
We also make an identity absolute displacement map.
set IDENT=^ 0,0,#000,^ %%[fx:w-1],0,#f00,^ 0,%%[fx:h-1],#0f0,^ %%[fx:w-1],%%[fx:h-1],#ff0 %IMG7%magick ^ %SRC% ^ -strip ^ -sparse-color bilinear "%IDENT%" ^ pop_id_abs_map.png |
![]() |
On this page, ordinary absolute displacement maps are called "pull" maps, because the value at a pixel in the map determines where the corresponding pixel in the final image comes from. We use the process module invdispmap to invert the map, making a "push" map, which determines where the corresponding pixel in the final image will be pushed to. The process invdispmap also does the opposite, converting a push map into a pull map. The inversion process leaves holes that we fill by relaxation.
The identity absolute displacement map creates no displacement, so can be regarded as either a pull map or a push map.
We first consider a special case: we move coordinate (x1,y1) to (x2,y2), by moving an entire column from x1 to x2, and an entire row from y1 to y2. All other pixels should move in a "reasonable" way. Pixels at the top and bottom edge will move left or right. Pixels at the left or right edge will move up or down. Corner pixels won't move at all.
set X1=100 set Y1=100 set X2=130 set Y2=120
We can crop into two pieces horizontally at X1, then resize each, and append them together. Then we do the same vertically.
set sFMT=^ WW=%%w\n^ HH=%%h\n^ WR1=%%[fx:w-%X1%]\n^ WR2=%%[fx:w-%X2%]\n^ HB1=%%[fx:h-%Y1%]\n^ HB2=%%[fx:h-%Y2%] for /F "usebackq" %%L in (`%IMG7%magick identify ^ -format "%sFMT%" %SRC%`) do set %%L %IMG7%magick ^ %SRC% ^ ( -clone 0 ^ -crop %X1%x+0+0 +repage ^ -resize "%X2%x^!" ^ ) ^ ( -clone 0 ^ -crop %WR1%x+%X1%+0 +repage ^ -resize "%WR2%x^!" ^ ) ^ -delete 0 ^ +append +repage ^ ( -clone 0 ^ -crop x%Y1%+0+0 +repage ^ -resize "x%Y2%^!" ^ ) ^ ( -clone 0 ^ -crop x%HB1%+0+%Y1% +repage ^ -resize "x%HB2%^!" ^ ) ^ -delete 0 ^ -append +repage ^ pop_li1.png |
![]() |
The abrupt change of scale is obvious.
A single point can be moved by applying a power (gamma) function to the gradients of the identity map. This is a pull map, so the value at coordinate (x2,y2) should be x1 in the red channel and y1 in the green channel.
We raise to the power k such that:
v' = v^k log(v') = log(v^k) (where log is to any base) = k * log(v) k = log(v') / log(v)
We use v7, so the calculation can be done within the "-evaluate pow".
Make a displacement map. %IMG7%magick ^ pop_id_abs_map.png ^ -channel R ^ -evaluate pow %%[fx:log(%X1%/(w-1))/log(%X2%/(w-1))] ^ -channel G ^ -evaluate pow %%[fx:log(%Y1%/(h-1))/log(%Y2%/(h-1))] ^ +channel ^ pop_pc_map.png |
![]() |
Apply the map. %IMG7%magick ^ %SRC% ^ pop_pc_map.png ^ -compose Distort -set option:compose:args 100%%x100%% -composite ^ pop_pc1.png |
![]() |
There is no abrupt change of scale, but stretching at the left and top edges is severe.
Iterating the above won't move multiple points, because moving any one point uniquely determines the movement of all the others. A power (gamma) curve is determined by a single point.
The obvious solution is a Bézier curve, which is determined by however many points we want. An external program, cBezCurve.exe, calculates values along a Bézier curve, creating an Nx1 clut image. We use this twice, for the two dimensions.
(I don't publish the source or binary of cBezCurve.exe. The program calculates "reasonable" coordinates for the required extra control points.)
Get the dimensions.
for /F "usebackq" %%L in (`%IMG7%magick identify ^ -format "WW=%%w\nHH=%%h\nWm1=%%[fx:w-1]\nHm1=%%[fx:h-1]" ^ %SRC%`) do set %%L echo WW=%WW% HH=%HH%
WW=267 HH=233
Make a WWx1 clut for the horizontal displacement. This is really a slightly distorted gradient. At ordinate X2, we want value X1. We also pin the first and last ordinates, 0 and %Wm1%.
cBezCurve /p0 /C /a1 /m%Wm1% /I"0,0; %X2%,%X1%; %Wm1%,%Wm1%" /n%WW% /T1 /F0 /Lpop_dx.ppm
Similarly, a HHx1 clut for the vertical displacement.
cBezCurve /p0 /C /a1 /m%Hm1% /I"0,0; %Y2%,%Y1%; %Hm1%,%Hm1%" /n%HH% /T1 /F0 /Lpop_dy.ppm
Use these two cluts to make a displacement map. We have told cBezCurve.exe to create just the red channel, so combining them is slightly complex. We need the red channel of the first PPM to go into the red channel of the map, and red channel of the second PPM to go into the green channel of the map.
Make a displacement map. %IMG7%magick ^ pop_dx.ppm ^ ( pop_dy.ppm -rotate 90 ) ^ xc:Black ^ -channel R ^ -scale "%WW%x%HH%^!" ^ -separate ^ +channel ^ -combine ^ pop_pmp_map.png |
![]() |
Apply the map. %IMG7%magick ^ %SRC% ^ pop_pmp_map.png ^ -compose Distort -set option:compose:args 100%%x100%% -composite ^ pop_pmp1.png |
![]() |
The result is similar to the one from the power (gamma) curve, but with less severe stretching at the left and top edges.
cBezCurve.exe has other interpolation methods, such as linear:
cBezCurve /p0 /C /a1 /m%Wm1% /I"0,0; %X2%,%X1%; %Wm1%,%Wm1%" /n%WW% /T0 /F0 /Lpop_dx1a.ppm cBezCurve /p0 /C /a1 /m%Hm1% /I"0,0; %Y2%,%Y1%; %Hm1%,%Hm1%" /n%HH% /T0 /F0 /Lpop_dy1a.ppm
Make a displacement map. %IMG7%magick ^ pop_dx1a.ppm ^ ( pop_dy1a.ppm -rotate 90 ) ^ xc:Black ^ -channel R ^ -scale "%WW%x%HH%^!" ^ -separate ^ +channel ^ -combine ^ pop_pmp_map1a.png |
![]() |
Apply the map. %IMG7%magick ^ %SRC% ^ pop_pmp_map1a.png ^ -compose Distort -set option:compose:args 100%%x100%% -composite ^ pop_pmp1a.png The result is essentially the same as the crop-resize method above. |
![]() |
With Bézier curves, we can push as many pixels as we like. Morever, the same mechanism can pin pixels; we simply give the same coordinates for input and output.
set pinX=30 set pinY=25 set X3=50 set Y3=200 set X4=55 set Y4=185 set X5=200 set Y5=50 set X6=210 set Y6=60 set NewX=%pinX%,%pinX%; %X4%,%X3%; %X6%,%X5% set NewY=%pinY%,%pinY%; %Y4%,%Y3%; %Y6%,%Y5%
Make the cluts:
cBezCurve /p0 /C /a1 /m%Wm1% /I"0,0; %X2%,%X1%; %NewX%; %Wm1%,%Wm1%" /n%WW% /T1 /F0 /Lpop_dx2.ppm cBezCurve /p0 /C /a1 /m%Hm1% /I"0,0; %Y2%,%Y1%; %NewY%; %Hm1%,%Hm1%" /n%HH% /T1 /F0 /Lpop_dy2.ppm
Make a displacement map. %IMG7%magick ^ pop_dx2.ppm ^ ( pop_dy2.ppm -rotate 90 ) ^ xc:Black ^ -channel R ^ -scale "%WW%x%HH%^!" ^ -separate ^ +channel ^ -combine ^ pop_pmp_map2.png |
![]() |
Apply the map. %IMG7%magick ^ %SRC% ^ pop_pmp_map2.png ^ -compose Distort -set option:compose:args 100%%x100%% -composite ^ pop_pmp2.png |
![]() |
When we move X1,Y1 to X2,Y2, all pixels on row Y1 will move to row Y2, and all pixels on column X1 will move to column X2. Hence, input lines that were vertical or horizontal will be vertical or horizontal in the output.
We could invert the map, getting a push (instead of pull) map. This could be modulated, eg reduced except in the vicinity of points, and converted back to a pull map. For example, we modulate with a gradient so we have no displacement at the top:
Invert, to get a push map. %IM7DEV%magick ^ pop_pmp_map2.png ^ -process invdispmap ^ pop_pmp_map2i.png |
![]() |
Fill by relaxation. set rfCOMP_METRIC=PAE set THRESH=1e-4 set NUM_ITER=1000 call %PICTBAT%relaxFillMS ^ pop_pmp_map2i.png . pop_pmp_maprf.png %THRESH% %NUM_ITER% We will use this push map a few times. |
![]() |
Blend with identity map, to get zero displacement at the top and full displacement at the bottom. %IMG7%magick ^ pop_pmp_maprf.png ^ pop_id_abs_map.png ^ -size %WW%x%HH% gradient: ^ -compose Over -composite ^ pop_pmp_mapbld.png |
![]() |
Invert, to get a pull map. %IM7DEV%magick ^ pop_pmp_mapbld.png ^ -process invdispmap ^ pop_pmp_mapbldi.png |
![]() |
Fill by relaxation. call %PICTBAT%relaxFillMS ^ pop_pmp_mapbldi.png . pop_pmp_mapbirf.png %THRESH% %NUM_ITER% |
![]() |
Apply the map. %IMG7%magick ^ %SRC% ^ pop_pmp_mapbirf.png ^ -compose Distort -set option:compose:args 100%%x100%% -composite ^ pop_pmp_bld.png |
![]() |
In the next example, we get the full displacement at the required points, and decreasing displacement further from any points. We are modifying the push map, so we want a mask that is black at the original locations of pinned or pushed pixels.
Black where we have a point; otherwise white. %IMG7%magick ^ -size %WW%x%HH% ^ xc:White ^ -fill Black ^ -draw "point %pinX%,%pinY% point %X1%,%Y1% point %X3%,%Y3% point %X5%,%Y5% " ^ pop_pnt_mask.png |
![]() |
%IMG7%magick ^ pop_pnt_mask.png ^ -morphology Distance Euclidean:7,100 ^ -auto-level ^ pop_pnt_mask2.png |
![]() |
Blend with identity map. %IMG7%magick ^ pop_pmp_maprf.png ^ pop_id_abs_map.png ^ pop_pnt_mask2.png ^ -compose Over -composite ^ pop_pmp_mapbld2.png |
![]() |
Invert, to get a pull map. %IM7DEV%magick ^ pop_pmp_mapbld2.png ^ -process invdispmap ^ pop_pmp_mapbld2i.png |
![]() |
Fill by relaxation. call %PICTBAT%relaxFillMS ^ pop_pmp_mapbld2i.png . pop_pmp_maprf2.png %THRESH% %NUM_ITER% |
![]() |
Apply the map. %IMG7%magick ^ %SRC% ^ pop_pmp_maprf2.png ^ -compose Distort -set option:compose:args 100%%x100%% -composite ^ pop_pmp_bld2.png |
![]() |
Another possibility: apply the full effect only in a circle around each point. The radius at each point probably needs to be sufficient to cover the displacement. For simplicity, we use the same radius and blur for all the circles.
Draw circles, and blur them. set sCIRC=circle 0,0 0,60 %IMG7%magick ^ -size %WW%x%HH% ^ xc:White ^ -fill Black ^ -draw "translate %pinX%,%pinY% %sCIRC%" ^ -draw "translate %X1%,%Y1% %sCIRC%" ^ -draw "translate %X3%,%Y3% %sCIRC%" ^ -draw "translate %X5%,%Y5% %sCIRC%" ^ -blur 0x25 ^ pop_pnt_mask3.png |
![]() |
Blend with identity map. %IMG7%magick ^ pop_pmp_maprf.png ^ pop_id_abs_map.png ^ pop_pnt_mask3.png ^ -compose Over -composite ^ pop_pmp_mapbld3.png |
![]() |
Invert, to get a pull map. %IM7DEV%magick ^ pop_pmp_mapbld3.png ^ -process invdispmap ^ pop_pmp_mapbld3i.png |
![]() |
Fill by relaxation. call %PICTBAT%relaxFillMS ^ pop_pmp_mapbld3i.png . pop_pmp_maprf3.png %THRESH% %NUM_ITER% |
![]() |
Apply the map. %IMG7%magick ^ %SRC% ^ pop_pmp_maprf3.png ^ -compose Distort -set option:compose:args 100%%x100%% -composite ^ pop_pmp_bld3.png |
![]() |
Above, we have pinned or pushed individual pixels. (Strictly speaking, individual coordinates.) Instead, we can pin or push groups of pixels. All the pixels in each group will be displaced by the same amount. The method shown here is in general quite complex, but simple enough when each area is a rectangle (so this also includes horizontal and vertical lines).
The method is to either construct an identity absolute displacement map and move the areas, making the other pixels transparent, or to make a relative displacement map with areas of the appropriate shade of gray.
Each pixel in the displacement map is one of:
Transparent pixels in the displacement map are then filled by the relaxation method, and the map is used to displace the input image.
IM v6 can't have %[fx:] in -crop, so we use v7. For the edges of the map, early versions of v7 don't have "-region" so we do the job with four crops.
set sEDGES=^ ( -clone 0 -crop %%[fx:w]x1+0+0 ) ^ ( -clone 0 -crop %%[fx:w]x1+0+%%[fx:h-1] ) ^ ( -clone 0 -crop 1x%%[fx:h]+0+0 ) ^ ( -clone 0 -crop 1x%%[fx:h]+%%[fx:w-1]+0 )
%IMG7%magick ^ pop_id_abs_map.png ^ ( -clone 0 -alpha transparent ) ^ %sEDGES% ^ ( -clone 0 ^ -crop %%[fx:w*0.3]x%%[fx:h*0.2]+%%[fx:w*0.4]+%%[fx:h*0.4] ^ ) ^ -delete 0 ^ -background None ^ -layers flatten ^ pop_map1.png |
![]() |
set rfCOMP_METRIC=PAE set THRESH=1e-4 set NUM_ITER=1000 rem set rfCOMP_METRIC=RMSE rem set THRESH=1e-6 call %PICTBAT%relaxFillMS ^ pop_map1.png . . %THRESH% %NUM_ITER% |
![]() |
We should have no displacement: %IMG7%magick ^ %SRC% ^ pop_map1_rfms.png ^ -compose Distort -set option:compose:args 100%%x100%% -composite ^ pop_m1.png |
![]() |
Displace a central block:
%IMG7%magick ^ pop_id_abs_map.png ^ ( -clone 0 -alpha transparent ) ^ %sEDGES% ^ ( -clone 0 ^ -set DW %%[fx:w*0.1] ^ -set DH %%[fx:h*0.1] ^ -crop %%[fx:w*0.3]x%%[fx:h*0.2]+%%[fx:w*0.4]+%%[fx:h*0.4] ^ -repage "+%%[DW]+%%[DH]^!" ^ ) ^ -delete 0 ^ -background None ^ -layers flatten ^ pop_map2.png |
![]() |
call %PICTBAT%relaxFillMS ^ pop_map2.png . . %THRESH% %NUM_ITER% |
![]() |
%IMG7%magick ^ %SRC% ^ pop_map2_rfms.png ^ -compose Distort -set option:compose:args 100%%x100%% -composite ^ pop_m2.png |
![]() |
Displace the four corners of a central block:
set sREPAGE=-repage "+%%[DW]+%%[DH]^^^!" %IMG7%magick ^ pop_id_abs_map.png ^ -set DW %%[fx:w*0.1] ^ -set DH %%[fx:h*0.1] ^ ( -clone 0 -alpha transparent ) ^ %sEDGES% ^ ( -clone 0 ^ -crop 1x1+%%[fx:w*0.4]+%%[fx:h*0.4] ^ %sREPAGE% ^ ) ^ ( -clone 0 ^ -set DW %%[fx:w*0.1] ^ -set DH %%[fx:h*0.1] ^ -crop 1x1+%%[fx:w*0.7]+%%[fx:h*0.4] ^ %sREPAGE% ^ ) ^ ( -clone 0 ^ -crop 1x1+%%[fx:w*0.4]+%%[fx:h*0.6] ^ %sREPAGE% ^ ) ^ ( -clone 0 ^ -crop 1x1+%%[fx:w*0.7]+%%[fx:h*0.6] ^ %sREPAGE% ^ ) ^ -delete 0 ^ -background None ^ -layers flatten ^ pop_map3.png |
![]() |
call %PICTBAT%relaxFillMS ^ pop_map3.png . . %THRESH% %NUM_ITER% |
![]() |
%IMG7%magick ^ %SRC% ^ pop_map3_rfms.png ^ -compose Distort -set option:compose:args 100%%x100%% -composite ^ pop_m3.png |
![]() |
The displacement is not as far as we wanted. Repeat the previous, but without multi-scale:
call %PICTBAT%relaxFill ^ pop_map3.png . pop_map3a_rfms.png ^ %THRESH% %NUM_ITER% |
![]() |
%IMG7%magick ^ %SRC% ^ pop_map3a_rfms.png ^ -compose Distort -set option:compose:args 100%%x100%% -composite ^ pop_m3a.png |
![]() |
This hasn't cured the problem.
Sadly, the process doesn't work well when we have isolated pixels in the holed image. The pixel at (50%,50%) has the correct value of RG=(40%,40%), but moving away from this pixel, the values swiftly rise.
Try moving small squares, one at each location:
set rfCOMP_METRIC=PAE set THRESH=1e-4 set NUM_ITER=1000 set sREPAGE=-repage "+%%[DW]+%%[DH]^^^!" set SW=10 set SH=10 %IMG7%magick ^ pop_id_abs_map.png ^ -set DW %%[fx:w*0.1] ^ -set DH %%[fx:h*0.1] ^ ( -clone 0 -alpha transparent ) ^ %sEDGES% ^ ( -clone 0 ^ -crop %SW%x%SH%+%%[fx:w*0.4]+%%[fx:h*0.4] ^ %sREPAGE% ^ ) ^ ( -clone 0 ^ -set DW %%[fx:w*0.1] ^ -set DH %%[fx:h*0.1] ^ -crop %SW%x%SH%+%%[fx:w*0.7]+%%[fx:h*0.4] ^ %sREPAGE% ^ ) ^ ( -clone 0 ^ -crop %SW%x%SH%+%%[fx:w*0.4]+%%[fx:h*0.6] ^ %sREPAGE% ^ ) ^ ( -clone 0 ^ -crop %SW%x%SH%+%%[fx:w*0.7]+%%[fx:h*0.6] ^ %sREPAGE% ^ ) ^ -delete 0 ^ -background None ^ -layers flatten ^ pop_map4.png |
![]() |
call %PICTBAT%relaxFillMS ^ pop_map4.png . . %THRESH% %NUM_ITER% |
![]() |
%IMG7%magick ^ %SRC% ^ pop_map4_rfms.png ^ -compose Distort -set option:compose:args 100%%x100%% -composite ^ pop_m4.png |
![]() |
Relative displacement maps are simpler, as each rectangle is a constant shade of gray.
%IMG7%magick ^ %SRC% ^ -shave 1x1 ^ -alpha transparent ^ -bordercolor gray(50%%) -border 1 ^ -set page %%[fx:w*0.4]+%%[fx:h*0.4] ^ ( -clone 0 ^ -crop %%[fx:w*0.3]x%%[fx:h*0.2]+%%[fx:w*0.4]+%%[fx:h*0.4] ^ -alpha opaque ^ -fill gray(50%%) -colorize 100 ^ ) ^ -background None ^ -layers merge ^ pop_rmap1.png |
![]() |
set rfCOMP_METRIC=PAE set THRESH=1e-4 set NUM_ITER=1000 rem set rfCOMP_METRIC=RMSE rem set THRESH=1e-6 call %PICTBAT%relaxFillMS ^ pop_rmap1.png . . %THRESH% %NUM_ITER% |
![]() |
We should have no displacement: %IMG7%magick ^ %SRC% ^ pop_rmap1_rfms.png ^ -compose Displace -set option:compose:args 100%%x100%% -composite ^ pop_rm1.png |
![]() |
Displace a central block:
%IMG7%magick ^ %SRC% ^ -shave 1x1 ^ -alpha transparent ^ -bordercolor gray(50%%) -border 1 ^ -set page %%[fx:w*0.4]+%%[fx:h*0.4] ^ ( -clone 0 ^ -crop %%[fx:w*0.3]x%%[fx:h*0.2]+%%[fx:w*0.4]+%%[fx:h*0.4] ^ -alpha opaque ^ -fill gray(40%%) -colorize 100 ^ ) ^ -background None ^ -layers merge ^ pop_rmap2.png |
![]() |
call %PICTBAT%relaxFillMS ^ pop_rmap2.png . . %THRESH% %NUM_ITER% |
![]() |
%IMG7%magick ^ %SRC% ^ pop_rmap2_rfms.png ^ -compose Displace -set option:compose:args 100%%x100%% -composite ^ pop_rm2.png |
![]() |
Displace the four corners of a central block:
%IMG7%magick ^ %SRC% ^ -shave 1x1 ^ -alpha transparent ^ -bordercolor gray(50%%) -border 1 ^ -set page %%[fx:w*0.4]+%%[fx:h*0.4] ^ ( -clone 0 ^ -crop 1x1+%%[fx:w*0.4]+%%[fx:h*0.4] ^ -alpha opaque ^ -fill gray(40%%) -colorize 100 ^ ) ^ ( -clone 0 ^ -crop 1x1+%%[fx:w*0.7]+%%[fx:h*0.4] ^ -alpha opaque ^ -fill gray(40%%) -colorize 100 ^ ) ^ ( -clone 0 ^ -crop 1x1+%%[fx:w*0.4]+%%[fx:h*0.6] ^ -alpha opaque ^ -fill gray(40%%) -colorize 100 ^ ) ^ ( -clone 0 ^ -crop 1x1+%%[fx:w*0.7]+%%[fx:h*0.6] ^ -alpha opaque ^ -fill gray(40%%) -colorize 100 ^ ) ^ -background None ^ -layers merge ^ pop_rmap3.png |
![]() |
call %PICTBAT%relaxFillMS ^ pop_rmap3.png . . %THRESH% %NUM_ITER% |
![]() |
%IMG7%magick ^ %SRC% ^ pop_rmap3_rfms.png ^ -compose Displace -set option:compose:args 100%%x100%% -composite ^ pop_rm3.png |
![]() |
Again, this doesn't work well. Try larger rectangles.
set SW=10 set SH=10 %IMG7%magick ^ %SRC% ^ -shave 1x1 ^ -alpha transparent ^ -bordercolor gray(50%%) -border 1 ^ ( -clone 0 ^ -crop %SW%x%SH%+%%[fx:w*0.5]+%%[fx:h*0.5] ^ -alpha opaque ^ -fill gray(40%%) -colorize 100 ^ ) ^ ( -clone 0 ^ -crop %SW%x%SH%+%%[fx:w*0.8]+%%[fx:h*0.5] ^ -alpha opaque ^ -fill gray(40%%) -colorize 100 ^ ) ^ ( -clone 0 ^ -crop %SW%x%SH%+%%[fx:w*0.5]+%%[fx:h*0.7] ^ -alpha opaque ^ -fill gray(40%%) -colorize 100 ^ ) ^ ( -clone 0 ^ -crop %SW%x%SH%+%%[fx:w*0.8]+%%[fx:h*0.7] ^ -alpha opaque ^ -fill gray(40%%) -colorize 100 ^ ) ^ -background None ^ +write info: ^ -layers merge ^ pop_rmap4.png |
![]() |
set rfCOMP_METRIC=PAE set THRESH=1e-4 set NUM_ITER=1000 call %PICTBAT%relaxFillMS ^ pop_rmap4.png . . %THRESH% %NUM_ITER% |
![]() |
%IMG7%magick ^ %SRC% ^ pop_rmap4_rfms.png ^ -compose Displace -set option:compose:args 100%%x100%% -composite ^ pop_rm4.png |
![]() |
It would be cute to allow constrained movement. For example, we might allow pixels at the left and right sides to move vertically but not horizontally.
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)
To improve internet download speeds, some images may have been automatically converted (by ImageMagick, of course) from PNG or TIFF or MIFF to JPG.
Source file for this web page is pinorpush.h1. To re-create this web page, run "procH1 pinorpush".
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 18-November-2016.
Page created 22-Aug-2022 21:41:40.
Copyright © 2022 Alan Gibson.