home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / Graphics / ToyViewer-2.6a / src / ImageOpr.bproj / ImageReduce.m < prev    next >
Encoding:
Text File  |  1996-10-04  |  7.2 KB  |  290 lines

  1. #import "../ImageOpr.h"
  2. #import <appkit/Application.h>
  3. #import <appkit/publicWraps.h>
  4. #import <appkit/NXBitmapImageRep.h>
  5. #import <appkit/Control.h>
  6. #import <appkit/Panel.h>
  7. #import <appkit/TextField.h>
  8. #import <stdio.h>
  9. #import <stdlib.h>
  10. #import <string.h>
  11. #import <libc.h>
  12. #import <streams/streams.h>
  13. #import "../TVController.h"
  14. #import "../ToyWin.h"
  15. #import "../ToyWinEPS.h"
  16. #import "../ToyView.h"
  17. #import "../common.h"
  18. #import "../getpixel.h"
  19. #import "../strfunc.h"
  20. #import "../ColorMap.h"
  21. #import "imageOperation.h"
  22. #ifdef _REDUCE_BY_MDA
  23. # import "MDAmethod.h"
  24. # define DitherCLASS    MDAmethod
  25. #else
  26. # import "Dither.h"
  27. # define DitherCLASS    Dither
  28. #endif
  29.  
  30. @implementation ImageOpr (ReduceColor)
  31.  
  32. static short tagColors[] = { /* Recude into N colors */
  33.     256, 256, 64, 16, 8
  34. };
  35.  
  36. /* Local Method */
  37. - (int)reduceColor:(ColorMap *)colormap info:(commonInfo *)cinf
  38.     map:(unsigned char **)map newmap:(unsigned char **)newmap
  39.     alpha:(BOOL)alpha tag:(int)tag
  40. {
  41.     id    msgtext;
  42.     paltype *pal = NULL;
  43.     int i, x, y, idx;
  44.     int trial, cnum;
  45.     id <Dithering> dither[3];
  46.     char msgbuf[80];
  47.     unsigned char *rr, *gg, *bb;
  48.     int elm[MAXPLANE];
  49.     unsigned char apool[MAXWidth];
  50.     unsigned char *alp;
  51.     static short tagOpr[] = {
  52.     /* initial value of 'trial'... index for dthbits[][] */
  53.         2, /* MCA (default reduction) */
  54.         5, /* Dither + MCA 256 colors */
  55.         7, /* Dither + MCA  64 colors */
  56.         5, /* Dither + MCA  16 colors */
  57.         5  /* Dither + MCA   8 colors */
  58.     };
  59.     static short dthbits[][3] = {
  60.         {7, 7, 7}, {7, 7, 6}, {6, 6, 6}, {6, 6, 5},
  61.         {5, 5, 5}, {5, 5, 4}, {4, 4, 4}, {4, 4, 3},
  62.         {3, 3, 3}, {3, 3, 2}, {2, 2, 2 /* never */ }};
  63.  
  64.     msgtext = [theController messageDisplay:"Starting Reduction..."];
  65.  
  66.     cnum = 0;
  67.     for (i = 0; i < 3; i++)
  68.         dither[i] = nil;
  69.     for (i = 0; i < 3; i++) {
  70.         dither[i] = [DitherCLASS alloc];
  71.         if (dither[i] == nil
  72.             || [dither[i] init:128 width:cinf->width] == nil)
  73.             goto ErrEXIT;
  74.     }
  75.  
  76.     resetPixel(map, 0);
  77.     idx = 0;
  78.     for (y = 0; y < cinf->height; y++) {
  79.         alp = alpha ? &newmap[ALPHA][idx] : apool;
  80.         for (x = 0; x < cinf->width; x++, idx++) {
  81.             getPixel(&elm[0], &elm[1], &elm[2], &elm[3]);
  82.             if ((alp[x] = elm[ALPHA]) == AlphaTransp) {
  83.                 for (i = 0; i < 3; i++)
  84.                     newmap[i][idx] = 255;
  85.             }else {
  86.                 for (i = 0; i < 3; i++)
  87.                     newmap[i][idx] = elm[i];
  88.             }
  89.         }
  90.     }
  91.  
  92.     for (trial = tagOpr[tag]; ; trial++) {
  93.         sprintf(msgbuf, "Trying Reduction: RGB=%d:%d:%d",
  94.         dthbits[trial][0], dthbits[trial][1], dthbits[trial][2]);
  95.         [msgtext setStringValue: msgbuf];
  96.         NXPing();
  97.  
  98.         for (i = 0; i < 3; i++)
  99.         [dither[i] reset:(1 << dthbits[trial][i])];
  100.         [colormap init_regColor];
  101.         for (y = 0; y < cinf->height; y++) {
  102.         for (i = 0; i < 3; i++) {
  103.             rr = [dither[i] buffer];
  104.             gg = &newmap[i][y * cinf->width];
  105.             for (x = 0; x < cinf->width; x++)
  106.                 *rr++ = *gg++;
  107.         }
  108.         rr = [dither[RED] getNewLine];
  109.         gg = [dither[GREEN] getNewLine];
  110.         bb = [dither[BLUE] getNewLine];
  111.         for (x = 0; x < cinf->width; x++) {
  112.             if ([colormap regColorToMap:*rr++:*gg++:*bb++] < 0)
  113.                 goto ReTRY;    /* Too Many Color */
  114.         }
  115.         }
  116.         break;    /* OK */
  117. ReTRY:        ;
  118.     }
  119.  
  120.     [msgtext setStringValue: "Making Palette..."];
  121.     NXPing();
  122.     cnum = tagColors[tag];
  123.     pal = [colormap getReducedMap: &cnum alpha:alpha];
  124.     [msgtext setStringValue: "Writing Image..."];
  125.     NXPing();
  126.  
  127.     for (i = 0; i < 3; i++)
  128.         [dither[i] reset:(1 << dthbits[trial][i])];
  129.     idx = 0;
  130.     for (y = 0; y < cinf->height; y++) {
  131.         for (i = 0; i < 3; i++) {
  132.             rr = [dither[i] buffer];
  133.             gg = &newmap[i][idx];
  134.             for (x = 0; x < cinf->width; x++)
  135.                 *rr++ = *gg++;
  136.         }
  137.         rr = [dither[RED] getNewLine];
  138.         gg = [dither[GREEN] getNewLine];
  139.         bb = [dither[BLUE] getNewLine];
  140.         for (x = 0; x < cinf->width; x++, idx++) {
  141.             unsigned char *p = pal[mapping(*rr, *gg, *bb)];
  142.             for (i = 0; i < 3; i++)
  143.                 newmap[i][idx] = p[i];
  144.             rr++, gg++, bb++;
  145.         }
  146.     }
  147.  
  148. ErrEXIT:
  149.     for (i = 0; i < 3; i++)
  150.         if (dither[i]) [dither[i] free];
  151.     [theController messageDisplay:NULL];
  152.     return cnum;
  153. }
  154.  
  155.  
  156. /* Local Method */
  157. - (commonInfo *)reducedBitmap:(unsigned char **)newmap
  158.     from:(ToyWin *)tw with:(commonInfo *)cinf tag:(int)tag
  159. {
  160.     commonInfo *newinfo = NULL;
  161.     ColorMap *colormap = nil;
  162.     unsigned char *map[MAXPLANE];
  163.     int    cnum = 0, pl, err = 0;
  164.     BOOL    hasalpha = NO;
  165.     const char *fnam;
  166.  
  167.     newmap[0] = NULL;
  168.     fnam = [tw filename];
  169.     if ((err = [tw getBitmap:map info: &cinf]) == 0)
  170.         err = initGetPixel(cinf);
  171.     if (err) {
  172.         errAlert(fnam, err);
  173.         return NULL;
  174.     }
  175.  
  176.     colormap = [[ColorMap alloc] init];
  177.     if ([colormap allocFullColor] == nil) {
  178.         err = Err_MEMORY;
  179.         goto ErrEXIT;
  180.     }else {
  181.         cnum = [colormap getAllColor:map limit:0 alpha:&hasalpha];
  182.         if (hasalpha) ++cnum;
  183.         if (cnum <= tagColors[tag]) {
  184.             (void)[self needReduce:fnam colors:cnum ask:NO];
  185.             goto ErrEXIT;
  186.         }
  187.     }
  188.     pl = hasalpha ? 4 : 3;
  189.     err = allocImage(newmap, cinf->width, cinf->height, 8, pl);
  190.     newinfo = (commonInfo *)malloc(sizeof(commonInfo));
  191.     if (!newinfo)
  192.         err = Err_MEMORY;
  193.     if (err) goto ErrEXIT;
  194.  
  195.     cnum = [self reduceColor:colormap info:cinf
  196.             map:map newmap:newmap alpha:hasalpha tag:tag];
  197.     if (cnum <= 0) {
  198.         err = Err_MEMORY;
  199.         goto ErrEXIT;
  200.     }
  201.     *newinfo = *cinf;
  202.     newinfo->xbytes = newinfo->width;
  203.     newinfo->palsteps = cnum;
  204.     newinfo->bits = 8;
  205.     newinfo->numcolors = 3;
  206.     newinfo->isplanar = YES;
  207.     newinfo->alpha = hasalpha;
  208.     newinfo->palette = [colormap getPalette];
  209.     sprintf(newinfo->memo, "%d x %d  %dcolors%s",
  210.             newinfo->width, newinfo->height, cnum,
  211.             (newinfo->alpha ? "  Alpha" : ""));
  212.     comment_copy(newinfo->memo, cinf->memo);
  213.  
  214.     if (colormap) [colormap free];
  215.     [tw freeTempBitmap];
  216.     return newinfo;
  217.  
  218. ErrEXIT:
  219.     if (err) errAlert(fnam, err);
  220.     [tw freeTempBitmap];
  221.     if (newmap[0]) free((void *)newmap[0]);
  222.     if (newinfo) free((void *)newinfo);
  223.     if (colormap) [colormap free];
  224.     return NULL;
  225. }
  226.  
  227.  
  228. - reduceUsing: (int)tag
  229. {
  230.     ToyWin        *tw, *newtw;
  231.     commonInfo    *cinf;
  232.     unsigned char    *map[MAXPLANE];
  233.     const char *fnam;
  234.     char    fn[256];
  235.  
  236.     if ((tw = [self keyParentWindow: Reduction]) == nil) {
  237.         NXBeep();
  238.         return self;
  239.     }
  240.     fnam = [tw filename];
  241.     cinf = [[tw toyView] commonInfo];
  242.     if (![self checkCommonInfo:cinf filename:fnam])
  243.         return self;
  244.  
  245.     if (cinf->numcolors == 1) {
  246.         warnAlert(fnam, Err_OPR_IMPL);
  247.         return NULL;
  248.     }
  249.     if (cinf->palette && cinf->palsteps <= tagColors[tag]) {
  250.         (void)[self needReduce:fnam colors:cinf->palsteps ask:NO];
  251.         return NULL;
  252.     }
  253.  
  254.     if ((cinf = [self reducedBitmap:map from:tw with:cinf tag:tag]) == NULL)
  255.         return self;
  256.     newtw = [[ToyWin alloc] init:tw by:Reduction];
  257.     if (tag == 0)
  258.         sprintf(fn, "%s(Reduce)", fnam);
  259.     else
  260.         sprintf(fn, "%s(Reduce%d)", fnam, tagColors[tag]);
  261.     [newtw initLocateWindow:fn width:cinf->width height:cinf->height];
  262.     if ([newtw drawView:map info: cinf] == nil) {
  263.         errAlert(fnam, Err_MEMORY);
  264.         [newtw free];
  265.         free((void *)map[0]);
  266.         free((void *)cinf);
  267.     }else
  268.         [theController newWindow: newtw];
  269.     return self;
  270. }
  271.  
  272.  
  273. - (BOOL)needReduce:(const char *)fn colors:(int)cnum ask:(BOOL)ask
  274. {
  275.     const char *qust, *title, *cancel, *reduce;
  276.  
  277.     qust = NXLocalizedString("No Need to Reduce", NULL, NO_Need_Reduction);
  278.     title = NXLocalizedString("WARNING", NULL, WARNING);
  279.     if (ask) {
  280.         cancel = NXLocalizedString("Cancel", NULL, Stop_SAVE);
  281.         reduce = NXLocalizedString("Reduce", NULL, BMP_Reduce);
  282.         if (NXRunAlertPanel(title, qust, cancel, reduce, NULL, fn, cnum))
  283.         return NO;
  284.     }else
  285.         NXRunAlertPanel(title, qust, NULL, NULL, NULL, fn, cnum);
  286.     return YES;
  287. }
  288.  
  289. @end
  290.