This is ImageCChange.m in view mode; [Download] [Up]
#import "../ImageOpr.h"
#import <appkit/Application.h>
#import <appkit/publicWraps.h>
#import <appkit/NXBitmapImageRep.h>
#import <appkit/Control.h>
#import <appkit/Panel.h>
#import <appkit/TextField.h>
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
#import <libc.h>
#import <streams/streams.h>
#import "../TVController.h"
#import "../ToyWin.h"
#import "../ToyWinEPS.h"
#import "../ToyView.h"
#import "../common.h"
#import "../getpixel.h"
#import "imageOperation.h"
@implementation ImageOpr (ColorReplace)
#define CLR_THRESHOLD (32 * 32 * 3)
#define BRT_THRESHOLD (64 * 3)
#define MONO_THRESHOLD 128
static BOOL isMono;
static const int *origClr;
static int origbrite, cthresh, bthreshm, bthreshp;
static void initNearColor(const int *orig, float comparison, int cnum)
{
origClr = orig;
if (cnum < 3) {
isMono = YES;
origbrite = orig[0];
bthreshm = orig[0] - MONO_THRESHOLD * comparison;
bthreshp = orig[0] + MONO_THRESHOLD * comparison;
}else {
isMono = NO;
origbrite = Bright255(orig[RED], orig[GREEN], orig[BLUE]);
bthreshm = origbrite - BRT_THRESHOLD * comparison;
bthreshp = origbrite + BRT_THRESHOLD * comparison;
cthresh = CLR_THRESHOLD * comparison;
}
}
static BOOL isNearColor(const int *elm)
{
int i, brt;
double dif, d, fr;
if (isMono)
return (elm[0] < bthreshp && elm[0] > bthreshm);
brt = Bright255(elm[RED], elm[GREEN], elm[BLUE]);
if (brt > bthreshp || brt < bthreshm) /* compare brightness */
return NO;
if (brt == 0 || brt == 255 * 3)
return YES; /* White/Black within allowed brightness */
fr = (float)origbrite / brt;
for (dif = 0, i = 0; i < 3; i++) {
d = fr * elm[i] - origClr[i];
dif += d * d;
}
if (dif < cthresh)
return YES;
fr = (255.0 * 3 - origClr[GREEN]) / (255.0 * 3 - elm[GREEN]);
for (dif = 0, i = 0; i < 3; i++) {
d = fr * (255.0 - elm[i]) - (255.0 - origClr[i]);
dif += d * d;
}
if (dif < cthresh)
return YES;
return NO;
}
static commonInfo *makeClrChangeMap(const int *origclr, const int *newclr,
float comparison, BOOL uniform, BOOL outside,
commonInfo *cinf, NXRect *selrect,
const unsigned char *map[], unsigned char *newmap[])
{
commonInfo *newinf = NULL;
int pn, alp, cn;
int x, y, i;
int xorg=0, yorg=0, xend=0, yend=0;
newmap[0] = NULL;
if (selrect == NULL
|| selrect->size.width <= 0 || selrect->size.height <= 0
|| (selrect->size.width >= cinf->width &&
selrect->size.height >= cinf->height))
selrect = NULL;
else {
xorg = selrect->origin.x;
xend = selrect->size.width + xorg - 1;
yorg = cinf->height -
(selrect->origin.y + selrect->size.height);
yend = cinf->height - selrect->origin.y - 1;
}
if ((newinf = (commonInfo *)malloc(sizeof(commonInfo))) == NULL)
goto ErrEXIT;
*newinf = *cinf;
newinf->palette = NULL;
newinf->palsteps = 0;
newinf->isplanar = YES;
newinf->bits = 8;
newinf->xbytes = newinf->width;
if (cinf->alpha && origclr[ALPHA] == AlphaTransp && selrect == NULL)
newinf->alpha = NO;
if (newclr[ALPHA] == AlphaTransp)
newinf->alpha = YES;
if (cinf->numcolors == 1) {
if (newclr[RED] != newclr[GREEN]
|| newclr[RED] != newclr[BLUE]) {
newinf->numcolors = 3;
newinf->cspace = NX_RGBColorSpace;
}else
newinf->cspace = NX_OneIsWhiteColorSpace;
}
pn = cn = (newinf->numcolors == 1) ? 1 : 3;
if (newinf->alpha) alp = pn++;
else alp = 0;
initNearColor(origclr, comparison, cn);
if (allocImage(newmap, newinf->width, newinf->height, 8, pn))
goto ErrEXIT;
if (initGetPixel(cinf) != 0)
goto ErrEXIT;
resetPixel(map, 0);
for (y = 0; y < newinf->height; y++) {
int elm[MAXPLANE], gen[MAXPLANE];
const int *cp;
BOOL selflag = selrect ? (yorg <= y && y <= yend) : NO;
int ptr = newinf->width * y;
for (x = 0; x < newinf->width; x++, ptr++) {
getPixel(&elm[RED], &elm[GREEN], &elm[BLUE], &elm[ALPHA]);
if (selrect == NULL ||
(outside ^ (selflag && xorg <= x && x <= xend))) {
if (origclr[ALPHA] == AlphaTransp)
cp = (elm[ALPHA] == AlphaTransp) ? newclr : elm;
else if (elm[ALPHA] == AlphaTransp)
cp = elm; /* origclr[ALPHA] != AlphaTransp */
else if (comparison == 0.0) {
for (i = 0; i < cn; i++)
if (origclr[i] != elm[i]) break;
cp = (i >= cn) ? newclr : elm;
}else if (isNearColor(elm)) {
if (uniform) cp = newclr;
else {
int d;
for (i = 0; i < cn; i++) {
d = elm[i] - origclr[i] + newclr[i];
gen[i] = (d>255)? 255: ((d<0)? 0: d);
}
if (alp) gen[ALPHA] = newclr[ALPHA];
cp = gen;
}
}else
cp = elm;
}else
cp = elm;
for (i = 0; i < cn; i++)
newmap[i][ptr] = cp[i];
if (alp)
newmap[alp][ptr] = cp[ALPHA];
}
}
return newinf;
ErrEXIT:
if (newinf)
free((void *)newinf);
if (newmap[0]) free((void *)newmap[0]);
return NULL;
}
- colorChange:(int *)origclr to:(int *)newclr with:(float)comparison
uniformly:(BOOL)uniform area:(BOOL)outside
{
ToyWin *tw, *newtw = nil;
ToyView *tv = nil;
commonInfo *cinf, *newinf;
const char *fnam;
char fn[256];
NXBitmapImageRep *rep;
unsigned char *map[MAXPLANE], *newmap[MAXPLANE];
int i;
for (i = 0; i < 4; i++)
if (origclr[i] != newclr[i]) break;
if (i >= 4 /* Same Color */
|| (tw = [theController keyWindow]) == nil) {
NXBeep();
return self;
}
tv = [tw toyView];
cinf = [tv commonInfo];
if (!cinf->alpha && origclr[ALPHA] == AlphaTransp) {
NXBeep();
return self;
}
fnam = [tw filename];
if (![self checkCommonInfo:cinf filename:fnam])
return self;
sprintf(fn, "%s(ColorChange)", fnam);
rep = (NXBitmapImageRep *)[[tv image] bestRepresentation];
[rep getDataPlanes: map];
newinf = makeClrChangeMap(origclr, newclr, comparison,
uniform, outside, cinf, [tv selectedScaledRect], map, newmap);
if (newinf == NULL) {
warnAlert(fnam, Err_MEMORY);
return self;
}
newtw = [[ToyWin alloc] init:tw by:ColorChange];
[newtw initLocateWindow:fn width:newinf->width height:newinf->height];
[newtw makeComment: newinf from: cinf];
[newtw drawView:newmap info: newinf];
[theController newWindow: newtw];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.