ZweiBieren
A logo or icon is an image, usually small, displayed to represent an object, operation, or concept. Pictools pages display a logo on the right side of the title line. Though mostly decorative, the logo is per-directory and distinguishes one directory from another.
Many logos are irregular, that is, non-rectangular. No common image format supports irregular images; they must be constructed by making transparent the unwanted portions of a rectangular image. For the web the right choice for small illustrations is the png format. For photos, jpg is fine, especially if that is what your camera delivers. If it delivers large raw format images, your web site will respond faster if you convert them to .jpg. The ImageMagick command to reformat a file from, say, jpg
to png
is
convert file.jpg file.png
Comments on popular image formats
Fmt |
sample file sizes |
image
quality |
supports
transparency |
Comments |
80x72 |
1157x1447 |
.png |
5316 |
1329918 |
excellent |
full or partial |
Designed for browser display. |
.jpg |
5087 |
726828 |
very good |
no |
Good compression but picture is blurred (imperceptibly). |
.gif |
2937 |
978947 |
speckled |
0/1 |
Speckled because the number of colors is limited. A pixel must be fully opaque or fully transparent. |
.tiff |
5110 |
5029395 |
excellent |
full or partial |
Suitable for printing; file size can be large. |
.bmp |
23178 |
5024122 |
excellent |
full or partial |
Saves every single byte; usually huge files. |
Clipping To an Irregular Image
Many tools are available for clipping an irregular shape from a rectangular one. Photoshop is great, but pricey. Clippingmagic.com does a great job of finding clip edges for free. They charge for downloading the result, though not for taking a screen dump. Others tools from a google search for "clipping image online" were too klutzy to mention. ImageMagick has some masking options that can help.
My poor-man's approach to making an irregular image relies on Window's paint
amd ImageMagick
. I start with an image in a window, be it a photoviewer, PowerPoint, paint, or some other. Typing ALT-PrtScrn copies the window to the cutbuffer. Then I open paint
and paste the image. With paint I resize the image as needed and color the unwanted parts with some color not found in the image. (identify -verbose
lists the colors that do appear in the image.) By flood-filling with various colors, I can spot the image pixels that shold not be part of the image. Editing the color gives me the exact color of the background as an rgb triple: rrr ggg bbb. After saving the image, I get a transparent background via ImageMagick:
mogrify -transparent 'rgb(rrr,ggg,bbb)' file.png
The paint/mogrify steps can be repeated to refine the image.
Halo Removal
Mouse me!
The
bear icon at left (originally from ablewebs.com) has a surrounding "halo" of white pixels. Roll your mouse over it and, tada, no halo. For several years I have held fast to the delusions that I could automate the process of removing a halo and understand ImageMagick
. I am now disillusioned on both counts. My various halo algorithms either failed to remove the halo or removed pieces of the image along with the halo.
ImageMagick
is indeed a useful and enormous of tools from many authors. And there's your problem: too many cooks. There is considerable diversity in defaults and code quality. If you have an image modification task, ImageMagick can do it; but be ready to invest some time figuring out how. Perhaps you will find useful my spreadsheet of ImageMagick option categories.
The simplest algorithm--appended below--is as good as, and faster than, my other attempts at an automated algorithm. It differs only in small ways from the mogrify -transparent
command noted above. The transparent color is taken to be the color of the upper left pixel, so it need not be provided. A "fuzz" is applied to that color so a small range of colors is eliminated altogether. And an option is provided to ensure that transparency is applied only to outside pixels, so pixels within the image are not affected. Repeated application of paint and this algorithm with different background colors and remove multiple colors from the halo, leaving fewer to be manually removed.
The convert command
The heart of the program is a lengthy convert
command. It extracts the background color, finds the pixels of that color in the image, and makes them transparent. Rather than operate on a single image, ImageMagick manipulate a sequence of images. The sequence can even be partitioned so the tail end is the current sequence while the rest awaits completion of that tail. Cleverly, the "(" operator starts a new partition and a ")" removes the most recent "(" appending the current sequence to the previous. The algorithm exploits this by creating each operand within a subsequence to build up a sequence of images to be com,bined in the final operation. Comments on each line show the contents of the sequence at that point. Here is what they mean:
orig |
Original image. The upper left pixel dictates the background color. |
( |
Sub-sequence separator. The current sequence is to the right. |
bkgd |
All pixels are the background color. |
diff |
Difference between orig and bkgd. |
mask |
Black for transparent and white for the image to retain. If -i is set, noislands deletes interior blobs from the mask. |
masked |
Result, but not yet trimmed. |
Guided by the contents of the sequence, you may (perhaps just barely) be able to follow the code in these steps:
find the background pixel and makes a image of just that color |
-sparse-color |
subtract the background from the image to get an image where pixels close to the background are zero |
-composite |
convert to zero those values that are close to zero |
-threshold |
optionally remove islands of transparent pixels from the central image |
${xaX:xx}... |
revise the original image to be transparent according to the mask |
-composite |
trim the image to remove transparent edge rows and colum,ns |
$trim |
write the file as a png |
$outfile |
The convert command
convert $infile \
# orig \
\( -clone 0 -sparse-color \
# orig ( orig \
voronoi '0,0 %[pixel:p{0,0}]' \) \
# orig bkgd \
\( -clone 0 -clone -1 \
# orig bkgd ( orig bkgd \
-compose Difference -composite \) -delete -2 \
# orig diff \
\( -clone -1 -threshold $fuzzpct% \) -delete -2 \
# orig mask \
${xiA:gx} ${xiB:q} ${xiC:gx} ${xiD:gx} ${xiE:gx} \
# orig mask \
-alpha Off -compose CopyOpacity -composite \
# masked \
$trim \
$outfile
exit 0
Managing the image sequence
After considerable tinkering with (, -clone, -swap, -delete, and ), I evolved a clear, simple strategy for managing the seqence of images. When I need a sequence of images derived from an original, I derive one at a time appending each to the sequence before going on. The result looks like the line
\( -clone -1 -threshold $fuzzpct% \) -delete -2
The initial ( starts a new sequence. The -clone fetches the operand from the pending sequence. The -threshold modifies the operand to produce the result of the subsequence. The ) removes the sequence separator inserted by (. finally, the -delete removes the no-longer-needed source for the operation. Such a sequence is used thrice; once each to generate bkgd, diff, and mask. It also appears in the island removal code.
Island removal
The script (below) affords the option -i, which ensures that there are no transparent pixels embedded in the image. This is not the default. It is not a good choice when the image has a hole like that at the right. But it is useful becuase some images have inside pixels that may be close to the background color. The script adds extra steps to the convert command by setting values for the xiX... shell variables. (It cannot be one variable in csh
due to quoting issues that are solved with :gx vs :q)
set xiA=" ( -clone -1 -channel RGB -bordercolor Black -compose src"
set xiB=" -border 1 -evaluate Multiply .5 -fill white -draw "
set xiC="color 0,0 floodfill"
set xiD=" -threshold 90% -negate -shave 1x1 ) "
set xiE=" -delete -2 "
This sequence is seriously convoluted, involving switching the mask between black-white and white-black. Understanding it is left as an exercise for the reader.
The complete script
#!/bin/csh
# Convert image so the background is transparent and without halo
#
# nohalo [-f fuzz-percent] [-i] [-t] file [outfile]
# Converts to , while making transparent all
# pixels close in color to the original upper left corner pixel.
# -f fuzz-percent -- Range of transparent colors.
# Pixels having colors within this percent of the
# transparency color are also deemed to be transparent.
set fuzzpct="5"
# -i -- no islands. The transparent region strictly surrounds the image.
# Pixels of the background color within the image are unaffected;
# there will be no "islands" of transparency.
set xiA=""
set xiB=""
set xiC=""
set xiD=""
# -t -- Omit the -trim step. Otherwise the default behavior is to
# trim the final image, removing all transparent border edges.
# Trimming will reduce the size of the image.
set trim="-trim"
# file -- the input file.
set infile=""
# outfile -- the output file. If omitted, use input file name,
# replacing its extension with "-nohalo.png"
set outfile=""
# It is an error to list more than two file names.
while ( $# != 0 )
switch ("$1")
case "-f":
set fuzzpct=$2
shift
breaksw
case "-i": # four variables because csh sucks
set xiA=" ( -clone -1 -channel RGB -bordercolor Black -compose src \
-border 1 -evaluate Multiply .5 -fill white -draw "
set xiB="color 0,0 floodfill"
set xiC=" -threshold 90% -negate -shave 1x1 ) "
set xiD=" -delete -2 "
breaksw
case "-t":
set trim=""
breaksw
case "-*":
echo unexpected "'$1'"
goto usage
default:
break
endsw
shift
end
# process input and output filenames
if ( $# == 0 ) then
echo no infile
goto usage
endif
set infile=$1
shift
if ( $# != 0 ) then
set outfile=$1
shift
else
# generate outfile name from infile
set outfile=${infile:r}-nohalo.png
endif
if ( $# != 0 ) then
echo unexpected "'$*'"
goto usage
endif
# make sure input file does not have transparency
if ( `identify -format '%A\n'` == "True" ) then
echo "\*\*\* Image $infile already has an alpha channel"
exit 3
endif
#################################
# The ImageMagick command follow. Comments on each line show
# the set of images constructed to that point. A left parens
# divides saved images from operands for the next operation.
# orig - the original image
# the upper left pixel dictates the background color
# bkgd -- all pixels are the background color
# diff -- difference between orig and bkgd
# mask -- a copy of image with black for transparent
# and white for the image to retain
# if -g is set, noislands deletes interior blobs from the mask,
# but does not otherwise alter the stack
# masked -- desired result, but not yet trimmed
convert $infile # orig \
\( -clone 0 -sparse-color # orig ( orig \
voronoi '0,0 %[pixel:p{0,0}]' \) # orig bkgd \
\( -clone 0 -clone -1 # orig bkgd ( orig bkgd \
-compose Difference -composite \) -delete -2 # orig diff \
\( -clone -1 -threshold $fuzzpct% \) -delete -2 # orig mask \
${xiA:gx} ${xiB:q} ${xiC:gx} ${xiD:gx} # orig mask \
-alpha Off -compose CopyOpacity -composite # masked \
$trim \
$outfile
exit 0
usage:
echo "*** usage: csh nohalo.csh [-i] [-f fuzz-precent] [-t] file [outfile]"
echo "*** -i removes islands -t skips trimming the result"
exit 99