Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Imaging With QuickDraw /
Chapter 7 - Pictures


Using Pictures

To create a picture, you should

To open an existing picture, you should

To draw a picture, you should use the DrawPicture procedure.

To save a picture, you should

To conserve memory, you can spool large pictures to and from disk storage; you should

To gather information about a single picture, pixel map, or bitmap, you should

To gather information about multiple pictures, pixel maps, and bitmaps, you should

When you are finished using a picture (such as when you close the window containing it), you should

Before using the routines described in this chapter, you must use the InitGraf procedure, described in the chapter "Basic QuickDraw" in this book, to initialize QuickDraw. The routines in this chapter are available on all computers running System 7--including those supporting only basic QuickDraw. To test for the existence of System 7, use the Gestalt function with the gestaltSystemVersion selector. Test the low-order word in the response parameter; if the value is $0700 or greater, all of the routines in this chapter are supported.

Note
On computers running only basic QuickDraw, the Picture Utilities return NIL in place of handles to Palette and ColorTable records.

Creating and Drawing Pictures

Use the OpenCPicture function to begin defining a picture. OpenCPicture collects your subsequent QuickDraw drawing commands in a new Picture record. To complete the collection of drawing and picture comment commands that define your picture, use the ClosePicture procedure.

Note
Operations with the following routines are not recorded in pictures: CopyMask, CopyDeepMask, SeedFill, SeedCFill, CalcMask, CalcCMask, and PlotCIcon.
You pass information to OpenCPicture in the form of an OpenCPicParams record. This record provides a simple mechanism for specifying resolutions when creating images. For example, applications that create pictures from scanned images can specify resolutions higher than 72 dpi for these pictures in OpenCPicParams records.

Listing 7-1 shows an application-defined routine, MyCreateAndDrawPict, that begins creating a picture by assigning values to the fields of an OpenCPicParams record. In this example, the normal screen resolution of 72 dpi is specified as the picture's resolution. You also specify a rectangle for best displaying the picture at this resolution.

Listing 7-1 Creating and drawing a picture

FUNCTION MyCreateAndDrawPict(pFrame: Rect): PicHandle;
CONST
   cHRes = $00480000;   {for 72 dpi}
   cVRes = $00480000;   {for 72 dpi}
VAR
   myOpenCPicParams: OpenCPicParams;
   myPic:            PicHandle;
   trianglePoly:     PolyHandle;
BEGIN
   WITH myOpenCPicParams DO BEGIN
      srcRect := pFrame;   {best rectangle for displaying this picture}
      hRes := cHRes;       {horizontal resolution}
      vRes := cVRes;       {vertical resolution}
      version := - 2;      {always set this field to -2}
      reserved1 := 0;      {this field is unused}
      reserved2 := 0;      {this field is unused}
   END;
   myPic := OpenCPicture(myOpenCPicParams);  {start creating the picture}
   ClipRect(pFrame);                      {always set a valid clip region}
   FillRect(pFrame,dkGray);   {create a dark gray rectangle for background}
   FillOval(pFrame,ltGray);   {overlay the rectangle with a light gray oval}
   trianglePoly := OpenPoly;  {start creating a triangle}
   WITH pFrame DO BEGIN
      MoveTo(left,bottom);
      LineTo((right - left) DIV 2,top);
      LineTo(right,bottom);
      LineTo(left,bottom);
   END;
   ClosePoly;                 {finish the triangle}
   PaintPoly(trianglePoly);   {paint the triangle}
   KillPoly(trianglePoly);    {dispose of the memory for the triangle}
   ClosePicture;              {finish the picture}
   DrawPicture(myPic,pFrame);       {draw the picture}
   IF QDError <> noErr THEN
      ; {likely error is that there is insufficient memory}
   MyCreateAndDrawPict := myPic;
END;
After assigning values to the fields of an OpenCPicParams record, the MyCreateAndDrawPict routine passes this record to the OpenCPicture function.

IMPORTANT
Always use the ClipRect procedure to specify a clipping region appropriate for your picture before you call OpenCPicture. If you do not use ClipRect to specify a clipping region, OpenCPicture uses the clipping region specified in the current graphics port. If the clipping region is very large (as it is when a graphics port is initialized) and you scale the picture when drawing it, the clipping region can become invalid when DrawPicture scales the clipping region--in which case, your picture will not be drawn. On the other hand, if the graphics port specifies a small clipping region, part of your drawing may be clipped when you draw it. Setting a clipping region equal to the port rectangle of the current graphics port, as shown in Listing 7-1, always sets a valid clipping region.
The MyCreateAndDrawPict routine uses QuickDraw commands to draw a filled rectangle, a filled oval, and a black triangle. These commands are stored in the Picture record.

Note
If there is insufficient memory to draw a picture in Color QuickDraw, the QDError function (described in the chapter "Color QuickDraw" in this book) returns the result code noMemForPictPlaybackErr.
The MyCreateAndDrawPict routine concludes the picture definition by using the ClosePicture procedure. By passing to the DrawPicture procedure the handle to the newly defined picture, MyCreateAndDrawPict replays in the current graphics port the drawing commands stored in the Picture record. Figure 7-3 shows the resulting figure.

Figure 7-3 A simple picture


Note
After using DrawPicture to draw a picture, your application can use the Window Manager procedure SetWindowPic to save a handle to the picture in the window record. When the window's content region must be updated, the Window Manager draws this picture, or only a part of it as necessary, instead of generating an update event. Another Window Manager routine, the GetWindowPic function, allows your application to retrieve the picture handle that you store using SetWindowPic. When you use the Window Manager procedure DisposeWindow to close a window, DisposeWindow automatically calls the KillPicture procedure to release the memory allocated to a picture referenced in the window record. These routines and the window record are described in the chapter "Window Manager" in Inside Macintosh: Macintosh Toolbox Essentials.

Opening and Drawing Pictures

Using File Manager routines, your application can retrieve pictures saved in 'PICT' files; using the GetPicture function, your application can retrieve pictures saved in the resource forks of other file types; and using the Scrap Manager function GetScrap, your application can retrieve pictures stored in the scrap.

Drawing a Picture Stored in a 'PICT' File

Listing 7-2 illustrates an application-defined routine, called MyDrawFilePicture, that uses File Manager routines to retrieve a picture saved in a 'PICT' file. The MyDrawFilePicture routine takes a file reference number as a parameter.

Listing 7-2 Opening and drawing a picture from disk

FUNCTION MyDrawFilePicture(pictFileRefNum: Integer; destRect: Rect): OSErr;
CONST
   cPicFileHeaderSize = 512;
VAR
   myPic:      PicHandle;
   dataLength: LongInt;
   err:        OSErr;
BEGIN    {This listing assumes the current graphics port is set.}
   err := GetEOF(pictFileRefNum,dataLength);    {get file length}
   IF err = noErr THEN BEGIN
      err := SetFPos(pictFileRefNum,fsFromStart,
                     cPicFileHeaderSize); {move past the 512-byte 'PICT' }
                                          { file header}
      dataLength := dataLength - cPicFileHeaderSize;  {remove 512-byte }
                                    { 'PICT' file header from file length}
      myPic := PicHandle(NewHandle(dataLength)); {allocate picture handle}
      IF (err = noErr) & (myPic <> NIL) THEN BEGIN
         HLock(Handle(myPic));   {lock picture handle before using FSRead}
         err := FSRead(pictFileRefNum,dataLength,Ptr(myPic^)); {read file}
         HUnlock(Handle(myPic)); {unlock picture handle after using FSRead}
         MyAdjustDestRect(myPic,destRect);   {see Listing 7-7 on page 7-18}
         DrawPicture(myPic,destRect);
         IF QDError <> noErr THEN
            ; {likely error is that there is insufficient memory}
         KillPicture(myPic);
      END;
   END;
   MyDrawFilePicture := err;
END;
In code not shown in Listing 7-2, this application uses the File Manager procedure StandardGetFile to display a dialog box that asks the user for the name of a 'PICT' file; using the file system specification record returned by StandardGetFile, the application calls the File Manager function FSpOpenDF to return a file reference number for the file. The application then passes this file reference number to MyDrawFilePicture.

Because every 'PICT' file contains a 512-byte header for application-specific use, MyDrawFilePicture uses the File Manager function SetFPos to skip past this header information. The MyDrawFilePicture function then uses the File Manager function FSRead to read the file's remaining bytes--those of the Picture record--into memory.

The MyDrawFilePicture function creates a handle for the buffer into which the Picture record is read. Passing this handle to the DrawPicture procedure, MyDrawFilePicture is able to replay onscreen the commands stored in the Picture record.

For large 'PICT' files, it is useful to spool the picture data from disk as necessary instead of reading all of it directly into memory. In low-memory conditions, for example, your application might find it useful to create a temporary file on disk for storing drawing instructions; your application can read this information as necessary. The application-defined routine MyReplaceGetPic shown in Listing 7-3 replaces the getPicProc field of the current graphics port's CQDProcs record with an application-defined low-level routine, called MyFileGetPic. While QuickDraw's standard StdGetPic procedure reads picture data from memory, MyFileGetPic reads the picture data from disk. (Listing 7-10 on page 7-21 shows how to replace QuickDraw's standard StdPutPic procedure with one that writes data to a file so that your application can spool a large picture to disk.)

Listing 7-3 Replacing QuickDraw's standard low-level picture-reading routine

FUNCTION MyReplaceGetPic: QDProcsPtr;
VAR
   currPort:      GrafPtr;
   customProcs:   QDProcs;
   customCProcs:  CQDProcs;
   savedProcs:    QDProcsPtr;
BEGIN
   GetPort(currPort);
   savedProcs := currPort^.grafProcs;  {save current CQDProcs }
                                       { or QDProcs record}
   IF MyIsColorPort(currPort) THEN     {this is a color graphics port}
   BEGIN
      SetStdCProcs(customCProcs);   {create new CQDProcs record containing }
                                    { standard Color QuickDraw low-level }
                                    { routines}
      customCProcs.getPicProc := @MyFileGetPic; {replace StdGetPic with }
                                                { address of custom }
                                                { low-level routine }
                                                { shown in Listing 7-5}
      currPort^.grafProcs := @customCProcs;  {replace current CQDProcs }
                                             { record}
   END
   ELSE 
   BEGIN                            {this is a basic graphics port}
      SetStdProcs(customProcs);     {create new QDProcs record containing }
                                    { standard basic QuickDraw low-level }
                                    { routines}
      customProcs.getPicProc := @MyFileGetPic;  {replace StdGetPic with }
                                                { address of custom }
                                                { low-level routine }
                                                { shown in Listing 7-5}
      currPort^.grafProcs := @customProcs;   {replace current QDProcs record}
   END;
   MyReplaceGetPic := savedProcs;
END;
Listing 7-4 shows the application-defined procedure MyIsColorPort, which MyReplaceGetPic calls to determine whether to replace the low-level picture-reading routine for a color graphics port or a basic graphics port.

Listing 7-4 Determining whether a graphics port is color or basic

FUNCTION MyIsColorPort(aPort: GrafPtr): Boolean;
BEGIN
   MyIsColorPort := (aPort^.portBits.rowBytes < 0)
END;
Listing 7-5 shows the application-defined procedure MyFileGetPic, which uses the File Manager function FSRead to read the file with the file reference number assigned to the application-defined global variable gPictFileRefNum.

Listing 7-5 A custom low-level procedure for spooling a picture from disk

PROCEDURE MyFileGetPic (dataPtr: Ptr; byteCount: Integer);
VAR
   longCount:  LongInt;
   myErr:      OSErr;
BEGIN
   longCount := byteCount;
   myErr := FSRead(gPictFileRefNum, longCount, dataPtr);
END;
Your application does not keep track of where FSRead stops or resumes reading a file. After reading a portion of a file, FSRead automatically handles where to begin reading next. See Inside Macintosh: Files for more information about using FSRead and other File Manager routines to retrieve data stored in files.

Drawing a Picture Stored in the Scrap

As described in the chapter "Scrap Manager" in Inside Macintosh: More Macintosh Toolbox, your application can use the Scrap Manager to copy and paste data within a document created by your application, among different documents created by your application, and among documents created by your application and documents created by other applications. The two standard scrap formats that all Macintosh applications should support are 'PICT' and 'TEXT'.

Listing 7-6 illustrates the application-defined routine MyPastePict, which retrieves a picture stored on the scrap. For example, a user may have copied to the Clipboard a picture created in another application and then pasted the picture into the application that defines MyPastePict. The MyPastePict procedure uses the Scrap Manager procedure GetScrap to get a handle to the data stored on the scrap; MyPastePict then coerces this handle to one of type PicHandle, which it can pass to the DrawPicture procedure in order to replay the drawing commands stored in the scrap.

Listing 7-6 Pasting in a picture from the scrap

PROCEDURE MyPastePict(destRect: Rect);
VAR
   myPic:      PicHandle;
   dataLength: LongInt;
   dontCare:   LongInt;
BEGIN
   myPic := PicHandle(NewHandle(0));   {allocate a handle for the picture}
   dataLength := 
            GetScrap(Handle(myPic),'PICT',dontCare);  {get picture in scrap}
   IF dataLength > 0 THEN {ensure there is PICT data}
   BEGIN
      MyAdjustDestRect(myPic,destRect);   {shown in Listing 7-7}
      DrawPicture(myPic,destRect);
      IF QDError <> noErr THEN
         ; {likely error is that there is insufficient memory}
   END
   ELSE
   ; {handle error for len < or = 0 here}
END;

Defining a Destination Rectangle

In addition to taking a handle to a picture as one parameter, DrawPicture also expects a destination rectangle as another parameter. You should specify this destination rectangle in coordinates local to the current graphics port. The DrawPicture procedure shrinks or stretches the picture as necessary to make it fit into this rectangle.

Listing 7-7 shows an application-defined routine called MyAdjustDestRect that centers the picture inside a destination rectangle, which is passed to DrawPicture when it's time to draw the picture. (MyAdjustDestRect first ensures that the picture fits inside the destination rectangle by scaling the picture if necessary.)

Listing 7-7 Adjusting the destination rectangle for a picture

PROCEDURE MyAdjustDestRect(aPict: PicHandle; VAR destRect: Rect);
VAR
   r:                      Rect;
   width, height:          Integer;
   scale, scaleH, scaleV:  Fixed;
BEGIN
   WITH destRect DO BEGIN  {determine width and height of destination rect}
      width := right - left;
      height := bottom - top;
   END;
   r := aPict^^.picFrame;        {get the bounding rectangle of the picture}
   OffsetRect(r, - r.left, - r.top);   {ensure upper-left corner is (0,0)}
   scale := Long2Fix(1);
   scaleH := FixRatio(width,r.right);     {get horizontal and vertical }
   scaleV := FixRatio(height,r.bottom);   { ratios of destination rectangle }
                                          { to bounding rectangle of picture}
   IF scaleH < scale THEN scale := scaleH;   {if bounding rect of picture }
   IF scaleV < scale THEN scale := scaleV;   { is greater than destination }
   IF scale <> Long2Fix(1) THEN              { rect, get scaling factors}
   BEGIN       {scale picture to fit inside destination rectangle}
      r.right := Fix2Long(FixMul(scale,Long2Fix(r.right)));
      r.bottom := Fix2Long(FixMul(scale,Long2Fix(r.bottom)));
    END;
   {next line centers the picture within the destination rectangle}
   OffsetRect(r,(width - r.right) DIV 2,(height - r.bottom) DIV 2);
   destRect := r;
END;
The application calling MyAdjustDestRect begins defining a destination rectangle by determining a target area within a window--perhaps the entire content area of a window, or perhaps an area selected by the user within a window. The application passes this rectangle to MyAdjustDestRect.

A bounding rectangle is stored in the picFrame field of the Picture record for every picture. The MyAdjustDestRect routine uses the boundaries for the picture to determine whether the picture fits within the destination rectangle. If the picture is larger than the destination rectangle, MyAdjustDestRect scales the picture to make it fit the destination rectangle.

The MyAdjustDestRect routine then centers the picture within the destination rectangle. Finally, MyAdjustDestRect assigns the boundary rectangle of the centered picture to be the new destination rectangle. By returning a destination rectangle whose dimensions are identical to those of the bounding rectangle for the picture, MyAdjustDestRect assures that the picture is not stretched when drawn into its window.

To display a picture at a resolution other than the one at which it was created, your application should compute an appropriate destination rectangle by scaling its width and height by the following factor:

scale factor = destination resolution / source resolution

For example, if a picture was created at 300 dpi and you want to display it at 75 dpi, then your application should compute the destination rectangle width and height as 1/4 of those of the picture's bounding rectangle. Your application can use the GetPictInfo function (described on page 7-46) to gather information about a picture. The PictInfo record (described on page 7-31) returned by GetPictInfo returns the picture's resolution in its hRes and vRes fields. The sourceRect field contains the bounding rectangle for displaying the image at its optimal resolution.

Drawing a Picture Stored in a 'PICT' Resource

To retrieve a picture stored in a 'PICT' resource, specify its resource ID to the GetPicture function, which returns a handle to the picture. Listing 7-8 illustrates an application-defined routine, called MyDrawResPICT, that retrieves and draws a picture stored as a resource.

Listing 7-8 Drawing a picture stored in a resource file

PROCEDURE MyDrawResPICT(destRect: Rect; resID: Integer);
VAR
   myPic:   PicHandle;
BEGIN
   myPic := GetPicture(resID);   {get the picture from the resource fork}
   IF myPic <> NIL THEN BEGIN
      MyAdjustDestRect(myPic,destRect);{see Listing 7-7 on page 7-18}
      DrawPicture(myPic,destRect);
      IF QDError <> noErr THEN
         ; {likely error is that there is insufficient memory}
   END
   ELSE
   ; {handle the error here}
END;
When you are finished using a picture stored as a 'PICT' resource, you should use the Resource Manager procedure ReleaseResource instead of the QuickDraw procedure KillResource to release its memory.

IMPORTANT
If you retrieve a picture stored in a 'PICT' resource and pass its handle to the Window Manager procedure SetWindowPic, the Window Manager procedures DisposeWindow and CloseWindow do not delete it; instead, you must call ReleaseResource before calling DisposeWindow or CloseWindow.

Saving Pictures

After creating or changing pictures, your application should allow the user to save them. To save a picture in a 'PICT' file, you should use File Manager routines, such as FSpCreate, FSpOpenDF, FSWrite, and FSClose. The use of these routines is illustrated in Listing 7-9, and they are described in detail in the chapter "File Manager" in Inside Macintosh: Files. Remember that the first 512 bytes of a 'PICT' file are reserved for your application's own purposes. As shown in Listing 7-9, your application should store the data (that is, the Picture record) after this 512-byte header.

Listing 7-9 Saving a picture as a 'PICT' file

FUNCTION DoSavePICTAsCmd(picH: PicHandle): OSErr;
LABEL 8,9;
VAR
   myReply:                      StandardFileReply;
   err, ignore:                  OSErr;
   pictFileRefNum:               Integer;
   dataLength, zeroData, count:  LongInt;
BEGIN                {display the default Save dialog box}
   StandardPutFile('Save picture as:','untitled',myReply);
   err := noErr;  {return noErr if the user cancels}
   IF myReply.sfGood THEN 
   BEGIN
      IF NOT myReply.sfReplacing THEN  {create the file if it doesn't exist}
         err := FSpCreate(myReply.sfFile,'WAVE','PICT',smSystemScript);
      IF err <> noErr THEN GOTO 9;
      err := FSpOpenDF(myReply.sfFile,fsRdWrPerm,pictFileRefNum); {open file}
      IF err <> noErr THEN GOTO 8;
      zeroData := 0;
      dataLength := 4;
      FOR count := 1 TO 512 DIV dataLength DO   {write the PICT file header}
         err := FSWrite(pictFileRefNum,dataLength,
                        @zeroData); {for this app, put 0's in header}
      IF err <> noErr THEN GOTO 8;
      dataLength := GetHandleSize(Handle(picH));
      HLock(Handle(picH)); {lock picture handle before writing data}
      err := FSWrite(pictFileRefNum,dataLength,Ptr(picH^)); {write picture }
                                                            { data to file}
       HUnlock(Handle(picH)); {unlock picture handle after writing data}
   END;
   8:
      ignore := FSClose(pictFileRefNum);  {close the file}
   9:
      DoSavePICTAsCmd := err;
END;
To save a picture in a 'PICT' resource, you should use Resource Manager routines, such as FSpOpenResFile (to open your application's resource fork), ChangedResource (to change an existing 'PICT' resource), AddResource (to add a new 'PICT' resource), WriteResource (to write the data to the resource), and CloseResFile and ReleaseResource (to conclude saving the resource). These routines are described in the chapter "Resource Manager" in Inside Macintosh: More Macintosh Toolbox.

To place a picture in the scrap--for example, in response to the user choosing the Copy command to copy a picture to the Clipboard--use the Scrap Manager function PutScrap, which is described in the chapter "Scrap Manager" in Inside Macintosh: More Macintosh Toolbox.

For large 'PICT' files, it is useful to spool the picture data to disk instead of writing it all directly into memory. In low-memory conditions, for example, your application might find it useful to create a temporary file on disk for storing drawing instructions; your application can read this information as necessary. The application-defined routine MyReplacePutPic shown in Listing 7-10 replaces the putPicProc field of the current graphics port's CQDProcs record with an application-defined low-level routine, called MyFilePutPic. While QuickDraw's standard StdPutPic procedure writes picture data to memory, MyFilePutPic writes the picture data to disk. (Listing 7-3 on page 7-14 shows how to replace QuickDraw's standard StdGetPic procedure with one that reads data from a spool file.)

Listing 7-10 Replacing QuickDraw's standard low-level picture-writing routine

FUNCTION MyReplacePutPic: QDProcsPtr;
VAR
   currPort:      GrafPtr;
   customProcs:   QDProcs;
   customCProcs:  CQDProcs;
   savedProcs:    QDProcsPtr;
BEGIN 
   GetPort(currPort);
   savedProcs := currPort^.grafProcs;  {save QDProcs or CQDProcs record }
                                       { for current graphics port}
   IF MyIsColorPort(currPort) THEN  {see Listing 7-4 on page 7-16}
   BEGIN
      SetStdCProcs(customCProcs);   {create new CQDProcs record containing }
                                    { standard Color QuickDraw low-level }
                                    { routines}

      customCProcs.putPicProc := @MyFilePutPic; {replace StdPutPic with }
                                                { address of custom }
                                                { low-level routine }
                                                { shown in Listing 7-11}
      currPort^.grafProcs := @customCProcs;  {replace current CQDProcs}
   END
   ELSE 
   BEGIN       {perform similar work for a basic graphics port}
      SetStdProcs(customProcs);
      customProcs.putPicProc := @MyFilePutPic;
      currPort^.grafProcs := @customProcs;
   END;
   gPictureSize := 0;   {track the picture size}
   gSpoolPicture := PicHandle(NewHandle(0));
   MyReplacePutPic := savedProcs;         {return saved CQDProcs or QDProcs }
                                    { record for restoring at a later time}
END;
Listing 7-11 shows MyFilePutPic, which uses the File Manager function FSWrite to write picture data to the file with the file reference number assigned to the application-defined global variable gPictFileRefNum. Your application does not keep track of where FSWrite stops or resumes writing a file. After writing a portion of a file, FSWrite automatically handles where to begin writing next.

Listing 7-11 A custom low-level routine for spooling a picture to disk

PROCEDURE MyFilePutPic (dataPtr: Ptr; byteCount: Integer);
VAR
   dataLength: LongInt;
   myErr: OSErr;
BEGIN
   dataLength := byteCount;
   gPictureSize := gPictureSize + byteCount;
   myErr := FSWrite(gPictFileRefNum, dataLength, dataPtr);
   IF gSpoolPicture <> NIL THEN
   gSpoolPicture^^.picSize := gPictureSize;
END;

Gathering Picture Information

You can use the Picture Utilities routines to gather extensive information about pictures and to gather color information about pixel maps. You use the GetPictInfo function to gather information about a single picture, and you use the GetPixMapInfo function to gather color information about a single pixel map or bitmap. Each of these functions returns color and resolution information in a PictInfo record (described on page 7-31). A PictInfo record can also contain information about the drawing objects, fonts, and comments in a picture.

You can also survey multiple pictures, pixel maps, and bitmaps for this information. Use the NewPictInfo function to begin collecting pictures, pixel maps, and bitmaps for your survey. You also use NewPictInfo to specify how you would like the color, comment, and font information for the survey returned to you.

To add the information for a picture to your survey, use the RecordPictInfo function. To add the information for a pixel map or a bitmap to your survey, use the RecordPixMapInfo function. The RetrievePictInfo function collects the information about the pictures, pixel maps, and bitmaps that you have added to your survey. The RetrievePictInfo function returns this information in a PictInfo record.

For example, to use the ColorSync Utilities to match the colors in a single picture to an output device such as a color printer, an application might find it useful to find the CMBeginProfile picture comment, which marks the beginning of a color profile in a Picture record. (Color profiles and the ColorSync Utilities are described in Advanced Color Imaging on the Mac OS.) Listing 7-12 shows an application-defined routine, called MyGetPICTProfileCount, that uses GetPictInfo to record comments in a CommentSpec record (which is described on page 7-29). The MyGetPICTProfileCount routine uses the CommentSpec record to determine whether any color profiles are included in the picture as picture comments.

Listing 7-12 Looking for color profile comments in a picture

FUNCTION MyGetPICTProfileCount (hPICT: PicHandle; VAR count: Integer): OSErr;
VAR
   err:              OSErr;
   thePICTInfo:      PictInfo;
   verb:             Integer;
   colorsRequested:  Integer;
   colorPickMethod:  Integer;
   version:          Integer;
   pCommentSpec:     CommentSpecPtr;
   i:                Integer;
BEGIN
   count := 0;
   verb := recordComments;
   colorsRequested := 0;
   colorPickMethod := systemMethod;
   version := 0;
   err := GetPictInfo(hPICT, thePICTInfo, verb, colorsRequested, 
                      colorPickMethod, version);
   IF ((err = noErr) AND (thePICTInfo.commentHandle <> NIL)) THEN
   BEGIN
      pCommentSpec := thePICTInfo.commentHandle^;
      FOR i := 1 TO thePICTInfo.uniqueComments DO
      BEGIN
         IF (pCommentSpec^.ID = CMBeginProfile) THEN
            BEGIN
               count := pCommentSpec^.count;
               LEAVE;
            END;
         pCommentSpec :=
            CommentSpecPtr(ORD4(pCommentSpec)+Sizeof(CommentSpec));
      END;
      {clean up allocations made by GetPictInfo}
      DisposeHandle(Handle(thePICTInfo.commentHandle));
   END;
   MyGetPICTProfileCount := err;
END;
If you want information about the colors of a picture or pixel map, you indicate to the Picture Utilities how many colors (up to 256) you want to know about, what method to use for selecting the colors, and whether you want the selected colors returned in a Palette record or ColorTable record.

The Picture Utilities provide two color-picking methods: one that gives you the most frequently used colors and one that gives you the widest range of colors. Each has advantages in different situations. For example, suppose the picture of a forest image contains 400 colors, of which 300 are greens, 80 are browns, and the rest are a scattering of golden sunlight effects. If you ask for the 250 most used colors, you will probably receive all greens. If you ask for a range of 250 colors, you will receive an assortment stretching from the greens and golds to the browns, including colors in between that might not actually appear in the image. You can also supply a color-picking method of your own, as described in "Application-Defined Routines" beginning on page 7-60.

Your application can then use the color information returned by the Picture Utilities in conjunction with the Palette Manager to provide the best selection of colors for displaying the picture on an 8-bit indexed device.

IMPORTANT
When you ask for color information about a picture, the Picture Utilities take into account only the version 2 and extended version 2 picture opcodes RGBFgCol, RGBBkCol, BkPixPat, PnPixPat, FillPixPat, and HiliteColor (as well as pixel map or bitmap data). Each occurrence of these opcodes is treated as one pixel, regardless of the number and sizes of the objects drawn with that color. If you need an accurate set of colors from a complex picture, create an image of the picture in an offscreen graphics world and call the GetPixMapInfo function to obtain color information about that pixel map for that graphics world.

Previous Book Contents Book Index Next

© Apple Computer, Inc.
7 JUL 1996