DrawTextCompress.c

/*
    File:       DrawTextCompress.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
                
 
*/
 
#include    <Types.h>
#include    <Memory.h>
#include    <ImageCompression.h>
#include    <QuickDraw.h>
 
 
 
#include    "DrawTextCodec.h"
 
short
CalcError(register char *src,short rowBytes,short index,register char *table);
long
Compress(char *baseAddr,short rowBytes,char *pBaseAddr,short pRowBytes,
    short bwidth,short bheight,long spatialQ,long temporalQ,char *dataPtr,
    Fixed *similarityP,SharedGlobals *sGlob);
void InitCharTab(SharedGlobals *sGlob,ComponentInstance self);
void MakeSkipTable(SharedGlobals *sGlob);
 
/***********************
    
    
    Compress bheight strips ( of bwidth blocks ) of pixels using the given table
    of char values.
    
    Source must be 1-bit/pixel.
    
    Should be called in 32-bit mmu mode, since we access pixels directly.
    
 
 
***********************/
 
long
Compress(char *baseAddr,short rowBytes,char *pBaseAddr,short pRowBytes,
    short bwidth,short bheight,long spatialQ,long temporalQ,char *dataPtr,
    Fixed *similarityP,SharedGlobals *sGlob)
{
    #pragma unused(pBaseAddr,pRowBytes,temporalQ)
    char *dataStart = dataPtr;
    char *bp;
    register short          i;
    short           x,y;
    short           min = 1000,minIndex,e;
    char            *charTab = sGlob->table;
    short           startIndex = ' ',endIndex = 'z';
    
    
    /* 
    
        limit search based on requested quality level.
        
    */
    
    if ( spatialQ <= codecLowQuality ) {
        startIndex = ' ';
        endIndex = '9';
    }
    else if ( spatialQ <= codecNormalQuality ) {
        startIndex = ' ';
        endIndex = 'z';
    } else  {
        startIndex = 0;
        endIndex = 255;
    }
    
    /* 
    
        compress the strips
        
    */
    
    for ( y=0; y <  bheight; y++ ) {
        bp = baseAddr;
        for (x=0; x < bwidth; x++) {
            min = 1000;
            
            /* find the best character for this block */
            
            for (i=startIndex; i <= endIndex; i++) {
                if ( (e=CalcError(bp,rowBytes,i,charTab)) < min ) {
                    min = e;
                    minIndex = i;
                }
                if ( min == 0 )
                    break;
            }
            *dataPtr++ = minIndex;                  // write char as compressed data
            bp++;
        }
        baseAddr += rowBytes * FONT_HEIGHT;         // bump to next strip
    }
    if ( similarityP )                              // if we did similarity...
        *similarityP = 0;
    return(dataPtr - dataStart);
}
 
 
/************************
 
    Calculate and return the number of pixels that dont match between the given block of 
    1-bit pixels and the equivcalent indexed block in the table
    
************************/
 
short
CalcError(register char *src,short rowBytes,short index,register char *table)
{
    short err = 0;
    short i,j;
    register signed char d;
    
    table += index;
    
    for ( i=FONT_HEIGHT; i-- ; ) {
        d = *src ^ *table;
        if ( d != 0 ) {
            if ( d == 0xff )
                err += 8;
            else {
                for ( j =FONT_WIDTH; j--;  )  {         
                    if ( d < 0 ) 
                        err++;
                    d <<= 1;
                }
            }
        }
        table += (256 * FONT_WIDTH) / 8;
        src += rowBytes;
    }
    return(err);
}
 
 
/************************
 
    Build a bitmap table of the characters in the font. Keep as shared data.
    
************************/
 
void InitCharTab(SharedGlobals *sGlob,ComponentInstance self)
 
{
    CGrafPtr        savePort;
    GDHandle        saveGD;
    short           x;
    Rect            rect;
    GWorldPtr       gw;
    THz             saveZone;
    Boolean         inAppHeap;
        
    /*
    
        figure out which zone to use, based on where we are loaded.
        
    */
    
    saveZone = GetZone();
    inAppHeap = ( GetComponentInstanceA5(self) != 0 );
    if ( !inAppHeap )
        SetZone(SystemZone());
    sGlob->tableWorld = nil;
    sGlob->table = nil;
    GetGWorld(&savePort,&saveGD);
    SetRect(&rect,0,0,256*FONT_WIDTH,FONT_HEIGHT);
    if ( NewGWorld(&gw,1,&rect,nil,nil,0) == 0 ) {
        (*gw->portPixMap)->rowBytes = 0x8000 | (256 * FONT_WIDTH) / 8;
        SetGWorld(gw,nil);
        TextSize(FONT_SIZE);
        TextFont(FONT_ID);
        EraseRect(&rect);
        ClipRect(&rect);
        for (x=0; x < 256; x++) {
            MoveTo(x*FONT_WIDTH,BASE_LINE);
            DrawChar(x);
        }
        SetGWorld(savePort,saveGD);
        LockPixels(gw->portPixMap);
        sGlob->tableWorld = gw;
        sGlob->table = GetPixBaseAddr(gw->portPixMap);
        
    } 
    SetZone(saveZone);
}
 
 
/************************
 
    Figure duplicate font chars. not used.
    
************************/
 
void MakeSkipTable(SharedGlobals *sGlob)
 
{
    short       i,x;
    char        *charTab = sGlob->table;
    
    for (i=0; i < 256; i++) 
        sGlob->skipTable[i] = 0;
    for (i=0; i < 256; i++) {
        char *icp = charTab + i * FONT_WIDTH;
        if ( !sGlob->skipTable[i] ) {
            for (x=i+1; x < 256; x++) {
                if ( CalcError(icp,(256 * FONT_WIDTH) / 8,x,charTab) == 0) 
                    sGlob->skipTable[x] = 1;
            }
        }
    }
 
}