|Web 2.0 Graphics|
|Alpha Compositing - Part 2|
Before adding the starburst you need to add a bit of shadow underneath the background and enlarge the image enough to contain the starburst. Adding a shadow is easy. Simply create a gray rectangle slightly larger than the background and blur it a bit. When you composite the background over the blurry rectangle it will make the background look like it's casting a shadow.
After blurring, the rectangle will be a bit larger so create
an image that is 10 pixels larger on each side. Draw the gray
rectangle and then use
blur_image to blur it.
shadow = Image.new(background.columns+10, background.rows+10) gc = Draw.new gc.fill "gray30" gc.rectangle 5, 5, background.columns+5, background.rows+5 gc.draw(shadow) shadow = shadow.blur_image(0, 2)
Here's what the shadow looks like:
Composite the background over the shadow.
shadowed_background = shadow.composite(background, CenterGravity, OverCompositeOp)
Here's what the background looks like after adding the shadow.
Now you need to put everything on a larger canvas so you can add the starburst. Create a large white image and composite the background over it. The NorthGravity argument puts the background at the top. The result becomes the new background.
big_canvas = Image.new(shadowed_background.columns, HEIGHT*5) big_background = big_canvas.composite(shadowed_background, NorthGravity, OverCompositeOp)
The image below has a gray border so you can see the dimensions of the new background.
Creating the finished starburst uses the same techniques I've already covered: alpha compositing, opacity masks, and annotation. Before starting, examine the starburst closely so that you'll understand what the next few steps are for. Now is probably a good time to go back and review the image you're working toward. The starburst has 25 points and is filled with a yellow-green gradient. The words "Ruby + Magick" appear in yellow within the starburst. The starburst has a very subtle shadow underneath. The starburst and its shadow are rotated 20° counter-clockwise.
Start by drawing a black version of the starburst on a white background. Rotate the starburst -20°. We'll use this image as a starting point for 2 different images.
black_star = Image.new(170,170) black_star.star(25, 60, 80, 'none', 'black') black_star.rotate!(-20)
(Don't go looking for the
method in the Image class because you won't find it. I've
added it especially for this tutorial. The algorithm is not
relevant to this tutorial so I'm not going to discuss it here.
If you want to see the code, go on to page 4.)
Make a copy of the black starburst and blur it to form the shadow.
star_shadow = black_star.copy.blur_image(3, 2)
Now you need to make the area outside of the shadow's perimeter transparent while leaving the inside opaque. Obviously this is a job for the copy-opacity composition operator, but what should you use for the opacity mask? The perimeter is blurry, so the blur pixels must be partially transparent. The solution is actually quite easy: use the inverse of the shadow itself:
shadow_mask = star_shadow.negate
Remember, the black pixels in the mask indicate transparent pixels in the destination image. The white pixels in the mask indicate opaque pixels. Use the mask to add transparency to the shadow:
shadow_mask.matte = false star_shadow.matte = true star_shadow.composite!(shadow_mask, CenterGravity, CopyOpacityCompositeOp)
Here's a piece of the shadow after compositing. This piece has been scaled up 400% and composited on a pale blue background. You can easily see where it's fully transparent, partially transparent, and fully opaque:
Set the shadow aside for a moment and make the green
starburst itself. Start by making an image with a green
gradient background. Add the "Ruby + Magick" text with
annotate. Finally, rotate the background -20°
to match the shadow.
grad = GradientFill.new(0, 0, black_star.columns, 0, "#99eb24", "#3c7f05}") green_grad = Image.new(black_star.columns, black_star.rows, grad) gc = Draw.new gc.annotate(green_grad, 0, 0, 0, 0, "Ruby\n+\nMagick!") do gc.gravity = CenterGravity gc.stroke = 'none' gc.fill = 'yellow' gc.pointsize = 24 gc.font_weight = BoldWeight end green_grad.rotate!(-20)
Use the black star image to make another opacity mask. Negate it so that the outside of the star is black and the inside is white.
inverse_black_star = black_star.negate
Use the mask as the source image in a copy-opacity composite operation. This makes the center of the green gradient opaque in the shape of the starburst and transparent outside of the starburst.
inverse_black_star.matte = false green_grad.matte = true green_star = green_grad.composite(inverse_black_star, CenterGravity, CopyOpacityCompositeOp)
Composite the green starburst over its shadow.1
shadowed_green_star = star_shadow.composite(green_star, CenterGravity, OverCompositeOp)
Here's what the green starburst looks like before and after adding the shadow. The pale blue background indicates the transparent portions.
|Without shadow||With shadow|
At this point you may be asking yourself "Why did I rotate
the images before adding transparency?" The answer is that
rotate produces a completely opaque image, so if
you were to add the transparency and then rotate, the rotated
image loses all your carefully-added transparency.
Finally, pick a spot on the background image (I chose x=400, y=0) and composite the starburst on the background.
result = big_background.composite(shadowed_green_star, 400, 0, OverCompositeOp)
This tutorial showed you how to produce some nice-looking
effects with just a handful of RMagick methods. The most useful
technique is the copy-opacity composite operation for making
parts of an image transparent. The
is an easy and versatile method for adding text. We covered
blur_image for shadows and
negate for masks.
append are also handy tools in your RMagick
The entire program for this tutorial is here. If you want to see just the code for
Image#star, go on to the next page.
Rempe pointed out that this call to
tickles a bug that is present in versions of RMagick prior to
1.10.1, including RMagick 1.9.2 on Windows. If you're using one
of these versions of RMagick, add the following statement:
# Add this line if you're using RMagick < 1.10.1 green_star.crop!(CenterGravity, star_shadow.columns, star_shadow.rows) shadowed_green_star = star_shadow.composite(green_star, CenterGravity, OverCompositeOp)
Tim - June 18, 2006