|
Alpha Compositing - Part I |
How do you fit odd-shaped pictures into your thumbnail collection? You know, a portrait photo in an otherwise landscape collection. Or an image that doesn't have a rectangular boundary. One way to handle these kinds of images is to blend them with an image of the desired shape using RMagick's composite method.
In image processing, alpha compositing is the blending of two images into a single image by combining the pixel data from each image according to a mathematical formula. The traditional alpha compositing model is called the Porter-Duff model. The Porter-Duff model defines 12 different formulas for combining two images - a source image and a destination image - into one. This article explains how to use the Porter-Duff formula called src-over, one of the simplest and most common alpha composite operations. The formula for src-over is:
Replace the destination pixels with the source pixels.
If the source image has pixels that are partially or entirely transparent, the formula is slightly more complicated:
Replace the destination pixels with the source pixels, unless the source pixel is partially or entirely transparent, in which case let some or all of the destination pixel show through.
RMagick binds Ruby programs to either the ImageMagick or the GraphicsMagick library. Both libraries provide the same alpha compositing API. In RMagick, this API is the composite method in the Magick::Image class. The composite method needs four pieces of information from the program.
composite method is sent.
Over time composite has changed to make it more flexible concerning the position of the source image. Consequently, it can now be called with three different argument lists. The difference between the three lists is the specification of the position of the source image relative to the destination image.
First, you can specify the position as a pair of x- and y-offsets:
result = dst.composite(src, x, y, comp_op)
Here dst is the destination image and src is the source image. The second and third arguments, x and y, are the x- and y-offsets of the source image relative to the upper-left corner of the destination image. Either or both of these arguments can be negative numbers. A negative x-offset represents a position to the left of the left-hand side of the destination image. A negative y-offset represents a position above the top of the destination image. The final argument (comp_op) is the composite operator, a value in the Magick::CompositeOperator enumeration class.
Second, you can replace with x- and y-offsets with a single Magick::GravityType value.
result = dst.composite(src, gravity, comp_op)
As before, the first argument is the source image and the final argument is the composite operator.
There are 9 GravityType values:
The third way to call composite is with both a GravityType value and x- and y-offsets. In this case, the GravityType value modifies the meaning of the x and y arguments.
result = dst.composite(src, gravity, x, y, comp_op)
As before, the first argument is the source image and the last argument is the composite operator. The second argument is a GravityType value, and the third and fourth arguments are x- and y-offsets, respectively.
Again, the x- or y-offset can be negative, with predictable consequences.
As I explained earlier, the src-over composite operation produces a composite image by replacing the pixels in the destination image with the corresponding pixels in the source image. If the source is smaller than the destination, only those pixels in the area of the destination covered by the source are replaced. We can use this property to place a rectangular image onto a square background.
Here's an example. The image on the left is an 80x100 thumbnail, which we want to composite onto the center image, a 128x128 gold-colored background. The composite is on the right and is the same dimensions as the destination. The src-over operator places the source image over the destination image.
|
|
|
| source | destination | composite |
Here's a script that performs this composite operation:
1 require 'RMagick'
2
3 gold_fill = Magick::GradientFill.new(0, 0, 0, 0, "#f6e09a", "#cd9245")
4
5 dst = Magick::Image.new(128, 128, gold_fill)
6 src = Magick::Image.read("composite1-src.gif")[0]
7
8 result = dst.composite(src, Magick::CenterGravity, Magick::OverCompositeOp)
9 result.write('composite1.gif')
composite to the destination. This example uses the second form of the composite argument list. Magick::CenterGravity causes the source image to be centered over the destination. Magick::OverCompositeOp specifies the src-over operation
Here's an example of src-over with a partially transparent source image. Remember the definition of src-over:
Replace the destination pixels with the source pixels, unless the source pixel is partially or entirely transparent, in which case let some or all of the destination pixel show through.
The amount of the destination pixel that shows through depends on how opaque the source pixel is. As you saw in the previous example, a 100% opaque source pixel hides the destination pixel completely. A source pixel that is only 50% opaque would allow half the color in the destination pixel to show through, and so forth.
In the example below, the source image on the left is a PNG format image with transparent pixels around a cartoon penguin. The destination image is a 128x128 "plasma" image. The src-over operation produces the image on the right by replacing pixels in the destination with opaque pixels from the source. The transparent pixels in the source are also composited onto the destination, but since the source pixels outside the penguin are transparent (that is, 0% opaque) 100% of the destination pixel shows through.
|
|
|
| source | destination | composite |
Here's a script that performs this composite operation.
1 require 'RMagick'
2
3 dst = Magick::Image.read("plasma:fractal") {self.size = "128x128"}.first
4 src = Magick::Image.read('tux.png').first
5
6 result = dst.composite(src, Magick::CenterGravity, Magick::OverCompositeOp)
7 result.write('composite2.gif')
composite call.
When the source image is larger than the destination image, source pixels which have no corresponding destination pixels are ignored. Thus the resulting image is always the size of the destination image. The x, y, and gravity arguments control which part of the source contributes to the composite.
RMagick provides two other compositing methods. The Draw class's composite method has this argument list:
gc.composite(x, y, width, height, src_image, comp_op)
The destination image is the image drawn upon, that is, the argument to the draw method. The x and y arguments are offsets from the top and left-hand side of the destination image. The source image will be scaled to the values of width and height. (Set either or both of these arguments to 0 to prevent scaling.)
In RVG, the image method in the RVG, RVG::Group, and RVG::Pattern classes composites a raster image over the background image. This method does not accept a comp_op argument, though. Instead, it always uses src-over.
As always, Anthony Thyssen's excellent site has more information about alpha compositing with ImageMagick.This page is a good introduction to alpha compositing and the Porter-Duff model. The SVG 1.2 Specification has detailed information about alpha compositing, complete with all the mathematics you could ask for.
Tim - Feb 18, 2006