IconUtil.c

/*
    File:       IconUtil.c
 
    Contains:   Routines to create icons of any pixel depth, and masked Icons.
 
    Written by: Brigham Stevens 
 
    Copyright:  Copyright © 1984-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/9/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
 
#include <QDOffscreen.h>
#include <Quickdraw.h>
#include <Palettes.h>
#include <Memory.h>
#include <Resources.h>
#include "OldBitMap.h"
#include "MiscCode.h"
 
#include "IconUtil.h"
 
Handle MakeIconMask(GWorldPtr srcGWorld, Rect *srcRect, short iconSize)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    this returns a handle to the image data for an icon MASK of dimension iconSize x iconSize.
    The icon is created by copying the srcRect of srcGWorld into a PixMap.
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
{
 
    Handle  iconBits;
    BitMap  srcBitMap,maskBitMap;
    short   err;
    long    numBytes;
    short   rowbytes;
    
    iconBits = MakeIcon(srcGWorld, srcRect, 1, iconSize);
    if(!iconBits)   return nil;
    HLock(iconBits);
 
    srcBitMap.bounds = *srcRect;            // set up a plain jane bitmap
    srcBitMap.rowBytes = iconSize/8;
    srcBitMap.baseAddr = *iconBits;
    
    NewMaskedBitMap(&srcBitMap,&maskBitMap,srcRect);
    if(!maskBitMap.baseAddr)
    {
        DisposeHandle(iconBits);
        return nil;
    }
    
    HUnlock(iconBits);
 
    CalcOffScreen(srcRect,&numBytes,&rowbytes);
    err = PtrToXHand(maskBitMap.baseAddr,iconBits,numBytes);
    if(err)
    {
        /* we can at least return a handle to the original image,
            which may be considered better than nothing.
            OR - we can dump the image and return nil.
        */
        DebugStr("\pERror in PtrToXHand");
    }
    
    FreeBitMap(&maskBitMap);
 
    HNoPurge(iconBits);
    return iconBits;
}
 
 
Handle  MakeICN_pound(GWorldPtr gwp, Rect *srcRect, short iconDimension)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    this returns a handle to the image data for an icon and it's mask, of size iconDimension x iconDimension.
    The icon is created by copying the srcRect of srcGWorld into a PixMap.
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
{
 
    Handle  icon;
    Handle  iconMask;
    Size    iconSize;
    
    icon = MakeIcon(gwp, srcRect,1,iconDimension);          
    
    if(icon)
    {
        iconMask = MakeIconMask(gwp, srcRect, iconDimension);   
        
        if(iconMask)
        {
            iconSize = GetHandleSize(icon);
            SetHandleSize(icon, iconSize + GetHandleSize(iconMask));
            CheckError("\pSetHandleSize fail.",MemError());
            BlockMove(*iconMask, (Ptr)(((long)*icon) + iconSize), GetHandleSize(iconMask));         
            DisposeHandle(iconMask);
        }
 
    }
    
    return icon;
 
}
 
Handle MakeIcon(GWorldPtr srcGWorld, Rect *srcRect, short dstDepth, short iconSize)
/*
    Creates a handle to the image data for an icon, or nil if an error.
    The source image is specified by GWorld and regtangle defining the area
    to create the icon from.
    The type of icon is specified by the depth and Size paramters.
    iconSize is used for both height and width.
    For example, to create an Icl8 pass 8 for dstDepth and 32 for iconSize.
    to create an ics8 pass 8 for the dstDepth and 16 for iconSize.
    to create an ICON pass 1 for the dstDepth and 32 for iconSize.
    
    
*/
{
    GWorldPtr       saveWorld;
    GDHandle        saveHandle;
    long            bytesPerRow;
    long            imageSize;
    Handle          dstHandle;
    PixMapHandle    pix;
    Rect            iconFrame;
    QDErr           err;
    
    GetGWorld(&saveWorld,&saveHandle);      // save Graphics env state
 
    SetGWorld(srcGWorld,nil);
    
    iconFrame.top = 0;
    iconFrame.left = 0;
    iconFrame.bottom = iconSize;
    iconFrame.right = iconSize;
    
    // make a gworld for the icl resource
    pix = (PixMapHandle)NewHandle(sizeof(PixMap));
    
    /* See Tech Note #120 - for info on creating a PixMap by hand as SetUpPixMap
        does.  SetUpPixMap was taken from that Tech Note....
    */
    err =  SetUpPixMap(dstDepth,&iconFrame,GetCTable(dstDepth),pix);
 
    if(err)
    {
        //asm {move.w   err, d0 }
        DebugStr("\pQuickDraw error.");
        return nil;
    }
        
    LockPixels(GetGWorldPixMap(srcGWorld));
    LockPixels(pix);
            
    CopyBits((BitMapPtr)*srcGWorld->portPixMap,
                (BitMapPtr)*pix,
                srcRect,
                &iconFrame,
                srcCopy | ditherCopy, nil);
 
 
    UnlockPixels(GetGWorldPixMap(srcGWorld));
 
    bytesPerRow = ((dstDepth * ((**pix).bounds.right - (**pix).bounds.left) + 31) / 32) * 4;
    imageSize  = (bytesPerRow) * ((**pix).bounds.bottom - (**pix).bounds.top);
 
    dstHandle = NewHandle(imageSize);
    err = MemError ();
    if(err || dstHandle == nil)
    {
        //asm { move.w err, d0}
        DebugStr("\pI am fuckered.");
        return nil; 
    }
    HLock((Handle)dstHandle);
    BlockMove(GetPixBaseAddr(pix),*dstHandle,imageSize);
    HUnlock(dstHandle);
    UnlockPixels(pix);
    TearDownPixMap(pix);
    // Restore graphics env to previous state
    SetGWorld(saveWorld,saveHandle);
    
    HNoPurge(dstHandle);
    return dstHandle;
}
 
 
void TearDownPixMap(PixMapHandle pix)
{
    // We really need to do more....  BUT It is the thought that counts.. 
    DisposeHandle((Handle)pix); 
}
 
 
#include <QDOffscreen.h>
#include <Palettes.h>
 
PicHandle PIXtoPICT(CGrafPtr wp)
{
    PicHandle       pict;               // this is the Picture we give back
    WindowPtr       saveWindow;         // for saving the port
    
    GetPort(&saveWindow);               // set up the ports so we can 
    SetPort((GrafPort*)wp);                     //  - copy and have a palette too
 
    pict = OpenPicture(&wp->portRect);  // open a picture, this disables drawing
    if(!pict)   return nil;
    
    CopyBits((BitMapPtr)*wp->portPixMap,            // src PixMap   - we copy image over itself -
                (BitMapPtr)*wp->portPixMap,     // dst PixMap   - no drawing occurs -
                &wp->portRect,          // srcRect      - it will be recorded and compressed -
                &wp->portRect,          // dstRect      - into the picture that is open -
                srcCopy,nil);           // copyMode and no clip region
 
    ClosePicture();                     // We are done recording the picture
    SetPort(saveWindow);                // restore to the previous port
    return pict;                        // return our groovy pict handle
}
 
GWorldPtr LoadPictToGWorld(int resID, WindowPtr wp, int numEntries,
                        int pdepth, int gdepth, Boolean linkCtabToPal)
                        
/*
    Loads in the picture specified be the resID parameter.
    Creates a GWorld from characteristics of window wp
    Stores the GWorld pointer in the wRefcon field of the windowRecord.
*/
{
 
    CTabHandle      gwctab;
    WindowPtr       saveWindow;
    GDHandle        saveDevice;
    PicHandle       pict;
    Rect            destRect;
    short           i;
    PaletteHandle   pal;
    GWorldPtr       gw; 
 
    pict = GetPicture(resID);
    if(!pict)
        DebugStr("\pError - pict was nil!");
    destRect = (**pict).picFrame;
    OffsetRect( &destRect, -destRect.left, -destRect.top );
    SizeWindow(wp, destRect.right, destRect.bottom,true);
 
    pal = NewPalette(numEntries, GetCTable(pdepth), pmTolerant, 0);
    SetPalette(wp, pal, true);
 
    gw = (GWorldPtr)CreateOffScreen(wp, gdepth, false); // make a gworld
 
    if(linkCtabToPal)
    {
        gwctab = (**GetGWorldPixMap(gw)).pmTable;   // get the color table for the gWorld.
    
        // Set up the clut so that the entries refer to palette
        // indexes, instead of the usual rgb information.
        (**gwctab).ctFlags |= 0x4000;       // this bit is the flag to indicate this
        //¥¥¥¥¥¥¥¥ See Inside Macintosh Volume VI page 20-17
        
        for (i = 0; i <= (**gwctab).ctSize; i++)
        {
            (**gwctab).ctTable[i].value = i;
        }
        CTabChanged(gwctab);        // Update the color table
    }   
    
    GetGWorld((CGrafPort**)&saveWindow,&saveDevice);
    SetGWorld(gw,nil);
 
    // draw the picture into the offscreen gworld
    pict = GetPicture(resID);
    
    if(LockPixels (GetGWorldPixMap (gw)))
    {
        DrawPicture(pict,&destRect);
        UnlockPixels(GetGWorldPixMap(gw));
    }
    SetGWorld((CGrafPort*)saveWindow,saveDevice);
    SetWRefCon(wp,(long)gw);                    // store gWold in refcon of Window
    ReleaseResource((Handle)pict);
    
    return gw;
}