Fred's ImageMagick Scripts


    Copyright © Fred Weinhaus

    My scripts are available free of charge for non-commercial (non-profit) use, ONLY.

    For use of my scripts in commercial (for-profit) environments or non-free applications, please contact me (Fred Weinhaus) for licensing arrangements. My email address is fmw at alink dot net.

    If you: 1) redistribute, 2) incorporate any of these scripts into other free applications or 3) reprogram them in another scripting language, then you must contact me for permission, especially if the result might be used in a commercial or for-profit environment.

    Usage, whether stated or not in the script, is restricted to the above licensing arrangements. It is also subject, in a subordinate manner, to the ImageMagick license, which can be found at:

    Please read the Pointers For Use on my home page to properly install and customize my scripts.


Applies a stained glass cell effect to an image.

Download Script

last modified: December 15, 2018

USAGE: stainedglass [-k kind] [-s size] [-o offset] [-n ncolors] [-b bright] [-e ecolor] [-t thick] [-r rseed] [-a] infile outfile
USAGE: stainedglass [-h or -help]

-k .... kind ....... kind of stainedglass cell shape; choices are: square
.................... (or s), hexagon (or h), random (or r); default=random
-s .... size ....... size of cell; integer>0; default=16
-o .... offset ..... random offset amount; integer>=0; default=6;
.................... only applies to kind=random
-n .... ncolors .... number of desired reduced colors for the output;
.................... integer>0; default is no color reduction
-b .... bright ..... brightness value in percent for output image;
.................... integer>=0; default=100
-e .... ecolor ..... color for edge or border around each cell; any valid
.................... IM color; default=black
-t .... thick ...... thickness for edge or border around each cell;
.................... integer>=0; default=1; zero means no edge or border
-r .... rseed ...... random number seed value; integer>=0; if seed provided,
.................... then image will reproduce; default is no seed, so that
.................... each image will be randomly different; only applies
.................... to kind=random
-a ................. use average color of cell rather than color at center
.................... of cell; default is center color

PURPOSE: Applies a stained glass cell effect to an image.

DESCRIPTION: STAINEDGLASS applies a stained glass cell effect to an image. The choices of cell shapes are hexagon, square and randomized square. The cell size and border around the cell can be specified.


-k kind ... KIND of stainedglass cell shape; choices are: square (or s), hexagon (or h), random (or r). The latter is a square with each corner randomly offset. The default=random.

-s size ... SIZE of stained glass cells. Values are integers>=0. The default=16.

-o offset ... OFFSET is the random offset amount for the case of kind=random. Values are integers>=0. The default=6.

-n ncolors ... NCOLORS is the number of desired reduced colors in the output. Values are integers>0. The default is no color reduction. Larger number of colors takes more time to color reduce.

-b bright ... BRIGHTNESS value in percent for the output image. Values are integers>=0. The default=100 means no change in brightness.

-e ecolor ... ECOLOR is the color for the edge or border around each cell. Any valid IM color is allowed. The default=black.

-t thick ... THICK is the thickness for the edge or border around each cell. Values are integers>=0. The default=1. A value of zero means no edge or border will be included.

-r rseed ... RSEED is the random number seed value for kind=random. Values are integers>=0. If a seed is provided, then the resulting image will be reproducable. The default is no seed. In that case, each resulting image will be randomly different.

-a ... use AVERAGE color of cell rather than color at center of cell; default is center color. The average value will be accurate only for odd square shapes with IM or higher. All others cases will use only an approximate average.

Thanks to Anthony Thyssen for critiqing the original version and for several useful suggestions for improvement.

REQUIREMENTS: Does not produce a proper set of edges/borders around each cell under Q8, due to insufficient graylevel resolution (0 and 255) to handle more that 255 cells.

NOTE: This script will be slow prior to IM due to the need to extract color values for each cell center point across the input image. A progress meter is therefore provided to the terminal. A speed-up is available via a -process function, getColors. To obtain getColors, contact me. It requires IM 6.6.2-10 or higher.

IMPORTANT: This script will fail due to an unintended restriction in the txt: format starting with IM and IM It has been fixed at IM and IM

CAVEAT: No guarantee that this script will work on all platforms, nor that trapping of inconsistent parameters is complete and foolproof. Use At Your Own Risk.


Original Image


-k random -b 150 -t 1 -r 56


-k hexagon -b 150 -t 1


-k square -b 150 -t 1


-k random -b 150 -t 0 -r 56


-k hexagon -b 150 -t 0


-k square -b 150 -t 0

What the script does is as follows:

  • Generates a file of x,y values for the specified cell kind
  • Converts the list of coordinates into a txt image file
    with all other pixels set to transpaent
  • Extracts all the opaque pixel's coordinates with color values
    and uses those with -sparse-color voronoi to generate the result

This is equivalent to the following IM commands for kind=hexagon when no border is used.

  • ww=`convert $infile -ping -format "%w" info:`
  • hh=`convert $infile -ping -format "%h" info:`
  • ww1=$(($ww-1))
  • hh1=$(($hh-1))
  • ww2=`convert xc: -format "%[fx:$ww1+round($size/2)]" info:`
  • hh2=`convert xc: -format "%[fx:$hh1+round($size/2)]" info:`
  • echo "# ImageMagick pixel enumeration: $ww,$hh,255,rgb" > $tmpC
  • awk -v size="$size" -v ww1="$ww1" -v hh1="$hh1" -v ww2="$ww2" -v hh2="$hh2" '
    BEGIN { j=0; y=0; while ( y < hh2 )
    { if (j%2==0) {x=int((size+0.5)/2);} else {x=0;} while (x < ww2 )
    { if (x>ww1) {x=ww1;} if (y>hh1) {y=hh1;} print x","y": (255,255,255)"; x=x+size; }
    j++; y=y+size; } }' >> $tmpC
  • convert $infile \( -background black $tmpC \) \
    -alpha off -compose copy_opacity -composite -monitor \
    txt:- |\
    sed '1d; / 0) /d; s/:.* /,/;' |\
    convert -size ${ww}x${hh} xc: -sparse-color voronoi '@-' \
    -modulate ${bright},100,100 \