Masking techniques can produce many interesting effects by controlling which parts of an image are painted. You can:
Apply an image mask to an image. You can also use an image as a mask to achieve an effect that’s opposite from applying an image mask.
Use color to mask parts of an image, which includes the technique referred to as chroma-key masking.
Clip a graphics context to an image or image mask, which effectively masks an image (or any kind of drawing) when Quartz draws the content to the clipped context.
As you’ll see in the sections that follow, each approach gives a different effect.
Masking an Image With an Image Mask
Masking an Image With an Image
Masking an Image With Color
Masking an Image by Clipping the Context
The function CGImageCreateWithMask returns the image that’s created by applying an image mask to an image. This function, available in Mac OS X v10.4 and later, takes two parameters:
The image you want to apply the mask to. This image can’t be an image mask or have a masking color (see “Masking an Image With Color”) associated with it.
An image mask created by calling the function CGImageMaskCreate. It’s possible to provide an image instead of an image mask, but that gives a much different result. See “Masking an Image With an Image.”
Source samples of an image mask act as an inverse alpha value. An image mask sample value (S):
Equal to 1 blocks painting the corresponding image sample.
Equal to 0 allows painting the corresponding image sample at full coverage.
Greater than 0 and less 1 allows painting the corresponding image sample at with an alpha value of (1 – S).
Figure 11-5 shows an image created with one of the Quartz image-creation functions while Figure 11-6 shows an image mask created with the function CGImageMaskCreate. Figure 11-7 shows the image that results from calling the function CGImageCreateWithMask to apply the image mask to the image.
Note that the areas in the original image that correspond to the black areas of the mask show through in the resulting image (Figure 11-7). The areas that correspond to the white areas of the mask aren’t painted. The areas that correspond to the gray areas in the mask are painted using an intermediate alpha value that’s equal to 1 minus the image mask sample value.
You can use function CGImageCreateWithMask to mask an image with another image, rather than with an image mask. You would do this to achieve an effect opposite of what you get when you mask an image with an image mask. Instead of passing an image mask that’s created using the function CGImageMaskCreate, you supply an image created from one of the Quartz image-creation functions.
Source samples of an image that is used as a mask (but is not a Quartz image mask) operate as alpha values. An image sample value (S):
Equal to 1 allows painting the corresponding image sample at full coverage.
Equal to 0 blocks painting the corresponding image sample.
Greater than 0 and less 1 allows painting the corresponding image sample with an alpha value of S.
Figure 11-8 shows the image that results from calling the function CGImageCreateWithMask to apply the image shown in Figure 11-6 to the image shown in Figure 11-5. In this case, assume that the image shown in Figure 11-6 is created using one of the Quartz image-creation functions, such as CGImageCreate. Compare Figure 11-8 with Figure 11-7 to see how the same sample values, when used as image samples instead of image mask samples, achieve the opposite effect.
The areas in the original image that correspond to the black areas of the image aren’t painted in the resulting image (Figure 11-8). The areas that correspond to the white areas of are painted. The areas that correspond to the gray areas in the mask are painted using an intermediate alpha value that’s equal to the masking image sample value.
The function CGImageCreateWithMaskingColors creates an image by masking one color or a range of colors in an image supplied to the function. Using this function, you can perform chroma key masking similar to what’s shown in Figure 11-9 or you can mask a range of colors, similar to what’s shown in Figure 11-11, Figure 11-12, and Figure 11-13.
The function CGImageCreateWithMaskingColors takes two parameters:
An image that is not an image mask and that is not the result of applying an image mask or masking color to another image.
An array of color components that specify a color or a range of colors for the function to mask in the image.
The number of elements in the color component array must be equal to twice the number of color components in the color space of the image. For each color component in the color space, supply a minimum value and a maximum value that specifies the range of colors to mask. To mask only one color, set the minimum value equal to the maximum value. The values in the color component array are supplied in the following order:
{min[1], max[1], ... min[N], max[N]}, where N is the number of components.
If the image uses integer pixel components, each value in the color component array must be in the range [0 .. 2^bitsPerComponent - 1] . If the image uses floating-point pixel components, each value can be any floating-point number that is a valid color component.
An image sample is not painted if its color values fall in the range:
{c[1], ... c[N]}
where min[i] <= c[i] <= max[i] for 1 <= i <= N
Anything underneath the unpainted samples, such as the current fill color or other drawing, shows through.
The image of two tigers, shown in Figure 11-10, uses an RGB color space that has 8 bits per component. To mask a range of colors in this image, you supply minimum and maximum color component values in the range of 0 to 255.
Listing 11-4 shows a code fragment that sets up a color components array and supplies the array to the function CGImageCreateWithMaskingColors to achieve the result shown in Figure 11-11.
Listing 11-4 A code fragment that masks light to mid-range brown colors in an image
CGImageRef myMaskedImage; |
const float myMaskingColors[6] = {124, 255, 68, 222, 0, 165}; |
myColorMaskedImage = CGImageCreateWithMaskingColors (image, |
myMaskingColors); |
CGContextDrawImage (context, myContextRect, myColorMaskedImage); |
Listing 11-5 shows another code fragment that operates on the image shown in Figure 11-10 to get the results shown in Figure 11-12. This example masks a darker range of colors.
Listing 11-5 A code fragment that masks shades of brown to black
CGImageRef myMaskedImage; |
const float myMaskingColors[6] = { 0, 124, 0, 68, 0, 0 }; |
myColorMaskedImage = CGImageCreateWithMaskingColors (image, |
myMaskingColors); |
CGContextDrawImage (context, myContextRect, myColorMaskedImage); |
You can mask colors in an image as well as set a fill color to achieve the effect shown in Figure 11-13 in which the masked areas are replaced with the fill color. Listing 11-6 shows the code fragment that generates the figure shown in Figure 11-13.
Listing 11-6 Code that sets a fill color and masks a range of colors
CGImageRef myMaskedImage; |
const float myMaskingColors[6] = { 0, 124, 0, 68, 0, 0 }; |
myColorMaskedImage = CGImageCreateWithMaskingColors (image, |
myMaskingColors); |
CGContextSetRGBFillColor (myContext, 0.6373,0.6373, 0, 1); |
CGContextFillRect(context, rect); |
CGContextDrawImage(context, rect, myColorMaskedImage); |
The function CGContextClipToMask, available in Mac OS X v10.4, maps a mask into a rectangle and intersects it with the current clipping area of the graphics context. You supply an the following parameters:
The graphics context you want to clip.
A rectangle to apply the mask to.
An image mask created by calling the function CGImageMaskCreate. You can supply an image instead of an image mask to achieve an effect opposite of what you get by supplying an image mask. The image must be created with a Quartz image creation function, but it cannot be the result of applying a mask or masking color to another image.
The resulting clipped area depends on whether you provide an image mask or an image to the function CGContextClipToMask. If you supply an image mask, you get results similar to those described in “Masking an Image With an Image Mask,” except that the graphics context is clipped. If you supply an image, the graphics context is clipped similar to what’s described in “Masking an Image With an Image.”
Take a look at Figure 11-14. Assume it is an image mask created by calling the function CGImageMaskCreate and then the mask is supplied as a parameter to the function CGContextClipToMask. The resulting context allows painting to the black areas, does not allow painting to the white areas, and allows painting to the gray area with an alpha value of 1–S, where S is the sample value of the image masks. If you draw an image to the clipped context using the function CGContextDrawImage, you’ll get a result similar to that shown in Figure 11-15.
When the masking image is treated as an image, you get the opposite result, as shown in Figure 11-16.
Last updated: 2007-12-11