|Web 2.0 Graphics|
|Alpha Compositing - Part 2|
Adding text to an image is called annotation and is
handled by the aptly-named
annotate method in the
Draw class. To add "RMAGICK", create an instance of Draw, set a
few style attributes, and then call
gc = Draw.new gc.fill = 'white' gc.stroke = 'none' gc.pointsize = 42 gc.annotate(background, 0, 0, 70, HEIGHT, "RMAGICK")
annotate arguments are easy. The first two
numbers describe the x- and y-axis rotation of the text. Here
I've set these to 0. The 3rd and 4th arguments are the x- and
y-offsets of the text. In this case, draw the text starting 70
pixels from the left and with the baseline exactly in the
middle of the background. The code above produces this
(You may want to use the
font= attribute to
specify a font other that the default. Here I've let it default
so the typeface is rather ordinary looking.)
Drawing the "reflection" of RMAGICK is not as easy. To make it look like a reflection you must add some transparency. Look carefully at the finished image. Notice that the reflection is mostly transparent, but it's slightly less transparent at the top and gradually becomes more transparent toward the bottom? To get this effect you'll create an image that describes the desired transparency levels as levels of gray and then use that image to set the transparency in the reflected RMAGICK.
Transparency information about an image is described in the alpha channel. Like the red, green, and blue channels, the alpha channel contains a number between 0 and MaxRGB, where MaxRGB is 100% transparency (or 0% opacity) and 0 is 0% transparency (or 100% opacity). The copy-opacity composition operation copies the transparency data from the source image to the destination image. Copy-opacity has two modes of operation:
I = 0.299*R + 0.587*G + 0.114*B. Copy-opacity sets the alpha channel of the destination image to
MaxRGB - I. That is, more intensity == more opacity.
You're going to take advantage of the 2nd mode to create a transparency mask for the reflection. Notice from the intensity formula that for gray images (where R=G=B) the intensity of a pixel corresponds to its blackness. An entirely black pixel (#000000) has intensity 0 and therefore represents 100% transparency. Pixels that are less than entirely black are less than 100% transparent, and pixels that are entirely white (#ffffff) are 0% transparent.
Begin by creating a copy of the bottom (dark-blue) stripe
and adding the RMAGICK annotation. The reflection will end up
upside-down, so use
flip to turn the stripe
upside-down now so that it will be right-side up when you're
reflection = stripes.flip reflection.composite!(color, CenterGravity, ColorizeCompositeOp) gc.annotate(reflection, 0, 0, 70, HEIGHT, "RMAGICK")
The next 2 statements create a gradient image that ranges from entirely black to dark gray. The blackest pixels are at the top. The lightest pixels are at the bottom.
grad = GradientFill.new(0, 0, WIDTH, 0, "black", "gray35") opacity_mask = Image.new(WIDTH, HEIGHT, grad)
The last trick you need to know is that RMagick ignores the
alpha channel if the image's
matte attribute is
false, and respects it if
matte is true. The next
reflection.matte = true opacity_mask.matte = false reflection.composite!(opacity_mask, CenterGravity, CopyOpacityCompositeOp)
Now flip the resulting image and composite it over the bottom stripe in the background:
reflection.flip! background.composite!(reflection, SouthWestGravity, OverCompositeOp)
Notice that the reflection effect wouldn't work if we used a font with descenders (descenders are parts of letters that drop below the baseline, like the hook in the letter "g".) because the descenders would cross the centerline. Mr. Maloney cleverly bypasses that problem with a font that uses small caps for lowercase letters. I cleverly bypassed it by using all caps.
Next, add the starburst.