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.