This is Scale.m in view mode; [Download] [Up]
/* Copyright (c) 1992 Linus Upson & The Geometry Center
University of Minnesota
1300 South Second Street
Minneapolis, MN 55454, USA
lupson@geom.umn.edu
*/
#import "Scale.h"
#import <math.h>
@implementation Scale
static unsigned char fourToEight_upper[256];
static unsigned char fourToEight_lower[256];
static unsigned char twoToEight_upper[256];
static unsigned char twoToEight_upperMiddle[256];
static unsigned char twoToEight_lowerMiddle[256];
static unsigned char twoToEight_lower[256];
static void print_info (const char *string, NXBitmapImageRep *bitmap)
{
printf ("%s\n", string);
printf (" bitsPerPixel %d\n", (int)[bitmap bitsPerPixel]);
printf (" samplesPerPixel %d\n", (int)[bitmap samplesPerPixel]);
printf (" bitsPerSample (NXImageRep) %d\n", (int)[bitmap bitsPerSample]);
printf (" isPlanar %d\n", (int)[bitmap isPlanar]);
printf (" numPlanes %d\n", (int)[bitmap numPlanes]);
printf (" numColors (NXImageRep) %d\n", (int)[bitmap numColors]);
printf (" hasAlpha (NXImageRep) %d\n", (int)[bitmap hasAlpha]);
printf (" bytesPerPlane %d\n", (int)[bitmap bytesPerPlane]);
printf (" bytesPerRow %d\n", (int)[bitmap bytesPerRow]);
printf (" colorSpace %d\n", (int)[bitmap colorSpace]);
printf (" pixelsWide (NXImageRep) %d\n", (int)[bitmap pixelsWide]);
printf (" pixelsHigh (NXImageRep) %d\n", (int)[bitmap pixelsHigh]);
printf ("\n");
}
static void convertFourBPSMeshed (NXBitmapImageRep *inBitmap,
NXBitmapImageRep *outBitmap)
{
int i, j, width, height, samplesPerPixel;
int inBytesPerRow, outBytesPerRow, inWordsPerRow, inRemainderSamples;
unsigned char *inData, *inPtr, *outData, *outPtr;
width = [inBitmap pixelsWide];
height = [inBitmap pixelsHigh];
samplesPerPixel = [inBitmap samplesPerPixel];
inData = [inBitmap data];
outData = [outBitmap data];
inBytesPerRow = [inBitmap bytesPerRow];
outBytesPerRow = [outBitmap bytesPerRow];
inWordsPerRow = inBytesPerRow / 4;
inRemainderSamples = (width * samplesPerPixel - inWordsPerRow * 8);
for (i = 0; i < height; i++) {
outPtr = outData + i * outBytesPerRow;
inPtr = inData + i * inBytesPerRow;
for (j = 0; j < inWordsPerRow; j++) {
*outPtr++ = fourToEight_upper[*inPtr];
*outPtr++ = fourToEight_lower[*inPtr++];
*outPtr++ = fourToEight_upper[*inPtr];
*outPtr++ = fourToEight_lower[*inPtr++];
*outPtr++ = fourToEight_upper[*inPtr];
*outPtr++ = fourToEight_lower[*inPtr++];
*outPtr++ = fourToEight_upper[*inPtr];
*outPtr++ = fourToEight_lower[*inPtr++];
}
for (j = 0; j < inRemainderSamples; j++) {
*outPtr++ = fourToEight_upper[*inPtr];
if (++j < inRemainderSamples)
*outPtr++ = fourToEight_lower[*inPtr++];
}
}
}
static void convertTwoBPSPlanar (NXBitmapImageRep *inBitmap,
NXBitmapImageRep *outBitmap)
{
int i, j, k, width, height;
int inBytesPerRow, inWordsPerRow, inRemainderSamples;
int numPlanes, outBytesPerRow;
unsigned char *inPlanes[5], *inPlanePtr[5], *outData, *outPtr;
width = [inBitmap pixelsWide];
height = [inBitmap pixelsHigh];
numPlanes = [inBitmap numPlanes];
[inBitmap getDataPlanes:inPlanes];
inBytesPerRow = [inBitmap bytesPerRow];
inWordsPerRow = inBytesPerRow / 4;
inRemainderSamples = width - inWordsPerRow * 16;
outData = [outBitmap data];
outBytesPerRow = [outBitmap bytesPerRow];
for (i = 0; i < height; i++) {
outPtr = outData + i * outBytesPerRow;
for (k = 0; k < numPlanes; k++)
inPlanePtr[k] = inPlanes[k] + i * inBytesPerRow;
for (j = 0; j < inWordsPerRow * 4; j++) {
for (k = 0; k < numPlanes; k++)
*outPtr++ = twoToEight_upper[*inPlanePtr[k]];
for (k = 0; k < numPlanes; k++)
*outPtr++ = twoToEight_upperMiddle[*inPlanePtr[k]];
for (k = 0; k < numPlanes; k++)
*outPtr++ = twoToEight_lowerMiddle[*inPlanePtr[k]];
for (k = 0; k < numPlanes; k++)
*outPtr++ = twoToEight_lower[*inPlanePtr[k]++];
}
for (j = 0; j < inRemainderSamples; j++) {
for (k = 0; k < numPlanes; k++)
*outPtr++ = twoToEight_upper[*inPlanePtr[k]];
if (++j < inRemainderSamples)
for (k = 0; k < numPlanes; k++)
*outPtr++ = twoToEight_upperMiddle[*inPlanePtr[k]];
if (++j < inRemainderSamples)
for (k = 0; k < numPlanes; k++)
*outPtr++ = twoToEight_lowerMiddle[*inPlanePtr[k]];
if (++j < inRemainderSamples)
for (k = 0; k < numPlanes; k++)
*outPtr++ = twoToEight_lower[*inPlanePtr[k]++];
}
}
}
static void convertEightBPSPlanar (NXBitmapImageRep *inBitmap,
NXBitmapImageRep *outBitmap)
{
int i, j, k, width, height, numPlanes;
int inBytesPerRow, outBytesPerRow;
unsigned char *inPlanes[5], *inPlanePtr[5], *outData, *outPtr;
width = [inBitmap pixelsWide];
height = [inBitmap pixelsHigh];
numPlanes = [inBitmap numPlanes];
[inBitmap getDataPlanes:inPlanes];
inBytesPerRow = [inBitmap bytesPerRow];
outData = [outBitmap data];
outBytesPerRow = [outBitmap bytesPerRow];
for (i = 0; i < height; i++) {
outPtr = outData + i * outBytesPerRow;
for (k = 0; k < numPlanes; k++)
inPlanePtr[k] = inPlanes[k] + i * inBytesPerRow;
for (j = 0; j < inBytesPerRow; j++) {
for (k = 0; k < numPlanes; k++)
*outPtr++ = *inPlanePtr[k]++;
}
}
}
- init
{
[super init];
scratchZone = NXCreateZone (vm_page_size, vm_page_size, YES);
return self;
}
- buildTables:(int)seed
{
int i;
double dx, dy, dz, rr;
// Build the different bitmap conversion tables.
for (i = 0; i < 256; i++) {
fourToEight_upper[i] = ((i >> 4) * 17);
fourToEight_lower[i] = ((i & 0x0F) * 17);
twoToEight_upper[i] = ((i >> 6) * 85);
twoToEight_upperMiddle[i] = (((i & 0x30) >> 4) * 85);
twoToEight_lowerMiddle[i] = (((i & 0x0C) >> 2) * 85);
twoToEight_lower[i] = ((i & 0x03) * 85);
}
// Build a table of points whose density falls off as:
// 1./sqrt (2.*M_PI*sigma) * exp (r*r/(2.*sigma*sigma))
srandom (seed);
for (i = 0; i < NUM_POINTS; i++) {
do {
dx = 1. - 4. * (double)random () / (double)(0xFFFFFFFF);
dy = 1. - 4. * (double)random () / (double)(0xFFFFFFFF);
dz = (double)random () / (double)(0xFFFFFFFF);
rr = dx * dx + dy * dy;
} while (dz > exp (-2. * rr) || rr > 1.);
jitterPoint[i].x = dx;
jitterPoint[i].y = dy;
}
jit = jitMin = jitterPoint;
jitMax = jitterPoint + NUM_POINTS;
tablesBuilt = YES;
return self;
}
- resetJitterIndex
{
jit = jitMin;
return self;
}
- (NXBitmapImageRep *)convertBitmap:(NXBitmapImageRep *)inBitmap
{
int bps;
BOOL planar;
NXBitmapImageRep *standardBitmap;
bps = [inBitmap bitsPerSample];
planar = [inBitmap isPlanar];
// If the bitmap is already 8 bits per sample and in meshed
// configuration, we don't need to do any conversion.
if (bps == 8 && !planar) {
freeStandardBitmap = NO;
return inBitmap;
}
// Make space for a bitmap that is one byte for each sample and meshed.
// Be sure to remember to free it.
freeStandardBitmap = YES;
standardBitmap = [[NXBitmapImageRep allocFromZone:scratchZone]
initData:NULL
pixelsWide:inWidth
pixelsHigh:inHeight
bitsPerSample:8
samplesPerPixel:[inBitmap samplesPerPixel]
hasAlpha:[inBitmap hasAlpha]
isPlanar:NO
colorSpace:[inBitmap colorSpace]
bytesPerRow:0
bitsPerPixel:0];
// Currently the Scale filter only supports the following bitmap formats:
// 4 bits per sample meshed (NeXT Station Color).
// 2 bits per sample planar (NeXT Station & Cube).
// 8 bits per sample planar (Eight bit Gray).
// 8 bits per sample meshed (NeXT Dimension) -- no conversion needed.
if (bps == 4 && !planar)
convertFourBPSMeshed (inBitmap, standardBitmap);
else if (bps == 2 && planar)
convertTwoBPSPlanar (inBitmap, standardBitmap);
else if (bps == 8 && planar)
convertEightBPSPlanar (inBitmap, standardBitmap);
else {
[standardBitmap free];
standardBitmap = nil;
}
return standardBitmap;
}
- (NXBitmapImageRep *)scaleBitmap:(NXBitmapImageRep *)inBitmap
{
int i, j, k, l, x, y;
int inBytesPerRow, outBytesPerRow, spp, accbuf[5];
float s, t;
unsigned char *inData, *inPtr, *outData, *outPtr;
NXBitmapImageRep *outBitmap;
inData = [inBitmap data];
inBytesPerRow = [inBitmap bytesPerRow];
spp = [inBitmap samplesPerPixel];
outBitmap = [[NXBitmapImageRep allocFromZone:scratchZone]
initData:NULL
pixelsWide:outWidth
pixelsHigh:outHeight
bitsPerSample:8
samplesPerPixel:spp
hasAlpha:[inBitmap hasAlpha]
isPlanar:NO
colorSpace:[inBitmap colorSpace]
bytesPerRow:0
bitsPerPixel:0];
outData = [outBitmap data];
outBytesPerRow = [outBitmap bytesPerRow];
for (i = 0; i < outHeight; i++) {
outPtr = outData + i * outBytesPerRow;
for (j = 0; j < outWidth; j++) {
for (l = 0; l < spp; l++)
accbuf[l] = 0.;
for (k = 0; k < samples; k++) {
if (++jit == jitMax) jit = jitMin;
s = ((float)j + .5 + focus * jit->x) / scale;
t = ((float)i + .5 + focus * jit->y) / scale;
if (++jit == jitMax) jit = jitMin;
x = (int)(s + .5 + focus * jit->x);
y = (int)(t + .5 + focus * jit->y);
if (x < 0)
x = 0;
else if (x >= inWidth)
x = inWidth - 1;
if (y < 0)
y = 0;
else if (y >= inHeight)
y = inHeight - 1;
inPtr = inData + y * inBytesPerRow + x * spp;
for (l = 0; l < spp; l++)
accbuf[l] += inPtr[l];
}
for (l = 0; l < spp; l++)
*outPtr++ = (unsigned char)(accbuf[l] / samples);
}
}
return outBitmap;
}
- filter:(NXBitmapImageRep *)inBitmap
{
NXBitmapImageRep *standardBitmap, *scaledBitmap;
// Do a quick reality check.
if (![inBitmap pixelsWide] || ![inBitmap pixelsHigh]) return nil;
// Read relevant parameters out of the text fields.
focus = [focusField floatValue];
samples = 256;
// Determine the input and output sizes in pixels
inWidth = [inBitmap pixelsWide];
inHeight = [inBitmap pixelsHigh];
outWidth = outHeight= [outSizeField intValue];
// Figure out the scale factor given the input and output sizes.
scale = (float)outWidth / (float)inWidth;
// If this is the first time the filter has been called, build the tables
// used in jittering and bitmap format conversion.
if (!tablesBuilt)
[self buildTables:1];
// Convert the bitmap into one that is eight bits per sample
// and in meshed configuration.
if (!(standardBitmap = [self convertBitmap:inBitmap])) {
print_info ("Unknown bitmap format.", inBitmap);
return nil;
}
// Actually do the scaling.
scaledBitmap = [self scaleBitmap:standardBitmap];
// If we had to do conversion of the input bitmap, free the tmp one
// in the standard format we created.
if (freeStandardBitmap) [standardBitmap free];
[inBitmap free];
// Return the 8 bit per sample bitmap.
return scaledBitmap;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.