Quartz 2D uses the same opaque data type to represent both images and image masks. That opaque data type is simply called CGImage. The CGImage object itself is a surprisingly lightweight entity. Rather than keeping track of a lot of data in and of itself, the CGImage class relies on other objects to manage many details on its behalf. The CGImage object's job is tie together these different objects into a single entity that the computer can draw on a CGContext. The first important aspect of the image maintained by a CGImage object is its geometry. For a rectangular array of color samples, or pixels, that means that the CGImage keeps track of how many pixels high and how many pixels wide the image is. Because this is working with pixels, a discrete valued entity, CGImage uses integers (more specifically size_t) to represent the height and width of an image. All of the color samples in the pixels of a CGImage come from a particular color space. The CGImage keeps track of this color space by using an instance of the CGColorSpace opaque data type. The primary job of the color space is to help the computer interpret the values of the pixels. As you will see, however, the color space has a more subtle duty in that it defines how many color components each pixel in the color should have. A CGImage also needs some means of getting at the data structures that store the actual pixel information. In this task, the CGImage enters a partnership with the code that created it. The CGImage doesn't own any of the image data itself. Instead, it works with an opaque type called the CGDataProvider. A CGDataProvider is simply an object that knows how to supply a CGImage instance with pixel data. Some CGDataProviders own the data they pull pixels from. Others allow your application to maintain the image data. Altogether, these different data providers give you a lot of flexibility in locating, storing, and working with image data. Quartz offers even more flexibility when it comes to the pixel data itself. The simplest way to store color samples is as ordered n-tuples. The number of values in each "tuple" is determined by the color space and whether or not the image contains an alpha channel. A grayscale image with no alpha would use a single value in each "tuple" (a single value for each pixel). An RGB image with an alpha channel would require four values for each pixel. Quartz gives you options in terms of the number and kinds of values that your image specifies for each component in a pixel. It also gives you a bit of wiggle room to select the ordering of the channels within a pixel (in particular the position of the alpha channel relative to the color components of each pixel). All of this information comes together when your application creates a CGImage. More of this topic will be explored shortly. The true beauty of Quartz, however, is the fact that it encapsulates much of the underlying complexity of images behind a relatively simple API for drawing images. The next topic to cover is the way your application draw images with Quartz 2D, and afterward the question of how to create images will be revisited.
|