sys7.1-doc-wip/QuickDraw/PictUtilities/puPopular.c
2019-07-27 22:37:48 +08:00

271 lines
8.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
File: puPopular.c
Contains: This is the popular color finding algorithm for the picture utilities package.
Written by: Dave Good. Some ideas stolen from Konstantin Othmer and Bruce Leak. Algorithm by Keith McGreggor.
Copyright: © 1990 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<7> 9/21/90 DDG Made changes from code review. Minor changes to reflect the new
interface to the buffering routines.
<6> 8/16/90 DDG Cleaned up the comments and optomized the CalcPopularTable
routine to save some bytes.
<5> 8/5/90 DDG Added a parameter to the RecordPopularColors routine. This
routine should still never be called.
<4> 7/31/90 DDG Fixed a bug in the RecordPopularColors routine. Note that this
routine should never be called, but better safe than sorry.
<3> 7/30/90 DDG Added stub init, record, and kill routines to support the new
extensible colorPickerMethods. Also fixed a few bugs.
<2> 7/29/90 DDG Fixed header.
<1> 7/29/90 DDG First checked in using new structure.
To Do:
*/
/*----------------------------------------------------------------------------------------------------------*/
/*
| Includes
*/
#include "puPrivate.h"
/*----------------------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------------------------------------*/
/************************************************************************************************************/
/**** Functions Follow ****/
/************************************************************************************************************/
/*----------------------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------------------------------------*/
/*
| This routine is called to initialize the popular method. It doesnt really do anything, except tell
| the main picture utilities package that it should store the colors in the ExactAnd555 format.
*/
pascal OSErr InitPopularMethod(
short colorsRequested,
long *dataHandlePtr,
short *colorBankTypePtr )
{
#pragma unused( colorsRequested )
*dataHandlePtr = nil;
*colorBankTypePtr = ColorBankIsExactAnd555;
return noErr;
}
/*----------------------------------------------------------------------------------------------------------*/
/*
| This routine is called to kill the popular method. It doesnt do anything.
*/
pascal OSErr KillPopularMethod(
long dataHandle )
{
#pragma unused( dataHandle )
return noErr;
}
/*----------------------------------------------------------------------------------------------------------*/
/*
| This routine should never be called, so it returns an error.
*/
pascal OSErr RecordPopularColors(
long dataHandle,
RGBColor *colorPtr,
long colorCount,
long *uniqueColorsPtr )
{
#pragma unused( dataHandle, colorPtr, colorCount, uniqueColorsPtr )
return cantLoadPickMethodErr;
}
/*----------------------------------------------------------------------------------------------------------*/
/*
| This returns the colors that occur most frequently in the histogram. In the case of a tie, the color with
| the higher RGB value is arbitrarily chosen.
*/
pascal OSErr CalcPopularTable(
long dataHandle,
short colorsRequested,
short *colorBankPtr,
register ColorSpec *resultPtr )
{
#pragma unused( dataHandle )
register short *histogramPtr;
register unsigned short index;
register short threshold;
register long ignoreCount;
short *countBufferPtr;
Buffer countBuffer;
unsigned short value = 0;
short uniqueColors;
OSErr error;
/*
| Allocate a buffer to hold a count of our counts. If we get the buffer, then clear it.
*/
if( error = NewBufferClear( &countBuffer, HistogramTableSize, bufferFixedType ) )
return error;
countBufferPtr = (short *)countBuffer.ptr;
/*
| Scan thru the histogram getting a "count of counts". Thus if there were two colors that each had 20 pixels
| in the image using them, we would put 2 in word number 20 of our count buffer. The variable uniqueColors ends
| up as the total number of UNIQUE colors in the histogram.
*/
uniqueColors = 0;
histogramPtr = (short *)colorBankPtr;
for(index = 0; index <= 32767; index++)
{
register unsigned short colorCount;
if( (colorCount = *(histogramPtr++)) != 0 )
{
uniqueColors++;
countBufferPtr[colorCount]++;
}
}
/*
| If, there are more colors in the table than we want to return, so do a very clever trick. We scan backwards
| thru our count buffer, totaling up the occurrances of each of the color counts. Thus if two colors had a count
| of 32767, and three colors had a count of 32766, then the countSum would start at 2 and then go to 5.
|
| As soon as the countSum is greater than the number of requested colors, then we have found our threshold.
|
| We know that there will be at least colorsRequested unique colors that have a equal or higher count than our
| count threshold. This means that we can ignore all colors in the histogram that have a lower count than our
| threshold. We can always put colors that have a count higher than our threshold into the returned color table.
| If the color has a count that is exactly equal to our threshold, then we skip over a certain number of such
| colors before putting them into the returned color table.
|
| The number of colors that we skip over is equal to the total number of colors with counts that are greater
| than or equal to our threshold MINUS the number of requested colors. This prevents us from overflowing the
| return table and returning too many colors.
|
| Note that we dont need to check the index for underflowing, since we know that there are more unique colors
| than were requested.
|
| Before we check this, we set the threshold to one and the ignoreCount to zero, so that we can use the same
| loop, even if we are requesting more colors than there are.
*/
threshold = 1;
ignoreCount = 0;
if( uniqueColors > colorsRequested )
{
register long countSum;
index = 32767;
threshold = index;
countSum = 0;
while( countSum < colorsRequested )
{
countSum += countBufferPtr[ index ];
threshold = index--;
}
ignoreCount = countSum - colorsRequested;
}
/*
| This is where we actually pull the colors out of the histogram. We make colors the same way as quickdraw does,
| as described below.
|
| To make a full 48-bit color, we spread the bits for each of the components evenly over the 16 bit range. For
| each component, we move the 5 bits to the top of the 16 bit range, and save this value. Then we shift a copy
| of this value over 5 bits and or it back into the main value. Then we shift a copy of the new main value over
| 10 bits (not 5) and or it with the main value again. The reason why we shift 10 bits instead of five is that
| we need to fill the remaining bit (bit 0) and we always have to shift in multiples of five so that oring the
| colors together doesnt change any of the bits.
|
| Every time we add a color into the table, we set the colors value field and increment our value counter.
*/
histogramPtr = (short *)colorBankPtr;
for(index = 0; index <= (unsigned short)32767; index++)
{
register unsigned short component;
short count;
if( (count = *(histogramPtr++)) >= threshold )
{
if( (count == threshold) && (ignoreCount != 0) )
{
ignoreCount--;
continue;
}
resultPtr->value = value++;
component = (index & 0x7C00) << 1;
component |= component >> 5;
component |= component >> 10;
resultPtr->rgb.red = component;
component = (index & 0x03E0) << 6;
component |= component >> 5;
component |= component >> 10;
resultPtr->rgb.green = component;
component = (index & 0x001F) << 11;
component |= component >> 5;
component |= component >> 10;
resultPtr->rgb.blue = component;
resultPtr++;
}
}
/*
| After we have returned all the colors in the histogram, we need to clear the remaining entries in the table.
| Note that the loop terminating condition will ensure that we dont execute this loop if we dont need to.
*/
colorsRequested -= uniqueColors;
while( --colorsRequested >= 0 )
{
resultPtr->value = value++;
resultPtr->rgb.red = 0;
resultPtr->rgb.green = 0;
resultPtr->rgb.blue = 0;
resultPtr++;
}
/*
| Kill the count buffer.
*/
KillBuffer( &countBuffer );
return noErr;
}
/*----------------------------------------------------------------------------------------------------------*/