This is ImageReduce.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 "../strfunc.h"
#import "../ColorMap.h"
#import "imageOperation.h"
#ifdef _REDUCE_BY_MDA
# import "MDAmethod.h"
# define DitherCLASS MDAmethod
#else
# import "Dither.h"
# define DitherCLASS Dither
#endif
@implementation ImageOpr (ReduceColor)
static short tagColors[] = { /* Recude into N colors */
256, 256, 64, 16, 8
};
/* Local Method */
- (int)reduceColor:(ColorMap *)colormap info:(commonInfo *)cinf
map:(unsigned char **)map newmap:(unsigned char **)newmap
alpha:(BOOL)alpha tag:(int)tag
{
id msgtext;
paltype *pal = NULL;
int i, x, y, idx;
int trial, cnum;
id <Dithering> dither[3];
char msgbuf[80];
unsigned char *rr, *gg, *bb;
int elm[MAXPLANE];
unsigned char apool[MAXWidth];
unsigned char *alp;
static short tagOpr[] = {
/* initial value of 'trial'... index for dthbits[][] */
2, /* MCA (default reduction) */
5, /* Dither + MCA 256 colors */
7, /* Dither + MCA 64 colors */
5, /* Dither + MCA 16 colors */
5 /* Dither + MCA 8 colors */
};
static short dthbits[][3] = {
{7, 7, 7}, {7, 7, 6}, {6, 6, 6}, {6, 6, 5},
{5, 5, 5}, {5, 5, 4}, {4, 4, 4}, {4, 4, 3},
{3, 3, 3}, {3, 3, 2}, {2, 2, 2 /* never */ }};
msgtext = [theController messageDisplay:"Starting Reduction..."];
cnum = 0;
for (i = 0; i < 3; i++)
dither[i] = nil;
for (i = 0; i < 3; i++) {
dither[i] = [DitherCLASS alloc];
if (dither[i] == nil
|| [dither[i] init:128 width:cinf->width] == nil)
goto ErrEXIT;
}
resetPixel(map, 0);
idx = 0;
for (y = 0; y < cinf->height; y++) {
alp = alpha ? &newmap[ALPHA][idx] : apool;
for (x = 0; x < cinf->width; x++, idx++) {
getPixel(&elm[0], &elm[1], &elm[2], &elm[3]);
if ((alp[x] = elm[ALPHA]) == AlphaTransp) {
for (i = 0; i < 3; i++)
newmap[i][idx] = 255;
}else {
for (i = 0; i < 3; i++)
newmap[i][idx] = elm[i];
}
}
}
for (trial = tagOpr[tag]; ; trial++) {
sprintf(msgbuf, "Trying Reduction: RGB=%d:%d:%d",
dthbits[trial][0], dthbits[trial][1], dthbits[trial][2]);
[msgtext setStringValue: msgbuf];
NXPing();
for (i = 0; i < 3; i++)
[dither[i] reset:(1 << dthbits[trial][i])];
[colormap init_regColor];
for (y = 0; y < cinf->height; y++) {
for (i = 0; i < 3; i++) {
rr = [dither[i] buffer];
gg = &newmap[i][y * cinf->width];
for (x = 0; x < cinf->width; x++)
*rr++ = *gg++;
}
rr = [dither[RED] getNewLine];
gg = [dither[GREEN] getNewLine];
bb = [dither[BLUE] getNewLine];
for (x = 0; x < cinf->width; x++) {
if ([colormap regColorToMap:*rr++:*gg++:*bb++] < 0)
goto ReTRY; /* Too Many Color */
}
}
break; /* OK */
ReTRY: ;
}
[msgtext setStringValue: "Making Palette..."];
NXPing();
cnum = tagColors[tag];
pal = [colormap getReducedMap: &cnum alpha:alpha];
[msgtext setStringValue: "Writing Image..."];
NXPing();
for (i = 0; i < 3; i++)
[dither[i] reset:(1 << dthbits[trial][i])];
idx = 0;
for (y = 0; y < cinf->height; y++) {
for (i = 0; i < 3; i++) {
rr = [dither[i] buffer];
gg = &newmap[i][idx];
for (x = 0; x < cinf->width; x++)
*rr++ = *gg++;
}
rr = [dither[RED] getNewLine];
gg = [dither[GREEN] getNewLine];
bb = [dither[BLUE] getNewLine];
for (x = 0; x < cinf->width; x++, idx++) {
unsigned char *p = pal[mapping(*rr, *gg, *bb)];
for (i = 0; i < 3; i++)
newmap[i][idx] = p[i];
rr++, gg++, bb++;
}
}
ErrEXIT:
for (i = 0; i < 3; i++)
if (dither[i]) [dither[i] free];
[theController messageDisplay:NULL];
return cnum;
}
/* Local Method */
- (commonInfo *)reducedBitmap:(unsigned char **)newmap
from:(ToyWin *)tw with:(commonInfo *)cinf tag:(int)tag
{
commonInfo *newinfo = NULL;
ColorMap *colormap = nil;
unsigned char *map[MAXPLANE];
int cnum = 0, pl, err = 0;
BOOL hasalpha = NO;
const char *fnam;
newmap[0] = NULL;
fnam = [tw filename];
if ((err = [tw getBitmap:map info: &cinf]) == 0)
err = initGetPixel(cinf);
if (err) {
errAlert(fnam, err);
return NULL;
}
colormap = [[ColorMap alloc] init];
if ([colormap allocFullColor] == nil) {
err = Err_MEMORY;
goto ErrEXIT;
}else {
cnum = [colormap getAllColor:map limit:0 alpha:&hasalpha];
if (hasalpha) ++cnum;
if (cnum <= tagColors[tag]) {
(void)[self needReduce:fnam colors:cnum ask:NO];
goto ErrEXIT;
}
}
pl = hasalpha ? 4 : 3;
err = allocImage(newmap, cinf->width, cinf->height, 8, pl);
newinfo = (commonInfo *)malloc(sizeof(commonInfo));
if (!newinfo)
err = Err_MEMORY;
if (err) goto ErrEXIT;
cnum = [self reduceColor:colormap info:cinf
map:map newmap:newmap alpha:hasalpha tag:tag];
if (cnum <= 0) {
err = Err_MEMORY;
goto ErrEXIT;
}
*newinfo = *cinf;
newinfo->xbytes = newinfo->width;
newinfo->palsteps = cnum;
newinfo->bits = 8;
newinfo->numcolors = 3;
newinfo->isplanar = YES;
newinfo->alpha = hasalpha;
newinfo->palette = [colormap getPalette];
sprintf(newinfo->memo, "%d x %d %dcolors%s",
newinfo->width, newinfo->height, cnum,
(newinfo->alpha ? " Alpha" : ""));
comment_copy(newinfo->memo, cinf->memo);
if (colormap) [colormap free];
[tw freeTempBitmap];
return newinfo;
ErrEXIT:
if (err) errAlert(fnam, err);
[tw freeTempBitmap];
if (newmap[0]) free((void *)newmap[0]);
if (newinfo) free((void *)newinfo);
if (colormap) [colormap free];
return NULL;
}
- reduceUsing: (int)tag
{
ToyWin *tw, *newtw;
commonInfo *cinf;
unsigned char *map[MAXPLANE];
const char *fnam;
char fn[256];
if ((tw = [self keyParentWindow: Reduction]) == nil) {
NXBeep();
return self;
}
fnam = [tw filename];
cinf = [[tw toyView] commonInfo];
if (![self checkCommonInfo:cinf filename:fnam])
return self;
if (cinf->numcolors == 1) {
warnAlert(fnam, Err_OPR_IMPL);
return NULL;
}
if (cinf->palette && cinf->palsteps <= tagColors[tag]) {
(void)[self needReduce:fnam colors:cinf->palsteps ask:NO];
return NULL;
}
if ((cinf = [self reducedBitmap:map from:tw with:cinf tag:tag]) == NULL)
return self;
newtw = [[ToyWin alloc] init:tw by:Reduction];
if (tag == 0)
sprintf(fn, "%s(Reduce)", fnam);
else
sprintf(fn, "%s(Reduce%d)", fnam, tagColors[tag]);
[newtw initLocateWindow:fn width:cinf->width height:cinf->height];
if ([newtw drawView:map info: cinf] == nil) {
errAlert(fnam, Err_MEMORY);
[newtw free];
free((void *)map[0]);
free((void *)cinf);
}else
[theController newWindow: newtw];
return self;
}
- (BOOL)needReduce:(const char *)fn colors:(int)cnum ask:(BOOL)ask
{
const char *qust, *title, *cancel, *reduce;
qust = NXLocalizedString("No Need to Reduce", NULL, NO_Need_Reduction);
title = NXLocalizedString("WARNING", NULL, WARNING);
if (ask) {
cancel = NXLocalizedString("Cancel", NULL, Stop_SAVE);
reduce = NXLocalizedString("Reduce", NULL, BMP_Reduce);
if (NXRunAlertPanel(title, qust, cancel, reduce, NULL, fn, cnum))
return NO;
}else
NXRunAlertPanel(title, qust, NULL, NULL, NULL, fn, cnum);
return YES;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.