CodecTestMain.c

/*
    File:       CodecTestMain.c
 
    Contains:   
 
    Written by: Mark Krueger    
 
    Copyright:  Copyright © 1992-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                7/29/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
 
 
#ifdef  THINK_C
//#define   OpenStdCompression  OPENSTDCOMPRESSION
#endif
 
 
#include    <QuickTimeComponents.h>
#include    <ImageCompression.h>
#include    "DrawTextCodec.h"
 
#define dangerousPattern
 
//#define   DONT_SHOW_PICTURE
//#define   DONT_DO_PREVIEW
 
#include    <Types.h>
#include    <Files.h>
#include    <Quickdraw.h>
#include    <Packages.h>
#include    <Memory.h>
#include    <Fonts.h>
#include    <Events.h>
#include    <OSUtils.h>
#include    <ToolUtils.h>
#include    <Menus.h>
#include    <Dialogs.h>
#include    <stdio.h>
#include    <Errors.h>
#include    <Scrap.h>
#include    <Desk.h>
#include    <string.h>
#include    <GestaltEqu.h>
#include    <Resources.h>
#include    <Finder.h>
#include    <palettes.h>
#include    <PictUtils.h>
#include    <QDOffscreen.h>
#include    <Windows.h>
#include    <FixMath.h>
#include    <ImageCodec.h>
 
#ifndef THINK_C
#include    <Strings.h>
#endif
 
 
#include    <ImageCompression.h>
 
 
 
#define     appleMenuID     128
#define     fileMenuID      129
#define     editMenuID      130
 
 
#define     M_OPEN          1
#define     M_CLOSE         3
#define     M_SAVE          4
#define     M_COMP          6
#define     M_QUIT          8
 
#define     M_COPY          4
#define     M_PASTE         5
#define     M_FIT           10
 
 
Boolean     gDitherFlag  = false;
StandardFileReply   gOriginalSFR;   
short           gOriginalFile;
Cursor          **gWatch;
short           gCompressedFile;
Boolean         gExitFlag = false;
MenuHandle      gMenus[3];          // our menus
CWindowPtr      gActiveWindow = nil;
CWindowPtr      gOrigWindow = nil;
CWindowPtr      gCompWindow = nil;
Rect            gOriginalPicFrame;
Rect            gZoomedPictureFrame;
Boolean         gZoomed = false;
Boolean         gFitToWindow = true;
Boolean         gHasNewStdFile = false;
PicHandle       gOriginalPicture = nil;
Boolean         gCompressed = false;
Boolean         gSevenOh = false;
short           gDepth = 1;
 
 
ComponentInstance   gSCComponent;
SCParams            gSCParams;
 
Boolean         gDidError = false;
 
GWorldPtr   gworld,compgworld;
int Initialize();
void Error(char *msg);
pascal OSErr
Progress(short progressMsg,Fixed progressPercent,long refcon);
int DoCompression(CWindowPtr    window);
void DoError();
void FitRect(Rect *rect,short w,short h);
void DoOpen(FSSpec *fsp);
void DoClose(CWindowPtr w);
void DoSave(CWindowPtr w) ;
void FixMenus();
void DoPaste();
void DoCopy(CWindowPtr w);
void DoUpdate(CWindowPtr w);
void DoSizeWindow(CWindowPtr wind,short h,short v,Boolean fup);
void DoZoom(WindowPtr wind);
void DoGrow(WindowPtr wind,Point *where);
void DoCommand(long mResult);
 
/************************************************
 *
 *  Set up application environment.
 *
 ************************************************/
 
 
int Initialize()
{
    Ptr size;
    
    size = GetApplLimit();
    SetApplLimit(size - 32*1024);       /* make room on stack so Quickdraw can do big pictures */
    MaxApplZone();
 
    /*  initialize managers */
 
    InitGraf(&qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    InitDialogs(nil);
    InitCursor();
    ErrorSound(nil);
    
    /*  install menus */
    
    if ( (gMenus[0] = GetMenu(appleMenuID)) == nil )
        return(-1);
    AppendResMenu(gMenus[0], (ResType) 'DRVR');
    InsertMenu(gMenus[0], 0);
    if ( (gMenus[1] = GetMenu(fileMenuID)) == nil )
        return(-1);
    InsertMenu(gMenus[1], 0);
    if ( (gMenus[2] = GetMenu(editMenuID)) == nil )
        return(-1);
    InsertMenu(gMenus[2], 0);
    DrawMenuBar();
    if ( (gWatch =  GetCursor(watchCursor)) == nil )
        return(-1);
    HNoPurge((Handle)gWatch);
    return(0);
}
 
 
/************************************************
 *
 *  Report errors as needed.
 *
 ************************************************/
 
void Error(char *msg)
{
    SysBeep(1);
    ParamText("\pError:",c2pstr(msg),nil,nil);  /* oops da baby */
    Alert(128,nil);
}
 
 
/************************************************
 *
 *  Progress proc called from the Image Compression manager.
 *
 ************************************************/
 
 
pascal OSErr
Progress(short progressMsg,Fixed progressPercent,long refcon)
{
    OSErr  result = noErr;
    short kind;
    Handle h;
    Rect r;
    CGrafPtr savePort,wmgPort;
    GDHandle saveGD;
    static DialogPtr progressDialog = 0;
    KeyMap  keys;
 
    switch (progressMsg) {
    
    case codecProgressOpen:
    
        progressDialog = 0;
        GetGWorld(&savePort,&saveGD);
        GetCWMgrPort(&wmgPort);
        SetGWorld(wmgPort,nil);
        if ( refcon != -1 && (progressDialog = GetNewDialog(5002, 0, (WindowPtr)-1)) != nil ) { 
            ShowWindow((WindowPtr)progressDialog);
            SetGWorld((CGrafPtr)progressDialog,nil);
            DrawDialog(progressDialog);
            GetDialogItem(progressDialog, 1, &kind, &h, &r);
            InsetRect(&r, -1, -1);
            FrameRect(&r);
            InsetRect(&r, 1, 1);
        }
        SetGWorld(savePort,saveGD);
        break;
 
    case codecProgressUpdatePercent:
    
        if ( progressDialog ) {
            GetGWorld(&savePort,&saveGD);
            SetGWorld((CGrafPtr)progressDialog,nil);
            GetDialogItem(progressDialog, 1, &kind, &h, &r);
            
            FillRect(&r,&qd.gray);
            r.right = r.left + FixRound( FixMul(progressPercent, FixRatio(r.right-r.left,1)));
            PaintRect(&r);
            SetGWorld(savePort,saveGD);
        }   
 
        /* check for command period - not the best way, but it works */
 
        GetKeys(keys);
        if ( (keys[1] & 0x8000) && ((0x800000 & keys[1]) || (0x2000000 & keys[1])  ) )
            result = codecAbortErr;
        break;
    
    case codecProgressClose:
    
        if ( progressDialog )
            DisposeDialog(progressDialog);
        progressDialog = 0;
        break;
    }
    return(result);
}
 
    
/************************************************
 *
 *  Allow the user to specify compression and an output file, and then
 *  compress the picture and save the result in that file.
 *
 ************************************************/
 
 
int DoCompression(CWindowPtr    window)
{
 
    /* StdFile stuff */
    
    CGrafPtr    savePort;
    GDHandle    saveGD;
 
    /* for sepecifying compression */
    
    Rect        pictureFrame;
    OSErr       result;
    Point       where;
    ImageDescriptionHandle desc = nil;
    Ptr data = nil;
    long    cdsize;
    ICMProgressProcRecord   *progP,progressRec;
    Str255      buf;
    GrafPtr     wmPort;
    
    progressRec.progressProc = NewICMProgressProc(Progress);
    progressRec.progressRefCon = 0;
    progP = &progressRec;
        
 
    if ( window == nil )
        return -1;
    pictureFrame = ((CGrafPtr)window)->portRect;
 
    /************************************************
     *
     *      Ask how the user wants to compress it.
     *
     ************************************************/
 
 
    
    SetCursor(&qd.arrow);
    if (SCSetTestImagePixMap(gSCComponent,gworld->portPixMap,&gworld->portRect,0))
        goto done;
 
 
    GetWMgrPort(&wmPort);
    SetPort(wmPort);
    where.h = where.v = -2;     // position dialog on the best device
    if (SCGetCompression(gSCComponent,&gSCParams,where))
        goto done;
    
    /************************************************
     *
     *      Ask her for the name of the new file.
     *
     ************************************************/
    
 
    SetCursor(*gWatch);
 
 
    if ( (result=GetMaxCompressionSize(gworld->portPixMap,&gworld->portRect,
            gSCParams.depth,gSCParams.spatialQuality,gSCParams.theCodecType,
            gSCParams.theCodec,&cdsize)) != noErr ) {
        Error("getting max comp size");
        goto done;
    }       
    if ( (data=NewPtr(cdsize)) == nil ) {
        Error("no mem for picture");
        goto done;
    }       
    desc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
    if ( desc == nil ) {
        DisposePtr(data);
        Error("no mem for picture");
        goto done;
    }       
        
    if ( (result=FCompressImage(gworld->portPixMap,&gworld->portRect,
                gSCParams.depth,gSCParams.spatialQuality,gSCParams.theCodecType,
                gSCParams.theCodec,nil,0,0,nil,progP,
                desc,data)) != noErr   ) {
        DisposePtr(data);
        DisposeHandle((Handle)desc);
        if ( result != codecAbortErr ) 
            Error("compressing picture");
        goto done;
    }   
    
    
    NumToString((*desc)->dataSize,buf);
    ParamText("\pCompressed to ",buf,"\pBytes",nil);
    Alert(128,nil);
    GetGWorld(&savePort,&saveGD);
    SetGWorld(compgworld,nil);
    
    if ( (result=DecompressImage(data,desc,compgworld->portPixMap,
                    &gworld->portRect,&compgworld->portRect,ditherCopy,nil)) != noErr ) {
        DisposePtr(data);
        DisposeHandle((Handle)desc);
        Error("compressing picture");
        goto done;
    }   
    DisposePtr(data);
    DisposeHandle((Handle)desc);
    SetGWorld(gCompWindow,nil);
    InvalRect(&gCompWindow->portRect);
    SetGWorld(savePort,saveGD);
done:
    gDidError = false;
    SetCursor(&qd.arrow);
    
    return(result);
}
 
    
    
    
 
 
void DoError()
{
    CGrafPtr    savePort;
    GDHandle    saveGD;
    RGBColor    opColor;
    
    
    GetGWorld(&savePort,&saveGD);
    SetGWorld(compgworld,nil);
    if ( !gDidError ) {
        gDidError = true;
        opColor.red = opColor.green = opColor.blue = 0;
        OpColor(&opColor);
        CopyBits((BitMap *)*gworld->portPixMap,(BitMap *)*((CGrafPtr)compgworld)->portPixMap,
            &gworld->portRect,&compgworld->portRect,subPin,nil);
    }
    opColor.red = opColor.green = opColor.blue = 0xffff;
    OpColor(&opColor);
    CopyBits((BitMap *)*compgworld->portPixMap,(BitMap *)*((CGrafPtr)compgworld)->portPixMap,
        &compgworld->portRect,&compgworld->portRect,addPin,nil);
    SetGWorld(gCompWindow,nil);
    InvalRect(&gCompWindow->portRect);
    SetGWorld(savePort,saveGD);
}
 
 
    
/************************************************
 *
 *  Massage a rectangle to fit on a device's screen.
 *
 ************************************************/
 
 
void FitRect(Rect *rect,short w,short h)
{
    short   n;
    Rect    dRect;
    GDHandle    gd;
    
//  dRect = *rect;
    gd = GetGDevice();
    dRect =(*gd)->gdRect;
    dRect.top += 40;                                /* make way for title bar */
    InsetRect(&dRect,16,16);
 
    if ( w < (dRect.right-dRect.left) &&  h < (dRect.bottom-dRect.top) ) {
         dRect.right = dRect.left + w;
         dRect.bottom = dRect.top + h;
    } else if ( gFitToWindow ) {
        n = dRect.top + ((dRect.right -dRect.left) * h)/w;
        if ( n > dRect.bottom )
            dRect.right = dRect.left +((dRect.bottom -dRect.top) * w)/h;
        else 
            dRect.bottom = n;
    }
    *rect = dRect;
 
}
 
 
    
/************************************************
 *
 *  Ask the user for a pict file to open and open it.
 *
 ************************************************/
 
 
void DoOpen(FSSpec *fsp)
{
    OpenCPicParams  originalPicHeader;
    SFTypeList  types = { 'PICT',0 };
    OSErr       result = noErr;
    long        size;
    CGrafPtr    savePort;
    GDHandle    saveGD;
    Rect        rect;
    
    
    if ( fsp == nil ) {
        if ( gHasNewStdFile )
            StandardGetFile(nil,1,types,&gOriginalSFR);
        else {
            SFReply     osfr;
            Point   pt = {100,100};
            
            SFGetFile(pt,(ConstStr255Param)"",nil,1,types,nil,&osfr);
            gOriginalSFR.sfGood = osfr.good;
            gOriginalSFR.sfReplacing = osfr.copy;
            gOriginalSFR.sfType = osfr.fType;
            if ( osfr.good ) 
                FSMakeFSSpec(osfr.vRefNum,0L,osfr.fName,&gOriginalSFR.sfFile);
        }
        if ( !gOriginalSFR.sfGood  ) {
            return ;
        }
    } else {
        gOriginalSFR.sfFile = *fsp;
    }
        
    SetCursor(*gWatch);
    if ((result=FSpOpenDF(&gOriginalSFR.sfFile,fsRdPerm,&gOriginalFile)) != noErr ) {
        goto done;
    }
 
    
    
    /************************************************
     *
     *  Get the picture frame, to see how big of a window to make.
     *
     ************************************************/
 
    if ( (result=GetPictureFileHeader(gOriginalFile,&gOriginalPicFrame,&originalPicHeader)) != noErr ) {
        FSClose(gOriginalFile);
        goto done;
    }
 
 
    /************************************************
     *
     *  Figure out the best screen to show the picture on, and if
     *  it doesn't fit, then scale it to fit while maintaining aspect ratio.
     *
     ************************************************/
    
    
    SetRect(&gZoomedPictureFrame,-32767,-32767,32767,32767);
    FitRect(&gZoomedPictureFrame,gOriginalPicFrame.right-gOriginalPicFrame.left,
        gOriginalPicFrame.bottom-gOriginalPicFrame.top);
    gZoomed = false;
 
    /************************************************
     *
     *  Create a window for the picture, and set our port to it.
     *
     ************************************************/
 
    if ( (gOrigWindow = (CWindowPtr)NewCWindow(nil,&gZoomedPictureFrame,gOriginalSFR.sfFile.name,true,
                zoomDocProc,(WindowPtr)-1,true,0)) == nil ) {
        FSClose(gOriginalFile);
        result = -1;
        goto done;
    }
    rect = gZoomedPictureFrame;
//  OffsetRect(&rect,(rect.right-rect.left)+10,0);
    OffsetRect(&rect,50,50);
    if ( (gCompWindow = (CWindowPtr)NewCWindow(nil,&rect,"\pCompressed",true,
                zoomDocProc,(WindowPtr)-1,true,0)) == nil ) {
        FSClose(gOriginalFile);
        result = -1;
        goto done;
    }
    SetPort((GrafPtr)gActiveWindow);
    if ( GetEOF(gOriginalFile,&size) == noErr ) {
        size -= 512;
        if ( gOriginalPicture = (PicHandle)NewHandle(size) ) {
            HLock((Handle)gOriginalPicture);
            SetFPos(gOriginalFile,fsFromStart,512);
            FSRead(gOriginalFile,&size,*(Handle)gOriginalPicture);
            HUnlock((Handle)gOriginalPicture);
            HPurge((Handle)gOriginalPicture);
        }
    }   
    rect = gZoomedPictureFrame; 
    OffsetRect(&rect,-rect.left,-rect.top);
    
    if ( (result=NewGWorld(&gworld,gDepth,&rect,nil,nil,0)) != 0 ) {
        if ( (result=NewGWorld(&gworld,gDepth,&rect,nil,nil,8)) != 0 ) {
            Error("No mem for gworld");
            goto done;
        }
    }
    if ( (result=NewGWorld(&compgworld,gDepth,&rect,nil,nil,0)) != 0 ) {
        if ( (result=NewGWorld(&compgworld,gDepth,&rect,nil,nil,8)) != 0 ) {
            Error("No mem for gworld");
            DisposeGWorld(gworld);
            gworld = nil;
            goto done;
        }
    }
    GetGWorld(&savePort,&saveGD);
    SetGWorld(gworld,nil);
    if ( gOriginalPicture && *gOriginalPicture) {
        HNoPurge((Handle)gOriginalPicture);
        if ( (result=DrawTrimmedPicture(gOriginalPicture,&rect,nil,gDitherFlag,nil)) != noErr  && result != codecAbortErr) {
            SysBeep(1);
        }
        HPurge((Handle)gOriginalPicture);
    }else {
        if ( (result=DrawTrimmedPictureFile(gOriginalFile,&rect,nil,gDitherFlag,nil)) != noErr  && result != codecAbortErr) {
            SysBeep(1);
        }
    }
    
    SetGWorld(compgworld,nil);
    EraseRect(&compgworld->portRect);
    SetGWorld(savePort,saveGD);
    SetWRefCon((WindowPtr)gCompWindow,(long)compgworld);
    SetWRefCon((WindowPtr)gOrigWindow,(long)gworld);
    FSClose(gOriginalFile);
    if ( gOriginalPicture ) {
        DisposeHandle((Handle)gOriginalPicture);
        gOriginalPicture = nil;
    }
done:
    SetCursor(&qd.arrow);
    if ( result ) {
        SysBeep(1);
    }
 
}
 
    
/************************************************
 *
 *  Close the window and the file and get rid of any temporary file we may have.
 *
 ************************************************/
 
 
void DoClose(CWindowPtr w)
{
    GWorldPtr   gw;
    
    if ( w == nil )
        return;
        
    gw = (GWorldPtr)GetWRefCon((WindowPtr)w);
    if ( gw ) {
        DisposeGWorld(gw);
    }
    CloseWindow((WindowPtr)w);
    if  ( w == gActiveWindow ) {
        gActiveWindow = nil;
    }
    if ( w == gOrigWindow ) 
        gOrigWindow = nil;
    if ( w == gCompWindow ) 
        gCompWindow = nil;
    return;
}
 
void DoSave(CWindowPtr w) 
{
 
    long    l,k;
    OSErr   e = 0;
    PicHandle   pict = nil;
    long    i;
    short   f = 0;
    static Str255   name = "\pPICT";
    StandardFileReply   sfr;
    CGrafPtr    savePort;
    GDHandle    saveGD;
    GWorldPtr   gw;
    long zero = 0;
    
        
    gw = (GWorldPtr)GetWRefCon((WindowPtr)w);
    if ( gw == nil )
        return;
    StandardPutFile((ConstStr255Param)"",name,&sfr);
    if ( sfr.sfGood ) { 
        GetGWorld(&savePort,&saveGD);
        SetGWorld(gw,nil);
        pict = OpenPicture(&gw->portRect);
        ClipRect(&gw->portRect);
        CopyBits((BitMap *)*gw->portPixMap,(BitMap *)*((CGrafPtr)gw)->portPixMap,
            &gw->portRect,&gw->portRect,ditherCopy,nil);
        ClosePicture();
        SetGWorld(savePort,saveGD);
        if ( (l=GetHandleSize((Handle)pict)) <= 10 ) {
            DisposeHandle((Handle)pict);
            Error("Making Pict");
            return;
        }
        FSpDelete(&sfr.sfFile);
        if ( (e=FSpCreate(&sfr.sfFile,'ppxi','PICT',0)) != noErr  ) {
            Error("Creating file");
            return;
        }
        if ( (e=FSpOpenDF(&sfr.sfFile,fsRdWrPerm,&f)) != noErr ) {
            Error("Opening file");
            goto bail;
        }
        SetFPos(f,fsFromStart,0);
        k = 4;
        for ( i=0; i < 512/4; i++ ) {
            if ( (e=FSWrite(f,&k,(char *)&zero)) != noErr ) {
                Error("Writing file");
                goto bail;
            }
        }
        HLock((Handle)pict);
        if ( (e=FSWrite(f,&l,(Ptr)*pict)) != noErr)  {
            Error("Writing file");
            goto bail;
        }
        SetEOF(f,l+512);
 
bail:   
        if ( pict ) 
            DisposeHandle((Handle)pict);
        if ( f ) 
            FSClose(f);
        if ( e )
            FSpDelete(&sfr.sfFile);
        FlushVol(nil,sfr.sfFile.vRefNum);
    }
}
 
 
 
    
/************************************************
 *
 *  Fix the menu hiliting based on conditions.
 *
 ************************************************/
 
 
void FixMenus()
{
    
    if ( gActiveWindow == nil ) {
        EnableItem(gMenus[1],M_OPEN);
        DisableItem(gMenus[1],M_CLOSE);
        DisableItem(gMenus[1],M_SAVE);
        DisableItem(gMenus[2],M_COPY);
    } else  { 
        DisableItem(gMenus[1],M_OPEN);
        EnableItem(gMenus[1],M_CLOSE);
        EnableItem(gMenus[1],M_SAVE);
//      EnableItem(gMenus[2],M_COPY);
    }
    
    if ( gOrigWindow != nil && gCompWindow != nil ) 
        EnableItem(gMenus[1],M_COMP);
    else
        DisableItem(gMenus[1],M_COMP);
    EnableItem(gMenus[2],M_FIT);
//  if ( GetScrap(nil,'PICT',&offset) > 0  ) 
//      EnableItem(gMenus[2],M_PASTE);
//  else
        DisableItem(gMenus[2],M_PASTE);
}
 
    
/************************************************
 *
 *  Paste the PICT from the clip board into a new window, making a temporary
 *  file for it.
 *
 ************************************************/
 
 
void DoPaste()
{
}
 
    
/************************************************
 *
 *  Copy the open PICT onto the clip board.
 *
 ************************************************/
 
 
void DoCopy(CWindowPtr w)
{
    #pragma unused(w)
}
    
 
/************************************************
 *
 *  Update the window from the PICT file.
 *
 ************************************************/
 
void DoUpdate(CWindowPtr w)
{
    CGrafPtr        savePort;
    GDHandle        saveGD;
    Rect        srcRect;
    GWorldPtr   gw;
 
 
    if ( w == nil ) 
        return;
    SetCursor(*gWatch);
    GetGWorld(&savePort,&saveGD);
    SetGWorld((CGrafPtr)w,nil);
    
    gw = (GWorldPtr)GetWRefCon((WindowPtr)w);
    if ( gw  ) { 
        srcRect = gw->portRect;
        BeginUpdate((WindowPtr)w);
        CopyBits((BitMap *)*gw->portPixMap,(BitMap *)*((CGrafPtr)w)->portPixMap,
            &srcRect,&((CGrafPtr)w)->portRect,ditherCopy,nil);
    
        EndUpdate((WindowPtr)w);
    }
    SetGWorld(savePort,saveGD);
    SetCursor(&qd.arrow);
 
}
 
    
/************************************************
 *
 *  Resize the window and remember the old size, and force it to update.
 *
 ************************************************/
 
 
void DoSizeWindow(CWindowPtr wind,short h,short v,Boolean fup)
{
    GrafPtr savePort;
 
    gZoomed = false;
    GetPort(&savePort);
    SetPort((GrafPtr)wind);
    SizeWindow((WindowPtr)wind,h,v,false);
    gZoomedPictureFrame = ((CGrafPtr)wind)->portRect;
    LocalToGlobal((Point *)&gZoomedPictureFrame.top);
    LocalToGlobal((Point *)&gZoomedPictureFrame.bottom);
    if ( fup )
        InvalRect(&((CWindowPtr)wind)->portRect);
    SetPort(savePort);
}
 
    
/************************************************
 *
 *  Handle clicks in the window zoom box.
 *
 ************************************************/
 
void DoZoom(WindowPtr wind)
{
    Rect        rect;
    Rect        saveRect;
    GrafPtr     savePort;
    KeyMap      keys;
    Boolean     doOriginal;
    
    GetPort(&savePort);
    SetPort((GrafPtr)wind);
 
    GetKeys(keys);
    doOriginal = (( keys[1] & 4 ) != 0);        /* option key */
 
    if ( doOriginal ) {
        gZoomed = false;
        FitRect(&gZoomedPictureFrame,gOriginalPicFrame.right-gOriginalPicFrame.left,
            gOriginalPicFrame.bottom-gOriginalPicFrame.top);
    } else {
        if ( gZoomed ) {
            gZoomed = false;
        } else {
            rect = gZoomedPictureFrame;
            rect.top += 16;                     /* make way for title bar */
            InsetRect(&rect,16,16);
            ShowHide(wind,0);
            MoveWindow(wind,rect.left,rect.top,true);
            saveRect = gZoomedPictureFrame;
            DoSizeWindow((CWindowPtr)wind,rect.right-rect.left,rect.bottom-rect.top,true);
            gZoomedPictureFrame = saveRect;
            gZoomed = true;
            goto done;
        }
    }
    ShowHide(wind,0);
    MoveWindow(wind,gZoomedPictureFrame.left,gZoomedPictureFrame.top,true);
    DoSizeWindow((CWindowPtr)wind,gZoomedPictureFrame.right-gZoomedPictureFrame.left,
        gZoomedPictureFrame.bottom-gZoomedPictureFrame.top,true);
done:
    ShowHide(wind,1);
    SetPort(savePort);
}
 
 
 
/************************************************
 *
 *  Grow the window (constrain aspect ratio if option key pressed.
 *
 ************************************************/
 
 
void DoGrow(WindowPtr wind,Point *where)
{
    unsigned long   size;
    Rect            sizeRect;
    GrafPtr         savePort;
    short           h,v;
    short           height = gOriginalPicFrame.bottom - gOriginalPicFrame.top;
    short           width = gOriginalPicFrame.right - gOriginalPicFrame.left;
    KeyMap          keys;
    short           minH = 128,minV = 128,maxH = 4096,maxV = 4096;
    Boolean         maintainAspect;
    Rect            rect;
    
    
    GetPort(&savePort);
    SetPort((GrafPtr)wind);
    GetKeys(keys);
    maintainAspect = (( keys[1] & 4 ) != 0);
    if ( maintainAspect ) {
        Rect    oRect;
        
        rect = ((CGrafPtr)wind)->portRect;
        LocalToGlobal((Point *)&rect.top);
        LocalToGlobal((Point *)&rect.bottom);
        oRect = rect;
        if ( width > 2048 || height > 2048 )
            FitRect(&rect,width,height);
        else if ( width < 1024 && height < 1024 )
            FitRect(&rect,width<<4,height<<4);
        else
            FitRect(&rect,width<<2,height<<2);
        maxH = (rect.right - rect.left);
        maxV = (rect.bottom - rect.top);
        if ( maxV < minV || maxH < minH ) {
            minV = maxV;
            minH = maxH;
        }
        maxV = (maxH * height)/width;
        minV = (minH * height)/width;
    }
    SetRect(&sizeRect,minH,minV,maxH,maxV);
    if ( (size = GrowWindow(wind,*where,&sizeRect))  != 0 ) {
        h = size & 0xffff;
        v = size >> 16;
        if ( maintainAspect )
            v = (h * height)/width;
        DoSizeWindow((CWindowPtr)wind,h,v,true);
    }
    SetPort(savePort);
    FixMenus();
}
 
/************************************************
 *
 *  Handle menu commands.
 *
 ************************************************/
 
void DoCommand(long mResult)
{
    short       theMenu, theItem;
    GrafPtr savePort;
    Str255      daName;
 
    theItem = ((mResult) & 0xFFFF);
    theMenu = (((mResult) >> 16) & 0xFFFF);     /* This is the resource ID */
 
    switch (theMenu) {
    case appleMenuID:
        if ( theItem != 1 ) {
            GetMenuItemText(gMenus[0], theItem, daName);
            GetPort(&savePort);
            (void) OpenDeskAcc(daName);
            SetPort(savePort);
        }
        break;
 
    case fileMenuID:
        {
            switch (theItem) {
            case M_OPEN:
                DoOpen(nil);
                break;
            case M_CLOSE:
                DoClose(gActiveWindow);
                break;
            case M_COMP:
                DoCompression(gActiveWindow);
                break;
            case M_SAVE:
                DoSave(gActiveWindow);
                break;
            case M_QUIT:
                gExitFlag = true;           /* Request exit */
                break;
            }
            FixMenus();
        }
        break;
    case editMenuID:
        if ( !SystemEdit(theItem-1) ) {
            switch ( theItem ) {
            case M_COPY:
                DoCopy(gActiveWindow);
                break;
            case M_PASTE:
                DoPaste();
                break;
            case M_FIT:
                DoError();
                break;
            default:
                break;
            }
        }
        FixMenus();
        break;
    default:
        break;
    }
    HiliteMenu(0);
}
 
extern pascal ComponentResult DRAWTEXTCODEC(ComponentParameters *params,Handle storage);
 
/************************************************
 *
 *  Our program.
 *
 ************************************************/
 
void main()
{
    GrafPtr savePort;
    EventRecord myEvent;
    Rect        dragRect;
    WindowPtr   whichWindow;
    long        resp;
 
 
    if ( Initialize() ) {
        SysBeep(1);
        ExitToShell();
    }
    
    if ( Gestalt(gestaltSystemVersion, &resp) != noErr || resp < 0x700 ) {
        gSevenOh = false;
    } else {
        gSevenOh = true;
    }
    
    /*  Check to make sure the image compression manager is installed. */
 
    if ( Gestalt(gestaltCompressionMgr, &resp) != noErr || resp < 15 ) {
        SysBeep(1);
        ExitToShell();
    }
 
    /*  Check to see if new style standard file is around. */
 
    gHasNewStdFile = ( Gestalt(gestaltStandardFileAttr,&resp) == 0 );
 
    /*  Install and open the standard compression component. */
 
    gSCComponent = OpenDefaultComponent('scdi',0);
    if (!gSCComponent) {
        SysBeep(1);
        ExitToShell();
    }
    
    /*  Set up the first defaults for compression dialog. */
    
    gSCParams.flags = scListEveryCodec;
    gSCParams.theCodecType = 'dtxt';
    gSCParams.theCodec = anyCodec;
    gSCParams.spatialQuality = codecNormalQuality;
    gSCParams.temporalQuality = 0;
    gSCParams.depth = 32;
 
 
 
    /* install CoDec to test */
 
 
 
     {
        ComponentDescription td;
    
        Handle  cname = NewHandle(sizeof(CODEC_NAME));
        Handle  dname = NewHandle(sizeof(CODEC_NAME));
    
        td.componentType = 'imco';
        td.componentSubType = 'dtxt';
        td.componentManufacturer = 'mark';
        td.componentFlags = codecInfoDoes1;
        td.componentFlagsMask = 0;
        
        
        BlockMove(CODEC_NAME,*cname,sizeof(CODEC_NAME));
        RegisterComponent(&td,NewComponentRoutineProc(DRAWTEXTCODEC), 0,cname,nil, nil);
            
        td.componentType = 'imdc';
        td.componentFlags = codecInfoDoes1;
        BlockMove(CODEC_NAME,*dname,sizeof(CODEC_NAME));
        RegisterComponent(&td,NewComponentRoutineProc(DRAWTEXTCODEC), 0,dname,nil, nil);
    }
 
 
    FixMenus();
    DoOpen(nil);
    
    while (!gExitFlag ) {
        
        if ( WaitNextEvent( everyEvent, &myEvent, 1, nil) == 0 )
            continue;
        
        switch (myEvent.what) {
        case mouseDown:
            switch ((short)FindWindow(myEvent.where, &whichWindow)) {
            case inSysWindow:
                SystemClick(&myEvent, whichWindow);
                FixMenus();
                break;
 
            case inMenuBar:
                DoCommand(MenuSelect(myEvent.where));
                break;
 
            case inDrag:
                GetPort(&savePort);
                SetPort((GrafPtr)whichWindow);
                SetRect(&dragRect, 4, 20 + 4, qd.screenBits.bounds.right-4, qd.screenBits.bounds.bottom-4);
                DragWindow(whichWindow, myEvent.where, &dragRect);
                gZoomedPictureFrame = ((CGrafPtr)whichWindow)->portRect;
                LocalToGlobal((Point *)&gZoomedPictureFrame.top);
                LocalToGlobal((Point *)&gZoomedPictureFrame.bottom);
                SetPort(savePort);
                break;
 
            case inGrow:
                DoGrow(whichWindow,&myEvent.where);
                break;
 
            case inGoAway:
                if ( TrackGoAway(whichWindow,myEvent.where)  ) 
                    DoClose((CWindowPtr)whichWindow);
                FixMenus();
                break;
 
            case inZoomIn:
                if ( TrackBox(whichWindow,myEvent.where,inZoomIn)  ) 
                    DoZoom(whichWindow);
                break;
 
            case inZoomOut:
                if ( TrackBox(whichWindow,myEvent.where,inZoomOut)  ) 
                    DoZoom(whichWindow);
                break;
 
            case inContent:
                if (whichWindow != FrontWindow()) 
                    SelectWindow(whichWindow);
                break;
            
            default:
                break;
            }
            break;
 
        case keyDown:
            if ( ((myEvent.modifiers & cmdKey) != 0) ) {
                char key = myEvent.message & charCodeMask;
                DoCommand(MenuKey(key));
            }
            break;
        
        case updateEvt :
 
            DoUpdate((CWindowPtr)myEvent.message);
            break;
        
        case activateEvt:
                
            whichWindow=(WindowPtr)myEvent.message;
            if ( (myEvent.modifiers & activeFlag) == 0 ) 
                gActiveWindow = nil;
             else 
                gActiveWindow = (CWindowPtr)whichWindow;
            FixMenus();
            break;
    
        default:
            break;
            
        }
    }
    DoClose(gActiveWindow);
    CloseComponent(gSCComponent);
    ExitToShell();
}