Blame editor/ppmshadow.doc

Packit 78deda
This file is a concatenation of two HTML files that John Walker wrote for the
Packit 78deda
original 'pnmshadow' program.  It is not all relevant to the current
Packit 78deda
'ppmshadow' program.
Packit 78deda
Packit 78deda
<html>
Packit 78deda
<head>
Packit 78deda
<title>pnmshadow: How it Works</title>
Packit 78deda
Packit 78deda
</head>
Packit 78deda
Packit 78deda
<body>
Packit 78deda
Packit 78deda
<center>
Packit 78deda

pnmshadow: How it Works

Packit 78deda
</center>
Packit 78deda
Packit 78deda

Packit 78deda

Packit 78deda
Packit 78deda
This document describes the process, including PBMplus commands
Packit 78deda
and the intermediate images they create, by
Packit 78deda
which pnmshadow
Packit 78deda
adds black shadows to source images.
Packit 78deda
A companion document
Packit 78deda
describes how translucent shadows are created when the
Packit 78deda
-t option is specified.
Packit 78deda
Packit 78deda

The Starting Point

Packit 78deda
Packit 78deda
Let's start with the following source image, 536 pixels wide and 141
Packit 78deda
pixels high.  We convert the image from whatever form in which
Packit 78deda
it was originally created (GIF, JPEG, etc.) to a PPM file before
Packit 78deda
processing it with pnmshadow.
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Input image
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

The Blank Background

Packit 78deda
Packit 78deda
We start by determining the size of the input image with
Packit 78deda
pnmfile and then constructing an image with the same
Packit 78deda
size as the input image consisting entirely of the background
Packit 78deda
color, which is defined as the color of the pixel at the upper
Packit 78deda
left corner of the source image.  This is performed by the
Packit 78deda
command:
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmcut 0 0 1 1 ifile | pnmscale -xsize xsize -ysize ysize >fname-5.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
yielding the image:
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Blank background image
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

The Positive Mask

Packit 78deda
Packit 78deda
A positive mask image is created in which all pixels of the background
Packit 78deda
color are set to white and all other pixels are black.  This is accomplished
Packit 78deda
by subtracting the blank background image from the input (using the
Packit 78deda
<tt>-difference</tt> option on pnmarith to avoid clipping at
Packit 78deda
zero or the maximum pixel value), then inverting the result and
Packit 78deda
thresholding it to a monochrome bitmap.
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmarith -difference ifile fname-5.ppm | pnminvert | ppmtopgm | pgmtopbm -thresh -value 1.0 >fname-1.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
This produces the following mask image.
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Positive mask image
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

The Blurred Image

Packit 78deda
Packit 78deda
Since we wish to simulate a shadow from a nearby extended
Packit 78deda
light source rather than a sharp shadow as cast by the
Packit 78deda
Sun, we need to prepare a blurred version of the original
Packit 78deda
image.  If the -t option is not specified on
Packit 78deda
pnmshadow the shadow cast by an object of any color
Packit 78deda
is always black, so the positive mask serves as the source image
Packit 78deda
when preparing the shadow.  A convolution kernel which averages
Packit 78deda
the number of pixels specified by the -b option
Packit 78deda
(default 11), written into the temporary file <tt>fname-2.ppm</tt>
Packit 78deda
in ASCII PGM format, and then the blurred image is created with
Packit 78deda
the command:
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmconvol fname-2.ppm fname-1.ppm >fname-3.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
With the default blur setting of 11 pixels, the blurred image
Packit 78deda
below is generated.
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Blurred shadow
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

Shadow on Background Color

Packit 78deda
Packit 78deda
Having generated the blurred shadow from the monochrome mask image,
Packit 78deda
it will consist of pixels ranging from white to black on a white
Packit 78deda
background.  In order to preserve the background color in the
Packit 78deda
original image, we multiply the shadow by the blank background color
Packit 78deda
image created previously.  White pixels take on the background color
Packit 78deda
and pixels belonging to the shadow are scaled to be relative to the
Packit 78deda
background.
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmarith -multiply fname-3.ppm fname-5.ppm >fname-10.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
This yields the following shadow, with the background of the
Packit 78deda
original image.
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Shadow with background color
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

Offset Shadow Clip

Packit 78deda
Packit 78deda
Shadows, even bogus ones like we're generating, usually look best when
Packit 78deda
cast by a light source diagonally displaced from the centre of the
Packit 78deda
shadow-casting object.  To achieve this effect, we first cut a
Packit 78deda
rectangle from the blurred shadow image reduced in size by the
Packit 78deda
the number of pixels specified by the -b option
Packit 78deda
which default to half the blur (-b) setting.  The
Packit 78deda
xsize and ysize arguments in the following
Packit 78deda
command are the size of the input image in pixels less the shadow
Packit 78deda
displacement in the respective axis.
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmcut 0 0 xsize ysize fname-10.ppm >fname-4.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
The shadow clip is the identical to the shadow on background color, but
Packit 78deda
smaller by the offset in each direction.
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Offset shadow clip
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

Offset Shadow

Packit 78deda
Packit 78deda
Now we're ready to assemble the shadow offset by the specified number
Packit 78deda
of pixels.  We do this by pasting the image cut in the previous step
Packit 78deda
into the blank background, yielding an image the same size as the
Packit 78deda
source image with the blurred shadow displaced to the right and
Packit 78deda
down.
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmpaste -replace fname-4.ppm xoffset yoffset fname-5.ppm >fname-6.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
This gives the following result:
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Offset shadow
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

Inverse Mask

Packit 78deda
Packit 78deda
In order to stitch everything together, we need an inverse of the
Packit 78deda
mask prepared earlier--one where black pixels represent the background
Packit 78deda
and all other material is white.  This is easily accomplished by
Packit 78deda
running the positive mask through pnminvert:
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnminvert fname-1.ppm >fname-7.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
yielding:
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Inverse mask
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

Masked Input Image

Packit 78deda
Packit 78deda
Now we use the inverse mask prepared in the previous step to create
Packit 78deda
an image containing all non-background pixels from the source image,
Packit 78deda
with background pixels set to black.  We simply multiply the
Packit 78deda
inverse mask by the source image:
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmarith -multiply ifile fname-7.ppm >fname-8.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
et voilĂ :
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Masked Input Image
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

Shadow with Source Masked

Packit 78deda
Packit 78deda
Our last intermediate step before joining the image with its
Packit 78deda
shadow is preparing a shadow image with all non-background pixels
Packit 78deda
in the source image set to black.  This ensures that when we add
Packit 78deda
the image and the shadow, the shadow will not override any pixel
Packit 78deda
in the source image.
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmarith -multiply fname-6.ppm fname-1.ppm >fname-9.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
This is accomplished by multiplying the shadow by the positive
Packit 78deda
mask image, which sets all non-background pixels in the source
Packit 78deda
image to black:
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Shadow with Source Masked
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

The Final Product

Packit 78deda
Packit 78deda
At long last, we're ready to put together the pieces and deliver
Packit 78deda
the result to our ever-patient user.  This amounts simply to 
Packit 78deda
adding the masked input image (consisting solely of non-background
Packit 78deda
pixels from the original image) to the shadow with source masked
Packit 78deda
(in which all source pixels are black):
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmarith -add fname-8.ppm fname-9.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
The resulting image, with shadow, is as follows:
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Output: Image with shadow
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

Smooth Operator

Packit 78deda
Packit 78deda
Since many computer graphics programs create sharp edges on
Packit 78deda
text, it's often best to create an image at a greater resolution
Packit 78deda
than that used for presentation, then scale it to the final
Packit 78deda
resolution with a tool which resamples the image, thus
Packit 78deda
minimising jagged edges by averaging adjacent
Packit 78deda
pixels.  Using the output of pnmshadow as the starting
Packit 78deda
point and scaling to half size with pnmscale, we arrive at
Packit 78deda
the following smoothed image, with shadow, ready to adorn a
Packit 78deda
Web page:
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Half scale image with shadow
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

How it works with translucent shadows

Packit 78deda

pnmshadow main page

Packit 78deda
Packit 78deda

Packit 78deda

Packit 78deda

Packit 78deda
<address>
Packit 78deda
by John Walker
Packit 78deda
August 8th, 1997
Packit 78deda
</address>
Packit 78deda
Packit 78deda
</body>
Packit 78deda
</html>
Packit 78deda
<html>
Packit 78deda
<head>
Packit 78deda
<title>pnmshadow: How it Works in Translucent Mode</title>
Packit 78deda
Packit 78deda
</head>
Packit 78deda
Packit 78deda
<body>
Packit 78deda
Packit 78deda
<center>
Packit 78deda

pnmshadow: How it Works in Translucent Mode

Packit 78deda
</center>
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
This document describes the process, including PBMplus commands
Packit 78deda
and the intermediate images they create, by
Packit 78deda
which pnmshadow
Packit 78deda
adds translucent shadows when the -t command line
Packit 78deda
option is specified.  A companion document
Packit 78deda
describes how the default black shadows are generated.
Packit 78deda
Packit 78deda

The Starting Point

Packit 78deda
Packit 78deda
Let's start with the following source image, 536 pixels wide and 141
Packit 78deda
pixels high.  We convert the image from whatever form in which
Packit 78deda
it was originally created (GIF, JPEG, etc.) to a PPM file before
Packit 78deda
processing it with pnmshadow.
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Input image
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

The Blank Background

Packit 78deda
Packit 78deda
We start by determining the size of the input image with
Packit 78deda
pnmfile and then constructing an image with the same
Packit 78deda
size as the input image consisting entirely of the background
Packit 78deda
color, which is defined as the color of the pixel at the upper
Packit 78deda
left corner of the source image.  This is performed by the
Packit 78deda
command:
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmcut 0 0 1 1 ifile | pnmscale -xsize xsize -ysize ysize >fname-5.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
yielding the image:
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Blank background image
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

The Positive Mask

Packit 78deda
Packit 78deda
A positive mask image is created in which all pixels of the background
Packit 78deda
color are set to white and all other pixels are black.  This is accomplished
Packit 78deda
by subtracting the blank background image from the input (using the
Packit 78deda
<tt>-difference</tt> option on pnmarith to avoid clipping at
Packit 78deda
zero or the maximum pixel value), then inverting the result and
Packit 78deda
thresholding it to a monochrome bitmap.
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmarith -difference ifile fname-5.ppm | pnminvert | ppmtopgm | pgmtopbm -thresh -value 1.0 >fname-1.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
This produces the following mask image.
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Positive mask image
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

The Blurred Image

Packit 78deda
Packit 78deda
Since we wish to simulate a shadow from a nearby extended
Packit 78deda
light source rather than a sharp shadow as cast by the
Packit 78deda
Sun, we need to prepare a blurred version of the original
Packit 78deda
image.
Packit 78deda
A convolution kernel which averages
Packit 78deda
the number of pixels specified by the -b option
Packit 78deda
(default 11), written into the temporary file <tt>fname-2.ppm</tt>
Packit 78deda
in ASCII PGM format, and then the blurred image is created with
Packit 78deda
the command:
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmconvol fname-2.ppm ifile >fname-10.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
With the default blur setting of 11 pixels, the blurred image
Packit 78deda
below is generated.
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Blurred shadow
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

Offset Shadow Clip

Packit 78deda
Packit 78deda
Shadows, even bogus ones like we're generating, usually look best when
Packit 78deda
cast by a light source diagonally displaced from the centre of the
Packit 78deda
shadow-casting object.  To achieve this effect, we first cut a
Packit 78deda
rectangle from the blurred shadow image reduced in size by the
Packit 78deda
the number of pixels specified by the -b option
Packit 78deda
which default to half the blur (-b) setting.  The
Packit 78deda
xsize and ysize arguments in the following
Packit 78deda
command are the size of the input image in pixels less the shadow
Packit 78deda
displacement in the respective axis.
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmcut 0 0 xsize ysize fname-10.ppm >fname-4.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
The shadow clip is the identical to the shadow on background color, but
Packit 78deda
smaller by the offset in each direction.
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Offset shadow clip
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

Offset Shadow

Packit 78deda
Packit 78deda
Now we're ready to assemble the shadow offset by the specified number
Packit 78deda
of pixels.  We do this by pasting the image cut in the previous step
Packit 78deda
into the blank background, yielding an image the same size as the
Packit 78deda
source image with the blurred shadow displaced to the right and
Packit 78deda
down.
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmpaste -replace fname-4.ppm xoffset yoffset fname-5.ppm >fname-6.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
This gives the following result:
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Offset shadow
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

Inverse Mask

Packit 78deda
Packit 78deda
In order to stitch everything together, we need an inverse of the
Packit 78deda
mask prepared earlier--one where black pixels represent the background
Packit 78deda
and all other material is white.  This is easily accomplished by
Packit 78deda
running the positive mask through pnminvert:
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnminvert fname-1.ppm >fname-7.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
yielding:
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Inverse mask
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

Masked Input Image

Packit 78deda
Packit 78deda
Now we use the inverse mask prepared in the previous step to create
Packit 78deda
an image containing all non-background pixels from the source image,
Packit 78deda
with background pixels set to black.  We simply multiply the
Packit 78deda
inverse mask by the source image:
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmarith -multiply ifile fname-7.ppm >fname-8.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
et voilĂ :
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Masked Input Image
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

Shadow with Source Masked

Packit 78deda
Packit 78deda
Our last intermediate step before joining the image with its
Packit 78deda
shadow is preparing a shadow image with all non-background pixels
Packit 78deda
in the source image set to black.  This ensures that when we add
Packit 78deda
the image and the shadow, the shadow will not override any pixel
Packit 78deda
in the source image.
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmarith -multiply fname-6.ppm fname-1.ppm >fname-9.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
This is accomplished by multiplying the shadow by the positive
Packit 78deda
mask image, which sets all non-background pixels in the source
Packit 78deda
image to black:
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Shadow with Source Masked
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

The Final Product

Packit 78deda
Packit 78deda
At long last, we're ready to put together the pieces and deliver
Packit 78deda
the image to our ever-patient user.  This amounts simply to 
Packit 78deda
adding the masked input image (consisting solely of non-background
Packit 78deda
pixels from the original image) to the shadow with source masked
Packit 78deda
(in which all source pixels are black):
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
    pnmarith -add fname-8.ppm fname-9.ppm
Packit 78deda
Packit 78deda

Packit 78deda
Packit 78deda
The resulting image, with shadow, is as follows:
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Output: Image with translucent shadow
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

Smooth Operator

Packit 78deda
Packit 78deda
Since many computer graphics programs create sharp edges on
Packit 78deda
text, it's often best to create an image at a greater resolution
Packit 78deda
than that used for presentation, then scale it to the final
Packit 78deda
resolution with a tool which resamples the image, thus
Packit 78deda
minimising jagged edges by averaging adjacent
Packit 78deda
pixels.  Using the output of pnmshadow as the starting
Packit 78deda
point and scaling to half size with pnmscale, we arrive at
Packit 78deda
the following smoothed image, with shadow, ready to adorn a
Packit 78deda
Web page:
Packit 78deda
Packit 78deda

Packit 78deda
<center>
Packit 78deda
Packit 78deda
Packit 78deda
Half scale image with translucent shadow
Packit 78deda
Packit 78deda
</center>
Packit 78deda
Packit 78deda

How it works with black shadows

Packit 78deda

pnmshadow main page

Packit 78deda
Packit 78deda

Packit 78deda

Packit 78deda

Packit 78deda
<address>
Packit 78deda
by John Walker
Packit 78deda
August 8th, 1997
Packit 78deda
</address>
Packit 78deda
Packit 78deda
</body>
Packit 78deda
</html>