Important: The information in this document is obsolete and should not be used for new development.
Using Pictures
To create a picture, you should
To open an existing picture, you should
- use the
OpenCPicture
function to create aPicture
record and begin defining the picture- issue QuickDraw drawing commands, which are collected in the
Picture
record- use the
PicComment
procedure to include picture comments in the picture definition (optional)- use the
ClosePicture
procedure to conclude the picture definition
To draw a picture, you should use the
- use File Manager routines to get a picture stored in a
'PICT'
file- use the
GetPicture
function to get a picture stored in a'PICT'
resource- use the Scrap Manager function
GetScrap
to get a picture stored in the scrap
DrawPicture
procedure.To save a picture, you should
To conserve memory, you can spool large pictures to and from disk storage; you should
- use File Manager routines to save the picture in a
'PICT'
file- use Resource Manager routines to save the picture in a
'PICT'
resource- use the Scrap Manager function
PutScrap
to place the picture in the scrap
To gather information about a single picture, pixel map, or bitmap, you should
- write your own low-level procedures--using File Manager routines--that read and write temporary
'PICT'
files to disk- use the
SetStdCProcs
procedure for a color graphics port (or theSetStdProcs
procedure for a basic graphics port) and replace QuickDraw's standard low-level proceduresStdGetPic
andStdPutPic
with your own procedures for reading and writing temporary'PICT'
files to disk
To gather information about multiple pictures, pixel maps, and bitmaps, you should
- use the
GetPictInfo
function to get information about a picture, or use theGetPixMapInfo
function to get information about a pixel map or bitmap- use the
Palette
record or theColorTable
record, the handles of which are returned by these functions in aPictInfo
record, to examine the colors collected from the picture, pixel map, or bitmap- use the
FontSpec
record, the handle of which is returned byGetPictInfo
in aPictInfo
record, to examine the fonts contained in the picture- use the
CommentSpec
record, the handle of which is returned byGetPictInfo
in aPictInfo
record, to examine the picture comments contained in the picture- examine the rest of the fields of the
PictInfo
record for additional information--such as pixel depth or optimal resolution--about the picture, pixel map, or bitmap- use the Memory Manager procedure
DisposeHandle
to release the memory occupied by thePictInfo
,FontSpec
, andCommentSpec
records; use the Palette Manager procedureDisposePalette
to release the memory occupied by aPalette
record; and use the Color QuickDraw procedureDisposeCTable
to release the memory occupied by aColorTable
record when you are finished with the information collected by theGetPictInfo
function
When you are finished using a picture (such as when you close the window containing it), you should
- use the
NewPictInfo
function to begin collecting pictures, pixel maps, and bitmaps for your survey- use the
RecordPictInfo
function to add the information for a picture to your survey- use the
RecordPixMapInfo
function to add the information for a pixel map or bitmap to your survey- use the
RetrievePictInfo
function to return the collected information in aPictInfo
record- use the
Palette
record or theColorTable
record, the handles of which are returned in thePictInfo
record, to examine the colors collected from the pictures, pixel maps, and bitmaps- use the
FontSpec
record, the handle of which is returned in thePictInfo
record, to examine the fonts contained in the collected pictures- use the
CommentSpec
record, the handle of which is returned in thePictInfo
record, to examine the picture comments contained in the collected pictures- examine the rest of the fields of the
PictInfo
record for additional information about the pictures, pixel maps, and bitmaps in your survey- use the
DisposePictInfo
function to dispose of the private data structures allocated by theNewPictInfo
function; use the Memory Manager procedureDisposeHandle
to release the memory occupied byPictInfo
,FontSpec
, andCommentSpec
records; use the Palette Manager procedureDisposePalette
to release the memory occupied by aPalette
record; and use the Color QuickDraw procedureDisposeCTable
to release the memory occupied by aColorTable
record when you are finished with the information collected byNewPictInfo
Before using the routines described in this chapter, you must use the
- release the memory it occupies by calling the
KillPicture
procedure if the picture is not stored in a'PICT'
resource- release the memory it occupies by calling the Resource Manager procedure
ReleaseResource
if the picture is stored in a'PICT'
resource
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 theGestalt
function with thegestaltSystemVersion
selector. Test the low-order word in theresponse
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 toPalette
andColorTable
records.Creating and Drawing Pictures
Use theOpenCPicture
function to begin defining a picture.OpenCPicture
collects your subsequent QuickDraw drawing commands in a newPicture
record. To complete the collection of drawing and picture comment commands that define your picture, use theClosePicture
procedure.
You pass information to
- Note
- Operations with the following routines are not recorded in pictures:
CopyMask
,CopyDeepMask
,SeedFill
,SeedCFill
,CalcMask
,CalcCMask
, andPlotCIcon
.OpenCPicture
in the form of anOpenCPicParams
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 inOpenCPicParams
records.Listing 7-1 shows an application-defined routine,
MyCreateAndDrawPict
, that begins creating a picture by assigning values to the fields of anOpenCPicParams
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 anOpenCPicParams
record, theMyCreateAndDrawPict
routine passes this record to theOpenCPicture
function.
The
- IMPORTANT
- Always use the
ClipRect
procedure to specify a clipping region appropriate for your picture before you callOpenCPicture
. If you do not useClipRect
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 whenDrawPicture
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.MyCreateAndDrawPict
routine uses QuickDraw commands to draw a filled rectangle, a filled oval, and a black triangle. These commands are stored in thePicture
record.
The
- 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 codenoMemForPictPlaybackErr
.MyCreateAndDrawPict
routine concludes the picture definition by using theClosePicture
procedure. By passing to theDrawPicture
procedure the handle to the newly defined picture,MyCreateAndDrawPict
replays in the current graphics port the drawing commands stored in thePicture
record. Figure 7-3 shows the resulting figure.
- Note
- After using
DrawPicture
to draw a picture, your application can use the Window Manager procedureSetWindowPic
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, theGetWindowPic
function, allows your application to retrieve the picture handle that you store usingSetWindowPic
. When you use the Window Manager procedureDisposeWindow
to close a window,DisposeWindow
automatically calls theKillPicture
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 theGetPicture
function, your application can retrieve pictures saved in the resource forks of other file types; and using the Scrap Manager functionGetScrap
, 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, calledMyDrawFilePicture
, that uses File Manager routines to retrieve a picture saved in a'PICT'
file. TheMyDrawFilePicture
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 procedureStandardGetFile
to display a dialog box that asks the user for the name of a'PICT'
file; using the file system specification record returned byStandardGetFile
, the application calls the File Manager functionFSpOpenDF
to return a file reference number for the file. The application then passes this file reference number toMyDrawFilePicture
.Because every
'PICT'
file contains a 512-byte header for application-specific use,MyDrawFilePicture
uses the File Manager functionSetFPos
to skip past this header information. TheMyDrawFilePicture
function then uses the File Manager functionFSRead
to read the file's remaining bytes--those of thePicture
record--into memory.The
MyDrawFilePicture
function creates a handle for the buffer into which thePicture
record is read. Passing this handle to theDrawPicture
procedure,MyDrawFilePicture
is able to replay onscreen the commands stored in thePicture
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 routineMyReplaceGetPic
shown in Listing 7-3 replaces thegetPicProc
field of the current graphics port'sCQDProcs
record with an application-defined low-level routine, calledMyFileGetPic
. While QuickDraw's standardStdGetPic
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 standardStdPutPic
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 procedureMyIsColorPort
, whichMyReplaceGetPic
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 procedureMyFileGetPic
, which uses the File Manager functionFSRead
to read the file with the file reference number assigned to the application-defined global variablegPictFileRefNum
.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 whereFSRead
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 usingFSRead
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 definesMyPastePict
. TheMyPastePict
procedure uses the Scrap Manager procedureGetScrap
to get a handle to the data stored on the scrap;MyPastePict
then coerces this handle to one of typePicHandle
, which it can pass to theDrawPicture
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. TheDrawPicture
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 toDrawPicture
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 callingMyAdjustDestRect
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 toMyAdjustDestRect
.A bounding rectangle is stored in the
picFrame
field of thePicture
record for every picture. TheMyAdjustDestRect
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. ThePictInfo
record (described on page 7-31) returned byGetPictInfo
returns the picture's resolution in itshRes
andvRes
fields. ThesourceRect
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 theGetPicture
function, which returns a handle to the picture. Listing 7-8 illustrates an application-defined routine, calledMyDrawResPICT
, 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 procedureReleaseResource
instead of the QuickDraw procedureKillResource
to release its memory.
- IMPORTANT
- If you retrieve a picture stored in a
'PICT'
resource and pass its handle to the Window Manager procedureSetWindowPic
, the Window Manager proceduresDisposeWindow
andCloseWindow
do not delete it; instead, you must callReleaseResource
before callingDisposeWindow
orCloseWindow
.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 asFSpCreate
,FSpOpenDF
,FSWrite
, andFSClose
. 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, thePicture
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 asFSpOpenResFile
(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), andCloseResFile
andReleaseResource
(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 routineMyReplacePutPic
shown in Listing 7-10 replaces theputPicProc
field of the current graphics port'sCQDProcs
record with an application-defined low-level routine, calledMyFilePutPic
. While QuickDraw's standardStdPutPic
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 standardStdGetPic
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 showsMyFilePutPic
, which uses the File Manager functionFSWrite
to write picture data to the file with the file reference number assigned to the application-defined global variablegPictFileRefNum
. Your application does not keep track of whereFSWrite
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 theGetPictInfo
function to gather information about a single picture, and you use theGetPixMapInfo
function to gather color information about a single pixel map or bitmap. Each of these functions returns color and resolution information in aPictInfo
record (described on page 7-31). APictInfo
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 useNewPictInfo
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 theRecordPixMapInfo
function. TheRetrievePictInfo
function collects the information about the pictures, pixel maps, and bitmaps that you have added to your survey. TheRetrievePictInfo
function returns this information in aPictInfo
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 aPicture
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, calledMyGetPICTProfileCount
, that usesGetPictInfo
to record comments in aCommentSpec
record (which is described on page 7-29). TheMyGetPICTProfileCount
routine uses theCommentSpec
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 aPalette
record orColorTable
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
, andHiliteColor
(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 theGetPixMapInfo
function to obtain color information about that pixel map for that graphics world.