PictInfoTest.c

// Sample to demonstrate using the Picture Utilities Package
//
// The guts of this is in the window creation function: DoCreateWindow( PicHandle thePicture )
// 
// DoCreateWindow is passed a picture handle and if the global gUsePictPalette is set it
// will use the pict utils package (PUP) to get the color table stored in the pict.  You could 
// this source to sample direct color images, but to keep things as clear as possible this
// application only deals with 8 bit images.
//
// We use the PUP to get the color table for the image.  This is passed into NewGWorld and it
// is also used to create a palette that is attached to the window.
//
// Note that we use PUP to sample the image that was stored in the file.  We interrogate a
// PicHandle read directly from the file.  There are also routines for sampling PixMaps,
// but dont forget that if you are in an indexed color environment, and you sample a PixMap, 
// if you didnt set up the color environment when your first created the PixMap, the colors
// may not be as you expect.  
//
// To see an example of this there are two 8-bit images included with this snippet.
// One is a spectral ramp, the other a green/brow ramp.  Both have approx 120 or so colors.
// to see an example of what PUP may report if you didnt set the colors for a window up
// properly before displaying open one of the files with the "use picture palette" item 
// from the palette menu toggled off.
//
// in this case it will use the "wrong" set of colors to try to draw the image (it just uses
// what ever the default system color table is).  If you get PUP to sample (by toggling on
// the "use picture palette" item from the palette menu the picture is rendered correctly.
//
// Nick Thompson - May 6th 1994
//
//  Copyright:  © 1989-94 by Apple Computer, Inc., all rights reserved.
 
/* Constant Declarations */
#include <menus.h>
#include <PictUtil.h>
#include <QDOffScreen.h>
 
 
#define WWIDTH      470
#define WHEIGHT     330
 
#define WLEFT       (((screenBits.bounds.right - screenBits.bounds.left) - WWIDTH) / 2)
#define WTOP        (((screenBits.bounds.bottom - screenBits.bounds.top) - WHEIGHT) / 2)
 
#define HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
#define LoWrd(aLong)    ((aLong) & 0xFFFF)
 
 
 
enum {
    mApple = 128,
    mFile,
    mPalette
} ;
 
enum {
    iAbout = 1
} ;
enum {
    iOpen = 1,
    iClose,
    iUnused1,
    iQuit = 4
} ;
 
enum {
    iUsePictPalette = 1
} ;
 
static Boolean gQuitFlag = false ;
static Point gStaggerPos = {50,50} ;
static Boolean gUsePictPalette = true ;
 
// function prototypes
 
void InitToolbox( void ) ;
void MainEventLoop( void ) ;
void HandleKeyPress(EventRecord *event) ;
void HandleOSEvent(EventRecord *event) ;
void HandleMenuCommand(long menuResult) ;
PicHandle DoReadPICT( short theRef, OSErr *theErr ) ;
OSErr DoCreateWindow( PicHandle thePicture ) ;
void AdjustMenus( void ) ;
 
 
const RGBColor  kRGBBlack = {0, 0, 0};
const RGBColor  kRGBWhite = {0xFFFF, 0xFFFF, 0xFFFF};
 
 
main()
{
    InitToolbox() ;
    
    MainEventLoop();
}
 
 
 
void InitToolbox()
{
    OSErr       retCode;
    long        gestResponse;
    Handle      menuBar = nil;
    EventRecord event;
    short       count;
 
 
    InitGraf((Ptr) &qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(0L);
    InitCursor();
 
    // initialize application globals
    
    gQuitFlag = false;
    
    
    menuBar = GetNewMBar(128);              // Read menus into menu bar, MBAR res id is 128
    
    if ( menuBar == nil )
         ExitToShell();                     // if we dont have it then quit - your app 
                                            // needs a dialog here
 
    SetMenuBar(menuBar);                    // Install menus
    DisposHandle(menuBar);
    
    AddResMenu(GetMHandle(mApple), 'DRVR'); // Add DA names to Apple menu, ID 128
 
    DrawMenuBar();
}
 
 
void MainEventLoop()
{
    EventRecord     event;
    WindowPtr       window;
    short           thePart;
    Rect            screenRect;
    Point           aPoint = {100, 100};
    GWorldPtr       theNewWorld ;
    PixMapHandle    offPixMap ;
    GrafPtr         oldPort ;
 
    while( !gQuitFlag )
    {
        if (WaitNextEvent( everyEvent, &event, 0, nil ))
        {
            AdjustMenus() ;
 
            switch (event.what) {
                case mouseDown:
                
                    thePart = FindWindow( event.where, &window );
                    
                    switch( thePart ) {
                        case inMenuBar: 
                            HandleMenuCommand(MenuSelect(event.where));
                            break;
                        
                        case inDrag:
                    
                            screenRect = (**GetGrayRgn()).rgnBBox;
                            DragWindow( window, event.where, &screenRect );
                            break ;
                    
                        case inContent:
                    
                            if (window != FrontWindow())
                                SelectWindow( window );
                            break ;
                    
                        case inGoAway:
                            if (TrackGoAway( window, event.where )) {
                                DisposeWindow ( window );
                            }
                            break ;
                            
                        default:
                            break ;
                    }
                    break ;
                            
                        
                case updateEvt:
                
                    window = (WindowPtr)event.message;
                    GetPort(&oldPort ) ;    
                    SetPort( window );
                    
                    BeginUpdate( window );
                    
                    // get the GWorld from the window refcon
                    theNewWorld = (GWorldPtr)GetWRefCon ( window );
                    offPixMap = GetGWorldPixMap( theNewWorld ) ;
                    (void) LockPixels( offPixMap ) ;
                    CopyBits( &((GrafPtr)theNewWorld)->portBits,
                              &window->portBits,
                              &window->portRect,
                              &window->portRect,
                              srcCopy,
                              nil ) ;
                    (void) UnlockPixels( offPixMap ) ;
 
                    EndUpdate( window );
                    SetPort( oldPort ) ;
                    break ;
                    
                case keyDown:
                case autoKey:
                    HandleKeyPress(&event);
                    break;
                    
                case diskEvt:
                    if ( HiWrd(event.message) != noErr ) 
                        (void) DIBadMount(aPoint, event.message);
                    break;
                    
                case osEvt:
                case activateEvt:
                    break;
 
 
            }
        }
    }
}
 
 
void HandleKeyPress(EventRecord *event)
{
    char    key;
 
    key = event->message & charCodeMask;
    
    // just check to see if we want to quit...
    
    if ( event->modifiers & cmdKey ) {      /* Command key down? */
        HandleMenuCommand(MenuKey(key));
    } 
}
 
 
void HandleMenuCommand(long menuResult)
{
    short       menuID;
    short       menuItem;
    Str255      daName;
    DialogPtr   theDialog ; 
    short       itemHit ;
    SFTypeList  myTypes = { 'PICT' } ;
    FSSpec      theFSSpec ;
    PicHandle   thePicture ;
    OSErr       err ;
    short       theRef ;
    
    StandardFileReply   theSFReply ;
 
    menuID = HiWrd(menuResult);
    menuItem = LoWrd(menuResult);
    switch ( menuID ) {
        case mApple:
            switch ( menuItem ) {
                case iAbout:
                    theDialog = GetNewDialog ( 128, nil, (WindowPtr)-1 );
                    do {
                        ModalDialog ( nil, &itemHit );
                    } while( itemHit != ok ) ;
                    DisposDialog ( theDialog );
                    break;
                    
                default:
                    GetItem(GetMHandle(mApple), menuItem, daName);
                    (void) OpenDeskAcc(daName);
                    break;
            }
            break;
        case mFile:
            switch ( menuItem ) {
                case iOpen:
                    // Get the file name to open
                    StandardGetFile( nil, 1, myTypes, &theSFReply ) ;
                    
                    // did the user cancel?
                    if(!theSFReply.sfGood)
                        break ;
                    
                    // open the file
                    err = FSpOpenDF( &theSFReply.sfFile, fsRdPerm, &theRef ) ;
                    
                    if( err != noErr )
                        break ;     // should handle this properly
                        
                    thePicture = DoReadPICT( theRef, &err ) ;
                    
                    if( err != noErr )
                        break ;     // should handle this properly
                
                    // display the contents
                    err = DoCreateWindow( thePicture ) ;
                    
                    break ;
                    
                case iClose:
                    DisposeWindow ( FrontWindow() );
                    break ;
                case iQuit:
                    gQuitFlag = true;
                    break;
            }
            break;
            
        case mPalette:
            switch ( menuItem ) {
                case iUsePictPalette :
                    // toggle the check mark and the global boolean
                    gUsePictPalette = !gUsePictPalette ;
                    CheckItem ( GetMHandle ( mPalette ), iUsePictPalette, gUsePictPalette );
                    break ;
            }
            break ;
            
        case 131:
            if( menuItem == 1 )
                if( FrontWindow() != nil )
                    ;   // add test code here
                    
            break; 
 
    }
    HiliteMenu(0);      // Unhighlight whatever MenuSelect or MenuKey hilited
}
 
void AdjustMenus( void ) 
{
    WindowPtr   theWindow ;
    theWindow = FrontWindow() ;
    if( theWindow != nil ) {
        EnableItem ( GetMHandle ( mFile ), iClose );
    }
    else {
        DisableItem ( GetMHandle ( mFile ), iClose );
    }
    // make sure the check marks are correct
    CheckItem ( GetMHandle ( mPalette ), iUsePictPalette, gUsePictPalette );
}
 
PicHandle DoReadPICT( short theRef, OSErr *theErr ) 
{
    long        theFileSize ;
    PicHandle   thePicture ;
    
    // pict files have a 512 byte header at the front - we dont care about this
    // we can find the size of the pict by subtracting 512 bytes from the length
    // of the file.  We then want to resize the handle to that and read the data
    // into the resized handle.
    
    if(( *theErr = GetEOF( theRef, &theFileSize )) != noErr ) {
        FSClose( theRef ) ;
        return nil ; 
    }
    
    if(( *theErr = SetFPos( theRef, fsFromStart, 512)) != noErr ) {
        FSClose( theRef ) ;
        return nil ; 
    }
 
    theFileSize -= 512 ;
    
    thePicture = (PicHandle)NewHandle( theFileSize ) ;
    if( thePicture == nil ) {
        FSClose( theRef ) ;
        *theErr = MemError() ;
        return nil ;        // what ever the mem manager error was
    }
    
    HLock( (Handle)thePicture ) ;
    *theErr = FSRead( theRef, &theFileSize, (Ptr)*thePicture ) ;
    HUnlock(  (Handle)thePicture ) ;
    
    if( *theErr != noErr ) {
        FSClose( theRef ) ;
        return nil ; 
    }
 
    return thePicture ; 
}
 
OSErr DoCreateWindow( PicHandle thePicture )
{
 
    Rect        theRect ;
    OSErr       theErr ;
    GWorldPtr   theNewWorld ;
    CGrafPtr    savedPort ;
    GWorldPtr   savedGWorld ;
    WindowPtr   theWindow ;
    GDHandle    oldDevice ;
    
    PictInfo        thePictInfo ;
    PaletteHandle   thePictPalette = nil ;
    CTabHandle      thePictCTab = nil ;
    
    // make an offscreen environment and image the pict into this
    // Make a window the size of the pict
    // store a reference to the GWorld in the Refcon of the window
    // invalidate the window content area.
    
    theRect.top = (**thePicture).picFrame.top ;
    theRect.left = (**thePicture).picFrame.left ;
    theRect.bottom = (**thePicture).picFrame.bottom ;
    theRect.right = (**thePicture).picFrame.right ;
    
    // to we want to attempt to sample the picture... 
    if( gUsePictPalette ) {
    
        // use the picture utilities to get the palette for the window
        theErr = GetPictInfo( thePicture, &thePictInfo, returnColorTable, 256, systemMethod, 0) ;
        
        // set up the palette and color table for later use
        thePictPalette = NewPalette( 256, thePictInfo.theColorTable, pmTolerant, 0x1000 ) ;
        thePictCTab = thePictInfo.theColorTable ;
    }
    
    // we are only dealing with eight bit images here
    // hence the requirement for the picture utils package to 
    // return 256 colors, and we will create a gWorld 8 bits deep
    
    theErr = NewGWorld( &theNewWorld, 8, &theRect, thePictCTab, nil, 0L ) ;
    
    if( theErr != noErr ) 
        return theErr ;
    
    // save the world
    GetGWorld( &savedPort, &oldDevice ) ;
    SetGWorld( theNewWorld, nil ) ;
    
    
    RGBForeColor( &kRGBBlack ) ;        // ensure the fg and bg colors are 
    RGBBackColor( &kRGBWhite ) ;        // as anticipated
    EraseRect( &theRect ) ;             // clear the area for the pict
    PenMode( srcCopy ) ;                // ensure the t/f mode is as expected
 
    // render the image into the offscreen buffer
    DrawPicture( thePicture, &theRect ) ;
    
    SetGWorld( savedPort, oldDevice ) ;
    
    // create the window
    OffsetRect( &theRect, gStaggerPos.h, gStaggerPos.v) ;
    gStaggerPos.h += 16 ;
    gStaggerPos.v += 16 ;       // heh - should roll these around, but you wont 
                                // create more than a couple of windows, will you  :-)
                                 
    theWindow  = NewCWindow( nil, &theRect, "\pplayTime", true, 
                                documentProc, (WindowPtr)-1, true, (long)theNewWorld ); 
                
    // and if we set up the palette earlier assign it to the window             
    if( thePictPalette != nil ) {
        SetPalette ( theWindow, thePictPalette, true );
    }
    
    ActivatePalette ( theWindow );  
    
    // make sure it is visible
    ShowWindow( theWindow ) ;
    
    SetGWorld( (CGrafPtr)theWindow, nil ) ;
    
    // invalidate the content region of the window - we don't do any drawing to it here.
    InvalRect ( &theRect );
    
    SetGWorld( savedPort, oldDevice ) ;
}