Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
DrawTextComponent.c
/* |
File: DrawTextComponent.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 <Memory.h> |
#include <Resources.h> |
#include <QuickDraw.h> |
#include <QDOffscreen.h> |
#include <OSUtils.h> |
#include <Errors.h> |
#include <FixMath.h> |
#include <ImageCodec.h> |
#include "DrawTextCodec.h" |
InitCharTab(SharedGlobals *sGlob,ComponentInstance self); |
extern long |
Decompress(char *baseAddr,short rowBytes,short bwidth,short bheight, |
char *dataPtr); |
extern long |
Compress(char *baseAddr,short rowBytes,char *pBaseAddr,short pRowBytes, |
short width,short height,long spatialQ,long temporalQ,char *dataPtr, |
Fixed *similarityP,SharedGlobals *glob); |
/* |
Our data structure declarations |
*/ |
/* Function prototypes to keep the compiler smiling. */ |
pascal ComponentResult |
DRAWTEXTCODEC(ComponentParameters *params,char **storage); |
pascal ComponentResult |
OpenCodec(ComponentInstance self); |
pascal ComponentResult |
CloseCodec(Handle storage,ComponentInstance self); |
pascal ComponentResult |
CanDoSelector(short selector); |
pascal ComponentResult |
GetVersion(); |
pascal void |
CompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg); |
pascal void |
DecompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg); |
pascal long |
CDPreCompress(Handle storage,register CodecCompressParams *p); |
pascal long |
CDBandCompress(Handle storage,register CodecCompressParams *p); |
pascal long |
CDPreDecompress(Handle storage,register CodecDecompressParams *p); |
pascal long |
CDBandDecompress(Handle storage,register CodecDecompressParams *p); |
pascal ComponentResult |
CDGetCodecInfo(Handle storage,CodecInfo *info); |
pascal ComponentResult |
CDGetCompressedImageSize(Handle storage,ImageDescriptionHandle desc,Ptr data,long dataSize, |
ICMDataProcRecordPtr dataProc,long *size); |
pascal ComponentResult |
CDGetMaxCompressionSize(Handle storage,PixMapHandle src,const Rect *srcRect,short depth, |
CodecQ quality,long *size); |
pascal ComponentResult |
CDGetCompressionTime(Handle storage,PixMapHandle src,const Rect *srcRect,short depth, |
CodecQ *spatialQuality,CodecQ *temporalQuality,unsigned long *time); |
pascal ComponentResult |
CDGetSimilarity(Handle storage,PixMapHandle src,const Rect *srcRect,ImageDescriptionHandle desc, |
Ptr data,Fixed *similarity); |
pascal ComponentResult |
CDTrimImage(Handle storage,ImageDescriptionHandle desc,Ptr inData,long inDataSize, |
ICMDataProcRecordPtr dataProc,Ptr outData,long outDataSize,ICMFlushProcRecordPtr flushProc, |
Rect *trimRect,ICMProgressProcRecordPtr progressProc); |
ComponentResult |
InitSharedTables(Globals **glob,ComponentInstance self); |
/************************************************************************************ |
* This is the main dispatcher for our codec. All calls from the codec manager |
* will come through here, with a unique selector and corresponding parameter block. |
* |
* This routine must be first in the code segment of the codec thing. |
*/ |
ProcInfoType __procinfo=kPascalStackBased |
| RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult))) |
| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(ComponentParameters*))) |
| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char**))); |
pascal ComponentResult |
DRAWTEXTCODEC(ComponentParameters *params,char **storage) |
{ |
/* If the selector is less than zero, it's a Component manager selector. */ |
if ( params->what < 0 ) { |
switch ( params->what ) { |
case kComponentOpenSelect: |
return CallComponentFunction(params, (ComponentFunctionUPP)OpenCodec ); |
case kComponentCloseSelect: |
return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP) CloseCodec ); |
case kComponentCanDoSelect: |
return CallComponentFunction(params, (ComponentFunctionUPP) CanDoSelector); |
case kComponentVersionSelect : |
return CallComponentFunction(params, (ComponentFunctionUPP) GetVersion); |
default : |
return (paramErr); |
} |
} |
/* |
* Here we dispatch the rest of our calls. We use the magic thing manager routine which |
* calls our subroutines with the proper parameters. The prototypes are in Image Codec.h. |
*/ |
switch ( params->what ) { |
case kImageCodecPreCompressSelect: |
return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDPreCompress); |
case kImageCodecBandCompressSelect: |
return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDBandCompress); |
case kImageCodecPreDecompressSelect: |
return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDPreDecompress); |
case kImageCodecBandDecompressSelect: |
return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDBandDecompress); |
case kImageCodecBusySelect: |
return 0; /* our codec is never asynchronously busy */ |
case kImageCodecGetCodecInfoSelect: |
return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDGetCodecInfo); |
case kImageCodecGetCompressedImageSizeSelect : |
return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDGetCompressedImageSize); |
case kImageCodecGetMaxCompressionSizeSelect: |
return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDGetMaxCompressionSize); |
case kImageCodecGetCompressionTimeSelect : |
return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDGetCompressionTime); |
case kImageCodecGetSimilaritySelect: |
return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDGetSimilarity); |
case kImageCodecTrimImageSelect : |
return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDTrimImage); |
default: |
return(paramErr); |
} |
} |
/************************************************************************************ |
* This gets called when the thing instance is opened. We allocate our shared storage at this |
* point. |
* If we have shared globals, we check if they exist, otherwise we allocate |
* them and set the ComponentRefCon so that other instances can use them. |
* |
* The shared globals hold our CodecInfo struct, which we read from our resource file, |
* and some tables that we use for speed. If we cant get the tables we can work without |
* them. All items in the shared globals are made purgeable when the last of our |
* instances is closed. If our component was loaded in the application heap ( because |
* there was no room in the system heap) then we keep our shared storage in the app heap. |
* |
* We keep a pointer to the shared globals in our instance globals so that other calls can get to them. |
*/ |
ComponentResult |
InitSharedTables(Globals **glob,ComponentInstance self) |
{ |
SharedGlobals *sGlob; |
short resFile; |
THz saveZone; |
Boolean inAppHeap; |
OSErr result = noErr; |
saveZone = GetZone(); |
inAppHeap = ( GetComponentInstanceA5(self) != 0 ); |
if ( !inAppHeap ) |
SetZone(SystemZone()); |
if ( (sGlob=(SharedGlobals*)GetComponentRefcon((Component)self)) == nil ) { |
if ( (sGlob = (SharedGlobals*)NewPtrClear(sizeof(SharedGlobals))) == nil ) { |
result = MemError(); |
goto obail; |
} |
SetComponentRefcon((Component)self,(long)sGlob); |
} |
(*glob)->sharedGlob = sGlob; // keep this around where it's easy to get at |
if ( sGlob->info == nil || *(Handle)sGlob->info == nil ) { |
if ( sGlob->info ) |
DisposeHandle((Handle)sGlob->info); |
/* Get the CodecInfo struct which we keep in our resource fork */ |
resFile = OpenComponentResFile((Component)self); |
#ifndef THINK_C // if running linked this will return an error since the res file is already open |
if ( (result=ResError() ) != 0 ) |
goto obail; |
#endif THINK_C |
sGlob->info = (CodecInfo **) GetResource(codecInfoResourceType,128); |
if ( sGlob->info == nil ) { |
CloseComponentResFile(resFile); |
result = ResError(); |
goto obail; |
} |
LoadResource((Handle)sGlob->info); |
if ( ResError() ) { |
sGlob->info = nil; |
CloseComponentResFile(resFile); |
result = ResError(); |
goto obail; |
} |
DetachResource((Handle)sGlob->info); |
CloseComponentResFile(resFile); |
} |
HNoPurge((Handle)sGlob->info); |
obail: |
SetZone(saveZone); |
if ( result != noErr && sGlob != nil ) { |
if ( sGlob->info ) |
DisposeHandle((Handle)sGlob->info); |
DisposePtr((Ptr)sGlob); |
SetComponentRefcon((Component)self,(long)nil); |
} |
return(result); |
} |
/************************************************************************************ |
* This gets called when the thing instance is opened. We allocate our storage at this |
* point. If we have shared globals, we check if they exist, and put a pointer to them |
* in our instance globals so that other calls can get to them. |
*/ |
pascal ComponentResult |
OpenCodec(ComponentInstance self) |
{ |
ComponentResult result; |
Globals **glob; |
/* |
First we allocate shared storage. This should be a handle to any |
kind of data used by the thing instance. They should be allocated |
in the current heap. |
*/ |
if ( (glob = (Globals **)NewHandleClear(sizeof(Globals))) == nil ) { |
return(MemError()); |
} |
SetComponentInstanceStorage(self,(Handle)glob); |
/* Check and initialize our shared globals */ |
(*glob)->self = self; |
result = InitSharedTables(glob,self); |
return result; |
} |
/************************************************************************************ |
* This gets called when the thing instance is closed. We need to get rid of any |
* instance storage here. |
*/ |
pascal ComponentResult |
CloseCodec(Handle storage,ComponentInstance self) |
{ |
SharedGlobals *sGlob; |
Globals **glob = (Globals **)storage; |
/* If we are closing our last instance |
then we make the shared global items purgeable to |
speed things up next instance. |
*/ |
if ( CountComponentInstances((Component)self) == 1) { |
if ( (sGlob=(SharedGlobals*)(*glob)->sharedGlob) != nil ) { |
if ( sGlob->info ) |
HPurge((Handle)sGlob->info); |
if ( sGlob->tableWorld ) { |
DisposeGWorld(sGlob->tableWorld ); |
sGlob->tableWorld = nil; |
} |
} |
} |
if ( glob ) { |
DisposeHandle((Handle)glob); |
} |
return(noErr); |
} |
/************************************************************************************ |
* Return true if we can handle the selector, otherwise false. |
*/ |
pascal ComponentResult |
CanDoSelector(short selector) |
{ |
switch(selector) { |
case kComponentOpenSelect: |
case kComponentCloseSelect: |
case kComponentCanDoSelect: |
case kComponentVersionSelect : |
case kImageCodecPreCompressSelect: |
case kImageCodecBandCompressSelect: |
case kImageCodecPreDecompressSelect: |
case kImageCodecBandDecompressSelect: |
case kImageCodecBusySelect: |
case kImageCodecGetCodecInfoSelect: |
case kImageCodecGetCompressedImageSizeSelect: |
case kImageCodecGetMaxCompressionSizeSelect: |
case kImageCodecGetCompressionTimeSelect: |
case kImageCodecGetSimilaritySelect: |
case kImageCodecTrimImageSelect: |
return(true); |
default: |
return (false); |
} |
} |
/************************************************************************************ |
* Return the version of this component ( defines interface ) and revision level |
* of the code. |
*/ |
pascal ComponentResult |
GetVersion() |
{ |
return ((1<<16) | 1); /* interface version in hi word, code rev in lo word */ |
} |
/************************************************************************************ |
* CDPreCompress gets called before an image is compressed, or whenever the source pixmap |
* pixel size changes when compressing a sequence. We return information about |
* how we can compress the image to the codec manager, so that it can fit the source data |
* to our requirements. The ImageDescriptor is already filled in, so we can use it for |
* reference (or even add to it ). PixelSize is the pixel depth of the source pixmap, we |
* use this as a reference for deciding what we can do. The other parameters return information |
* to the CodecManager about what we can do. We can also do setup here if we want to. |
*/ |
pascal long |
CDPreCompress(Handle storage,register CodecCompressParams *p) |
{ |
Globals **glob = (Globals **)storage; |
CodecCapabilities *capabilities = p->capabilities; |
/* |
* First we return which depth input pixels we can deal with - based on what the |
* app has available - we can only work with 32 bit input pixels. |
*/ |
switch ( (*p->imageDescription)->depth ) { |
case 1: |
capabilities->wantedPixelSize = 1; |
break; |
default: |
return(codecConditionErr); |
break; |
} |
/* if the buffer gets banded, return the smallest one we can deal with */ |
capabilities->bandMin = FONT_HEIGHT; |
/* if the buffer gets banded, return the increment it be should grown */ |
capabilities->bandInc = FONT_HEIGHT; |
/* |
* If a codec needs the dimensions of the source pixmap to be of certain multiples |
* it can ask for the image to be extended out (via pixel replication) vertically |
* and/or horizontally. |
*/ |
if ( (*p->imageDescription)->width % FONT_WIDTH ) |
capabilities->extendWidth = FONT_WIDTH & (FONT_WIDTH - ((*p->imageDescription)->width % FONT_WIDTH)); |
if ( (*p->imageDescription)->height % FONT_HEIGHT ) |
capabilities->extendHeight = FONT_HEIGHT & (FONT_HEIGHT - ((*p->imageDescription)->height % FONT_HEIGHT)); |
if ( (*glob)->sharedGlob->tableWorld == nil ) |
InitCharTab((*glob)->sharedGlob,(*glob)->self); |
return(noErr); |
} |
/************************************************************************************ |
* CDBandCompress gets called when the codec manager wants us to compress an image, or a horizontal |
* band of an image. The pixel data at sBaseAddr is guaranteed to conform to the criteria we |
* demanded in BeginCompress. |
*/ |
pascal long |
CDBandCompress(Handle storage,register CodecCompressParams *p) |
{ |
short width,height; |
Ptr cDataPtr,dataStart; |
short depth; |
Rect sRect; |
long offsetH,offsetV; |
Globals **glob = (Globals **)storage; |
register char *baseAddr; |
long numLines,numStrips; |
short rowBytes; |
char mmuMode = 1; |
register short y; |
ImageDescription **desc = p->imageDescription; |
OSErr result = noErr; |
Fixed simil; |
long csize; |
CodecQ spatialQ,temporalQ; |
/* If there is a progress proc, give it an open call at the start of this band. */ |
if (p->progressProcRecord.progressProc) |
CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressOpen,0, |
p->progressProcRecord.progressRefCon); |
width = (*desc)->width; |
height = (*desc)->height; |
depth = (*desc)->depth; |
dataStart = cDataPtr = p->data; |
spatialQ = p->spatialQuality; |
temporalQ = p->temporalQuality; |
/* figure out offset to first pixel in baseAddr from the pixelsize and bounds */ |
rowBytes = p->srcPixMap.rowBytes & 0x3fff; |
sRect = p->srcPixMap.bounds; |
numLines = p->stopLine - p->startLine; /* number of scanlines in this band */ |
numStrips = numLines/FONT_HEIGHT; /* number of strips in this band */ |
/* adjust the source baseAddress to be at the beginning of the desired rect */ |
switch ( p->srcPixMap.pixelSize ) { |
case 1: |
offsetH = sRect.left>>3; /* 8 pixels = 1 byte */ |
break; |
default: |
result = codecErr; |
goto bail; |
} |
offsetV = sRect.top * rowBytes; |
baseAddr = p->srcPixMap.baseAddr + offsetH + offsetV; |
if ( p->conditionFlags & codecConditionFirstBand) { |
(*glob)->totalSize = 0; |
} |
else { |
/* if there is not a flush proc, adjust the pointer to the next band */ |
if ( p->flushProcRecord.flushProc == nil ) |
cDataPtr += (*glob)->totalSize; |
} |
/* do the slower flush/progress case if we have too */ |
if ( p->flushProcRecord.flushProc || p->progressProcRecord.progressProc ) { |
SharedGlobals *sg = (*glob)->sharedGlob; |
for ( y=0; y < numStrips; y++) { |
SwapMMUMode(&mmuMode); |
csize = Compress(baseAddr,rowBytes,nil,0,width/FONT_WIDTH,1,spatialQ,temporalQ, |
cDataPtr,&simil,sg); |
SwapMMUMode(&mmuMode); |
baseAddr += rowBytes*FONT_HEIGHT; |
if ( p->flushProcRecord.flushProc ) { |
if ( (result=CallICMFlushProc(p->flushProcRecord.flushProc,cDataPtr,csize, |
p->flushProcRecord.flushRefCon)) != noErr) { |
result = codecSpoolErr; |
goto bail; |
} |
} else { |
cDataPtr += csize; |
} |
(*glob)->totalSize += csize; |
if (p->progressProcRecord.progressProc) { |
if ( (result=CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressUpdatePercent, |
FixDiv(y,numStrips),p->progressProcRecord.progressRefCon)) != noErr ) { |
result = codecAbortErr; |
goto bail; |
} |
} |
} |
} else |
{ |
SharedGlobals *sg = (*glob)->sharedGlob; |
SwapMMUMode(&mmuMode); |
csize = Compress(baseAddr,rowBytes,nil,0,width/FONT_WIDTH,numStrips,spatialQ, |
temporalQ,cDataPtr,&simil,sg); |
SwapMMUMode(&mmuMode); |
cDataPtr += csize; |
(*glob)->totalSize += csize; |
} |
/* |
return size and similarity on the last band |
*/ |
if ( p->conditionFlags & codecConditionLastBand ) { |
(*p->imageDescription)->dataSize = (*glob)->totalSize; /* return the actual size of the compressed data */ |
p->similarity = 0; /* we don't do frame differencing */ |
} |
bail: |
/* If there is a progress proc, give it a close call at the end of this band. */ |
if (p->progressProcRecord.progressProc) |
CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressClose,0, |
p->progressProcRecord.progressRefCon); |
return(result); |
} |
/************************************************************************************ |
* CDPreDecompress gets called before an image is decompressed. We return information about |
* how we can decompress the image to the codec manager, so that it can fit the destination data |
* to our requirements. |
*/ |
pascal long |
CDPreDecompress(Handle storage,register CodecDecompressParams *p) |
{ |
#pragma unused(storage) |
register CodecCapabilities *capabilities = p->capabilities; |
Rect dRect = p->srcRect; |
/* Check if the matrix is okay for us. We don't do anything fancy. */ |
if ( !TransformRect(p->matrix,&dRect,nil) ) |
return(codecConditionErr); |
/* Decide which depth compressed data we can deal with. */ |
switch ( (*p->imageDescription)->depth ) { |
case 1: |
break; |
default: |
return(codecConditionErr); |
break; |
} |
/* We can deal only 1 bit pixels. */ |
capabilities->wantedPixelSize = 1; |
capabilities->bandMin = FONT_HEIGHT; |
capabilities->bandInc = FONT_HEIGHT; |
/* If we needed our pixels to be aligned on some integer multiple we would set these to |
* the number of pixels we need the dest extended by. If we dont care, or we take care of |
* it ourselves we set them to zero. |
*/ |
if ( (*p->imageDescription)->width % FONT_WIDTH ) |
capabilities->extendWidth = FONT_WIDTH & (FONT_WIDTH - ((*p->imageDescription)->width % FONT_WIDTH)); |
if ( (*p->imageDescription)->height % FONT_HEIGHT ) |
capabilities->extendHeight = FONT_HEIGHT & (FONT_HEIGHT - ((*p->imageDescription)->height % FONT_HEIGHT)); |
return(noErr); |
} |
/************************************************************************************ |
* CDBandDecompress gets called when the codec manager wants us to decompress an image or a horizontal |
* band of an image. The pixel data at baseAddr is guaranteed to conform to the criteria we |
* demanded in BeginDecompress. If maskIn is true, then the mask data at mBaseAddr is valid, and |
* we need to clear bits in it that correspond to any pixels in the destination we do not want to |
* change. ( We always write all pixels, so we dont care. This mode is important only for those |
* codecs that have frame differencing and don't always write all the pixels. ) |
*/ |
pascal long |
CDBandDecompress(Handle storage,register CodecDecompressParams *p) |
{ |
Rect dRect; |
long offsetH,offsetV; |
Globals **glob = (Globals **)storage; |
long numLines,numStrips; |
short rowBytes; |
long stripBytes; |
short width; |
register short y; |
register char *baseAddr; |
char *cDataPtr; |
char mmuMode = 1; |
OSErr result = noErr; |
long csize; |
/* Calculate the real base address based on the bounds rect. If it's not |
a linear transformation, we dont do it. */ |
dRect = p->srcRect; |
if ( !TransformRect(p->matrix,&dRect,nil) ) |
return(paramErr); |
/* If there is a progress proc, give it an open call at the start of this band. */ |
if (p->progressProcRecord.progressProc) |
CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressOpen,0, |
p->progressProcRecord.progressRefCon); |
/* initialize some local variables */ |
width = (*p->imageDescription)->width; |
rowBytes = p->dstPixMap.rowBytes; |
numLines = p->stopLine - p->startLine; /* number of scanlines in this band */ |
numStrips = numLines/FONT_HEIGHT; /* number of strips in this band */ |
stripBytes = (width + (FONT_WIDTH-1))/FONT_WIDTH; /* number of bytes in one strip of blocks */ |
cDataPtr = p->data; |
/* adjust the destination baseaddress to be at the beginning of the desired rect */ |
offsetH = (dRect.left - p->dstPixMap.bounds.left); |
switch ( p->dstPixMap.pixelSize ) { |
case 1: |
offsetH >>= 3; /* 8 pixel = 1 bytes */ |
break; |
default: |
result = codecErr; /* we dont handle these cases, thow we could */ |
goto bail; |
} |
offsetV = (dRect.top - p->dstPixMap.bounds.top) * rowBytes; |
baseAddr = p->dstPixMap.baseAddr + offsetH + offsetV; |
/* |
* If we are skipping some data, we just skip it here. We can tell because |
* firstBandInFrame says this is the first band for a new frame, and |
* if startLine is not zero, then that many lines were clipped out. |
*/ |
if ( (p->conditionFlags & codecConditionFirstBand) ) { |
cDataPtr += p->startLine * stripBytes; |
} |
/* |
* If theres a dataproc spooling the data to us, then we have to do the data |
* in whatever size chunks they want to give us, or if there is a progressProc |
* make sure to call it as we go along. |
*/ |
if ( p->dataProcRecord.dataProc || p->progressProcRecord.progressProc ) { |
SharedGlobals *sg = (*glob)->sharedGlob; |
for (y=0; y < numStrips; y++) { |
if (p->dataProcRecord.dataProc) { |
if ( (result=CallICMDataProc(p->dataProcRecord.dataProc,&cDataPtr,stripBytes, |
p->dataProcRecord.dataRefCon)) != noErr ) { |
result = codecSpoolErr; |
goto bail; |
} |
} |
SwapMMUMode(&mmuMode); |
csize = Decompress(baseAddr,rowBytes,width/FONT_WIDTH,1,cDataPtr); |
SwapMMUMode(&mmuMode); |
baseAddr += rowBytes*FONT_HEIGHT; |
cDataPtr += csize; |
if (p->progressProcRecord.progressProc) { |
if ( (result=CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressUpdatePercent, |
FixDiv(y, numStrips),p->progressProcRecord.progressRefCon)) != noErr ) { |
result = codecAbortErr; |
goto bail; |
} |
} |
} |
/* |
* |
* otherwise - do the fast case. |
* |
*/ |
} else |
{ |
SwapMMUMode(&mmuMode); |
csize = Decompress(baseAddr,rowBytes,width/FONT_WIDTH,numStrips,cDataPtr); |
SwapMMUMode(&mmuMode); |
cDataPtr += csize; |
} |
/* |
* |
* IMPORTANT: update pointer to data in params, so when we get the next |
* band we'll be at the right place in our data. |
* |
*/ |
p->data = cDataPtr; |
if ( p->conditionFlags & codecConditionLastBand ) { |
/* Tie up any loose ends on the last band of the frame, if we had any */ |
} |
bail: |
/* If there is a progress proc, give it a close call at the end of this band. */ |
if (p->progressProcRecord.progressProc) |
CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressClose,0, |
p->progressProcRecord.progressRefCon); |
return(result); |
} |
/************************************************************************************ |
* CDGetCodecInfo allows us to return information about ourselves to the codec manager. |
* |
* There will be a tool for determining appropriate values for the accuracy, speed |
* and level information. For now we estimate with scientific wild guessing. |
* |
* The info is stored as a resource in the same file with our component. |
*/ |
pascal ComponentResult |
CDGetCodecInfo(Handle storage,CodecInfo *info) |
{ |
Globals **glob = (Globals **)storage; |
if ( info == nil ) |
return(paramErr); |
BlockMove((Ptr)*((*glob)->sharedGlob)->info,(Ptr)info,sizeof(CodecInfo)); |
return(noErr); |
} |
/************************************************************************************ |
* When CDGetSimilarity is called, we return the percent of the compressed image A that |
* is different from compressed image B. This can be used by applications that use sequence |
* dynamics as an indicator for editing image sequences. |
* |
* If the codec cannot do a direct similarity comparison, the ICM decompresses image A and |
* do a comparison with image B. This call is provided so that a codec can save the time |
* of the intermediate decompress if it can do the comparison directly. |
*/ |
pascal ComponentResult |
CDGetSimilarity(Handle storage,PixMapHandle src,const Rect *srcRect,ImageDescriptionHandle desc, |
Ptr data,Fixed *similarity) |
{ |
#pragma unused(storage,src,srcRect,desc,data,similarity) |
/* This call is not implemented yet, which is okay, because its not used very much and is not mandatory */ |
return(codecUnimpErr); |
} |
/************************************************************************************ |
* When CDGetCompressedImageSize is called, we return the size in bytes of the given compressed |
* data ( for one image frame). |
*/ |
pascal ComponentResult |
CDGetCompressedImageSize(Handle storage,ImageDescriptionHandle desc,Ptr data,long dataSize, |
ICMDataProcRecordPtr dataProc,long *size) |
{ |
#pragma unused(storage,data,dataSize,dataProc) |
short width = (*desc)->width; |
short height = (*desc)->height; |
if ( size == nil ) |
return(paramErr); |
/* we always end up with a fixed size. If we did not, we would return the worst case size */ |
*size = ((width + (FONT_WIDTH-1))/FONT_WIDTH) * ((height+(FONT_HEIGHT-1))/FONT_HEIGHT); |
return(noErr); |
} |
/************************************************************************************ |
* When CDGetMaxCompressionSize is called, we return the maximum size the compressed data for |
* the given image would be in bytes. |
*/ |
pascal ComponentResult |
CDGetMaxCompressionSize(Handle storage,PixMapHandle src,const Rect *srcRect,short depth, |
CodecQ quality,long *size) |
{ |
#pragma unused(storage,src,depth,quality) |
short width = srcRect->right - srcRect->left; |
short height = srcRect->bottom - srcRect->top; |
/* we always end up with a fixed size. If we did not, we would return the worst case size */ |
*size = 100 + ((width + (FONT_WIDTH-1))/FONT_WIDTH) * ((height+(FONT_HEIGHT-1))/FONT_HEIGHT); |
return(noErr); |
} |
/************************************************************************************ |
* When CDGetCompressionTime is called, we return the approximate time for compressing |
* the given image would be in milliseconds. We also return the closest actual quality |
* we can handle for the requested value. |
*/ |
pascal ComponentResult |
CDGetCompressionTime(Handle storage,PixMapHandle src,const Rect *srcRect,short depth, |
CodecQ *spatialQuality,CodecQ *temporalQuality,unsigned long *time) |
{ |
#pragma unused(storage,src,srcRect,depth) |
if (time) |
*time = 0; /* we don't know how many msecs */ |
if ( spatialQuality ) { |
if ( *spatialQuality <= codecLowQuality ) { |
*spatialQuality = codecLowQuality; |
} |
else if ( *spatialQuality <= codecNormalQuality ) { |
*spatialQuality = codecNormalQuality; |
} else { |
*spatialQuality = codecHighQuality; |
} |
} |
if ( temporalQuality ) |
*temporalQuality = 0; |
return(noErr); |
} |
/************************************************************************************ |
* When CDTrimImage is called, we take the given compressed data and return only the portion |
* which is represented by the trimRect. We can return a little more if we have too, but we |
* need only return enough so that the image in trimRect is properly displayed. We then |
* adjust the rectangle to corresond to the same rectangle in the new trimmed data. |
*/ |
pascal ComponentResult |
CDTrimImage(Handle storage,ImageDescriptionHandle desc,Ptr inData,long inDataSize, |
ICMDataProcRecordPtr dataProc,Ptr outData,long outDataSize,ICMFlushProcRecordPtr flushProc, |
Rect *trimRect,ICMProgressProcRecordPtr progressProc) |
{ |
#pragma unused(storage,desc,inData,inDataSize,dataProc,outData,outDataSize,flushProc,trimRect,progressProc) |
return(codecUnimpErr); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14