JPEGView/Source/C/CopyScaledFrom32.c
Aaron Giles 92bdb55672 JPEGView 3.3 for Macintosh
These are the sources for the final official release of JPEGView for the
Mac, back in 1994.
2015-02-05 00:18:10 -08:00

1 line
6.9 KiB
C

/*********************************************************/
/* This source code copyright (c) 1991-2001, Aaron Giles */
/* See the Read Me file for licensing information. */
/* Contact email: mac@aarongiles.com */
/*********************************************************/
// void CopyScaledFrom32(CopyDataPtr theData);
#define AddPixel(source, factor) \
pixel = (source),\
blue += factor * (pixel & 0xff),\
pixel >>= 8,\
green += factor * (pixel & 0xff),\
pixel >>= 8,\
red += factor * (pixel & 0xff)
DitherErrorsPtr eBuffer, // pointers to whichever dithering
oBuffer; // buffers we decide to use
ulong *scaled, // pointer to the start of the scaling buffer
*srcScaled, // temp. source pointer used during scaling
*dstScaled; // destination pointer used during scaling
Ptr src = theData->srcBase, // source pointer into original image data
dst = theData->dstBase; // dest. pointer into real destination
ulong srcPixelContributionY, // contribution in Y made by each source pixel
srcPixelContributionX, // contribution in X made by each source pixel
srcRemainingY = theData->yRemainder,// remaining Y contribution for source
srcRemainingX; // remaining X contribution for current src
ulong dstNeededY, // amount needed for complete dest. Y pixel
dstNeededX, // amount needed for complete dest. X pixel
red, green, blue, pixel; // temp. counter for rgb and holder for pixel
short *rgnPtr; // pointer to the region data
long row = theData->height, // row counter
col; // column counter
Handle dynamicBuffer; // handle to any allocation we make
RgnBuffer rgnData; // buffer for the region data
DitherErrors evenDithering[kStackRowWidth + 2], // stack-based buffers for dithering; if these
oddDithering[kStackRowWidth + 2]; // aren't enough, we allocate bigger ones
ulong scaledRow[kStackRowWidth + 2]; // stack-based buffer for scaling
// Allocate space for our buffers, if not enough room on stack
// NOTE: This only works if the machine is in 32-bit addressing mode!!!
if (theData->width > kStackRowWidth) {
dynamicBuffer = AnyNewHandle((theData->width + 2) * (2 * sizeof(DitherErrors) + sizeof(ulong)));
if (!dynamicBuffer) return;
HLock(dynamicBuffer);
eBuffer = (DitherErrorsPtr)*dynamicBuffer + 1;
oBuffer = eBuffer + theData->width + 2;
scaled = (ulong *)(oBuffer + theData->width + 1) + 1;
} else {
eBuffer = &evenDithering[1];
oBuffer = &oddDithering[1];
}
scaled = &scaledRow[1];
// Clear out the dithering and scaling buffers
if (theData->evodd & 1)
ClearMem((Ptr)&eBuffer[-1], (theData->width + 2) * sizeof(DitherErrors));
else ClearMem((Ptr)&oBuffer[-1], (theData->width + 2) * sizeof(DitherErrors));
// Initialize the region data
rgnData.zero = 0;
rgnPtr = InitRegion(*theData->theRgn, &rgnData, &theData->boxRect);
// Set up the source/destination quantities
srcPixelContributionY = (theData->dstHeight << 16) / theData->srcHeight + 1;
srcPixelContributionX = (theData->dstWidth << 16) / theData->srcWidth + 1;
// The outermost (row) loop begins here; set up our pointers into the data
while (row--) {
srcScaled = (ulong *)src;
dstScaled = (ulong *)scaled;
// reset the columns counter and reset the source X remainder
col = theData->width;
srcRemainingX = theData->xRemainder;
// The inner (column) loop begins here; set up our counters in the dest system
while (col--) {
dstNeededX = dstNeededY = 1L << 16;
red = green = blue = 0;
// Determine what sort of scaling is best for us
if (dstNeededY < srcRemainingY && dstNeededX < srcRemainingX) {
// no scaling needed for this particular destination pixel
*dstScaled++ = *srcScaled;
goto dontStore;
} else if (dstNeededY < srcRemainingY) {
// scaling needed in the X direction only
do {
AddPixel(*srcScaled++, srcRemainingX);
dstNeededX -= srcRemainingX;
srcRemainingX = srcPixelContributionX;
} while (dstNeededX > srcRemainingX);
AddPixel(*srcScaled, dstNeededX);
} else if (dstNeededX < srcRemainingX) {
// scaling needed in the Y direction only
ulong origSrcRemainingY = srcRemainingY;
ulong *srcStart = srcScaled;
do {
AddPixel(*srcScaled, srcRemainingY);
srcScaled += (theData->srcRow >> 2);
dstNeededY -= srcRemainingY;
srcRemainingY = srcPixelContributionY;
} while (dstNeededY > srcRemainingY);
if (dstNeededY) AddPixel(*srcScaled, dstNeededY);
srcScaled = srcStart;
srcRemainingY = origSrcRemainingY;
} else {
// scaling needed in both directions
ulong multiplier, origSrcRemainingX = srcRemainingX;
ulong origSrcRemainingY = srcRemainingY;
ulong *srcStart = srcScaled, *srcRowStart;
do {
srcRowStart = srcScaled;
do {
multiplier = (srcRemainingX * srcRemainingY) >> 16;
AddPixel(*srcScaled++, multiplier);
dstNeededX -= srcRemainingX;
srcRemainingX = srcPixelContributionX;
} while (dstNeededX > srcRemainingX);
multiplier = (dstNeededX * srcRemainingY) >> 16;
AddPixel(*srcScaled, multiplier);
srcRemainingX = origSrcRemainingX;
dstNeededX = 1L << 16;
srcScaled = srcRowStart + (theData->srcRow >> 2);
dstNeededY -= srcRemainingY;
srcRemainingY = srcPixelContributionY;
} while (dstNeededY > srcRemainingY);
do {
multiplier = (srcRemainingX * dstNeededY) >> 16;
AddPixel(*srcScaled++, multiplier);
srcStart++;
dstNeededX -= srcRemainingX;
srcRemainingX = srcPixelContributionX;
} while (dstNeededX > srcRemainingX);
multiplier = (dstNeededX * dstNeededY) >> 16;
AddPixel(*srcScaled, multiplier);
srcScaled = srcStart;
srcRemainingY = origSrcRemainingY;
}
pixel = red >> 16;
pixel <<= 8;
pixel += green >> 16;
pixel <<= 8;
pixel += blue >> 16;
*dstScaled++ = pixel;
// apply the final adjustment to the X counters
dontStore:
if (!(srcRemainingX -= dstNeededX)) {
srcScaled++;
srcRemainingX = srcPixelContributionX;
}
}
// We now have a row; set up to do a dithered copy from it
if ((++theData->evodd) & 1)
theData->odd(scaled, dst, theData->itAddr, theData->ctAddr, eBuffer, oBuffer,
rgnData.buffer, theData->errTable, theData->width);
else theData->even(scaled, dst, theData->itAddr, theData->ctAddr, eBuffer, oBuffer,
rgnData.buffer, theData->errTable, theData->width);
if (!row) break;
if (!--rgnData.yCount) rgnPtr = UpdateRegion(rgnPtr, &rgnData, &theData->boxRect);
// apply final adjustments to the Y counters
dstNeededY = 1L << 16;
while (dstNeededY >= srcRemainingY) {
src += theData->srcRow;
dstNeededY -= srcRemainingY;
srcRemainingY = srcPixelContributionY;
}
srcRemainingY -= dstNeededY;
dst += theData->dstRow;
}
// Return space allocated for buffers
if (theData->width > kStackRowWidth) DisposeHandle(dynamicBuffer);