CLUTBuilder.c

/*
    File:       CLUTBuilder.c
 
    Contains:   this file contains functions used to pull colors from a PICT.  You activate it by
                calling CollectColors(PicHandle) with PicHandle set to a PICT that you have already
                loaded into memory.  It will almost invariably return a (handle to a) color table
                (that contains at least black and white) however the color table is not at all clean
                in the current implementation.  It is probably ok if you run it through NewPalette.
                If it runs across a direct pixmap it won't bomb but it won't add any colors to the
                color table.
    
                WARNING: This code has been tested but it has not been tested thoroughly;
                USE AT YOUR OWN RISK!
 
    Written by: Jon Zap 
 
    Copyright:  Copyright © 1989-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/8/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
#include "CLUTBuilder.h"
#define applec
 
 
/* Add a color to the color table. */
void AddRGBColor(RGBColor * rgb)
{
    long numSpecs,sizeInBytes;
    int     i,ctSize;
    CTabPtr TablePtr;
    RGBColor rgbx;
    
    if (gColorError)
        return;
    
    TablePtr = (*gColorTable);
    ctSize = TablePtr -> ctSize;
    for (i = 0; i <= ctSize; i++) {
        rgbx = TablePtr->ctTable[i].rgb;
        if (rgbx.red==(*rgb).red &&
            rgbx.green==(*rgb).green &&
            rgbx.blue==(*rgb).blue) 
            return;     /* if already there, done */
    }
    numSpecs = (long) (++(**gColorTable).ctSize);   /* add a colorspec to table */
    sizeInBytes = (numSpecs * sizeof(ColorSpec)) + sizeof(ColorTable);
    SetHandleSize((Handle)gColorTable, sizeInBytes);
    if ((gColorError = MemError()) == noErr) {
        (**gColorTable).ctTable[numSpecs].rgb = *rgb;
        (**gColorTable).ctTable[numSpecs].value = 0;
    }
}
 
/* Add the contents of another color table to our color table.*/
void AddColorTable(CTabHandle cTab)
{
    short index,size;
    RGBColor color;
    size = (**cTab).ctSize;
    for (index= 0; index <= size; index++) {
        color = (**cTab).ctTable[index].rgb;
        AddRGBColor(&color);
    }
}
 
/* Add the foreground color of the current port to the color table. */
void AddRGBForeColor()
{
#ifdef applec
    AddRGBColor(&((*(CGrafPtr)qd.thePort).rgbFgColor));
#else
    AddRGBColor(&((*(CGrafPtr)thePort).rgbFgColor));
#endif
}
 
/* Add the background color of the current port to the color table. */
void AddRGBBackColor()
{
#ifdef applec
    AddRGBColor(&((*(CGrafPtr)qd.thePort).rgbBkColor));
#else
    AddRGBColor(&((*(CGrafPtr)thePort).rgbBkColor));
#endif
}
 
/* Add colors from a PixPat to a color table. */
void AddPixPat(PixPatHandle pPat)
{
    switch ((**pPat).patType) {
    
    case 0:     /* one-bit patterns are drawn in the foreground and background color. */
        AddRGBForeColor();
        AddRGBBackColor();
        break;
    case 1:     /* Type 1 PixPats have a color table. */
        AddColorTable((**(**pPat).patMap).pmTable);
        break;
    }
}
 
/* Add colors from the pen PixPat to the color table. */
void AddPenPixPat()
{
#ifdef applec
    AddPixPat((*(CGrafPtr)qd.thePort).pnPixPat);
#else
    AddPixPat((*(CGrafPtr)thePort).pnPixPat);
#endif
}
 
/* Add colors from the fill PixPat to the color table. */
void AddFillPixPat()
{
#ifdef applec
    AddPixPat((*(CGrafPtr)qd.thePort).fillPixPat);
#else
    AddPixPat((*(CGrafPtr)thePort).fillPixPat);
#endif
}
 
/* Add colors because we are about to draw an object. */
void AddVerb(GrafVerb verb)
{
    switch (verb) {
    
    case kQDGrafVerbFrame:
    case kQDGrafVerbPaint: /* Framed and painted objects are drawn in the pen PixPat. */
            AddPenPixPat();
            break;
    case kQDGrafVerbErase: /* Erased objects are drawn in the background color. */
            AddRGBBackColor();
            break;
    case kQDGrafVerbFill:
            /* Filled objects are drawn in the fill PixPat.  The fillPixPat is
                a pattern used to record fill commands for pictures.  First, a
                command to set the fillPixPat is recorded, then the fill command
                is recorded. */
            AddFillPixPat();
    }
}
 
/* bottleneck routines follow . . . */
 
pascal void ColorTextProc(short byteCount, Ptr textBuf, Point numer, Point denom)
{   /* Text is drawn with the foreground and background colors.*/
#ifdef applec
#pragma unused (byteCount, textBuf, numer, denom)
#endif
    AddRGBForeColor();
    AddRGBBackColor();
}
 
pascal void ColorLineProc(Point newPt)
{ /* Lines are drawn with the pen PixPat. */
#ifdef applec
#pragma unused (newPt)
#endif
    AddPenPixPat();
}
 
pascal void ColorRectProc(GrafVerb verb,Rect* r)
{
#ifdef applec
#pragma unused (r)
#endif
    AddVerb(verb);
}
 
pascal void ColorRRectProc(GrafVerb verb,Rect* r, short ovalWidth,short ovalHeight)
{
#ifdef applec
#pragma unused (r, ovalWidth, ovalHeight)
#endif
    AddVerb(verb);
}
 
pascal void ColorOvalProc(GrafVerb verb,Rect r)
{
#ifdef applec
#pragma unused (r)
#endif
    AddVerb(verb);
}
 
pascal void ColorArcProc(GrafVerb verb,Rect* r,short startAngle,short arcAngle)
{
#ifdef applec
#pragma unused (r, startAngle, arcAngle)
#endif
    AddVerb(verb);
}
 
pascal void ColorPolyProc(GrafVerb verb, PolyHandle poly)
{
#ifdef applec
#pragma unused (poly)
#endif
    AddVerb(verb);
}
 
pascal void ColorRgnProc(GrafVerb verb,RgnHandle rgn)
{
#ifdef applec
#pragma unused (rgn)
#endif
    AddVerb(verb);
}
 
pascal void ColorBitsProc(BitMap* BitsPtr,Rect srcRect, Rect dstRect,short mode,RgnHandle maskRgn)
{
#ifdef applec
#pragma unused (srcRect, dstRect, mode, maskRgn)
#endif
    PixMapPtr aPixMap;
    short tempRB;
 
    /* Get the PixMap that we are about to draw.  SrcBits might be a BitMap, or
        one of two different kinds of PixMap pointers.  */
    tempRB = BitsPtr->rowBytes;         /* local copy of rowBytes */
    if (tempRB < 0) {                       /* high bit set? */
        if ((tempRB<<1) < 0)                /* next to high bit set? */
            aPixMap = (PixMapPtr)BitsPtr;   /* ptr to PixMap handle */
        else
            aPixMap = (PixMapPtr) BitsPtr;      /* pointer to a PixMap */
        if ((*aPixMap).pixelSize > maxPixDepth) /* deepest pixmap so far? */
            maxPixDepth = (*aPixMap).pixelSize;
        if ((*aPixMap).pixelType==16) {
            foundDirect = true;
            return;                             /* direct pixmap?  eek! */
        }
        AddColorTable((*aPixMap).pmTable);      /* it has its own color table. */
    }
    else {
        /* It's just a BitMap; it will use the background and foreground colors. */
        AddRGBBackColor();
        AddRGBForeColor();
    }
}
 
RGBColor whiteRGB = { 0xFFFF,0xFFFF,0xFFFF };
RGBColor blackRGB = { 0,0,0 };
 
CTabHandle CollectColors(PicHandle fromPicture,short * depthPtr,short * directFlagPtr)
{
    CTabHandle colors;
    CQDProcs bottlenecks;
 
    /* Set the bottlenecks.  These bottlenecks will figure out what colors are in
        a picture, but won't draw anything.
    Note: the bottlenecks are installed in thePort, which must be a color port.
    */
    SetStdCProcs(&bottlenecks);
    bottlenecks.textProc = NewQDTextProc(ColorTextProc);
    bottlenecks.lineProc = NewQDLineProc(ColorLineProc);
    bottlenecks.rectProc = NewQDRectProc(ColorRectProc);
    bottlenecks.rRectProc = NewQDRRectProc(ColorRRectProc);
    bottlenecks.ovalProc = NewQDOvalProc(ColorOvalProc);
    bottlenecks.arcProc = NewQDArcProc(ColorArcProc);
    bottlenecks.polyProc = NewQDPolyProc(ColorPolyProc);
    bottlenecks.rgnProc = NewQDRgnProc(ColorRgnProc);
    bottlenecks.bitsProc =NewQDBitsProc(ColorBitsProc);
 
    /* Create a color table containing black and white. */
    foundDirect = false;    /* haven't found a direct pixmap yet */
    maxPixDepth = 1;        /* assume we will find a bitmap */
    colors = (CTabHandle) NewHandle( sizeof(ColorTable) + sizeof(ColorSpec) );
    if (colors) {
        (**colors).ctSize = 1; /* 2 entries */
#ifdef applec
        (**colors).ctFlags = 0x8000;
#else
        (**colors).transIndex = 0x8000;
#endif
        (**colors).ctSeed = GetCTSeed();
        (**colors).ctTable[0].rgb = whiteRGB; /*first entry is white*/
        (**colors).ctTable[1].rgb = blackRGB; /*second entry is black*/
        /* Now play back the picture to get the colors.  The dstRect doesn't
            matter since our bottlenecks will never actually draw. We use global
            variables (gColorError and gColorTable) to communicate with the
            bottlenecks. */
#ifdef applec
        (*(qd.thePort)).grafProcs = (QDProcs *) &bottlenecks;
#else
        (*thePort).grafProcs = (QDProcs *) &bottlenecks;
#endif
        gColorError = noErr;
        gColorTable = colors;
        DrawPicture(fromPicture, &((**fromPicture).picFrame));
#ifdef applec
        (*(qd.thePort)).grafProcs = 0L;
#else
        (*thePort).grafProcs = 0L;
#endif
        *depthPtr = maxPixDepth;
        *directFlagPtr = foundDirect;
 
        /* Fail if error occurred while within the color bottlenecks. */
        if (gColorError != noErr) {
            DisposeHandle((Handle)colors);
            colors = 0L;
        }
    }
    return colors;
}