home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / gbmsrc.zip / gbmbpp.c < prev    next >
C/C++ Source or Header  |  1998-12-31  |  15KB  |  633 lines

  1. /*
  2.  
  3. gbmbpp.c - Change bits per pixel in a General Bitmap
  4.  
  5. */
  6.  
  7. /*...sincludes:0:*/
  8. #include <stdio.h>
  9. #include <ctype.h>
  10. #include <string.h>
  11. #include <stddef.h>
  12. #include <stdlib.h>
  13. #include <stdarg.h>
  14. #include <memory.h>
  15. #include <malloc.h>
  16. #if defined(AIX) || defined(LINUX)
  17. #include <unistd.h>
  18. #else
  19. #include <io.h>
  20. #endif
  21. #include <fcntl.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #ifndef O_BINARY
  25. #define    O_BINARY    0
  26. #endif
  27. #include "gbm.h"
  28. #include "gbmerr.h"
  29. #include "gbmtrunc.h"
  30. #include "gbmht.h"
  31. #include "gbmhist.h"
  32. #include "gbmmcut.h"
  33.  
  34. /*...vgbm\46\h:0:*/
  35. /*...vgbmerr\46\h:0:*/
  36. /*...vgbmtrunc\46\h:0:*/
  37. /*...vgbmht\46\h:0:*/
  38. /*...vgbmhist\46\h:0:*/
  39. /*...vgbmmcut\46\h:0:*/
  40. /*...e*/
  41.  
  42. static char progname[] = "gbmbpp";
  43.  
  44. /*...sfatal:0:*/
  45. static void fatal(const char *fmt, ...)
  46.     {
  47.     va_list    vars;
  48.     char s[256+1];
  49.  
  50.     va_start(vars, fmt);
  51.     vsprintf(s, fmt, vars);
  52.     va_end(vars);
  53.     fprintf(stderr, "%s: %s\n", progname, s);
  54.     exit(1);
  55.     }
  56. /*...e*/
  57. /*...susage:0:*/
  58. static void usage(void)
  59.     {
  60.     int ft, n_ft;
  61.  
  62.     fprintf(stderr, "usage: %s [-m map] [-e] [-hN] [--] fn1.ext{,opt} [fn2.ext{,opt}]\n", progname);
  63.     fprintf(stderr, "flags: -m map         mapping to perform (default 7x8x4)\n");
  64.     fprintf(stderr, "                      bw           black and white\n");
  65.     fprintf(stderr, "                      vga          16 colour VGA\n");
  66.     fprintf(stderr, "                      8            8 colour (in 4 bit file)\n");
  67.     fprintf(stderr, "                      4g           4 bit greyscale\n");
  68.     fprintf(stderr, "                      7x8x4        7 levels red, 8 green, 4 blue 8514/A\n");
  69.     fprintf(stderr, "                      6x6x6        6 levels red, 6 green, 6 blue\n");
  70.     fprintf(stderr, "                      8g           8 bit greyscale\n");
  71.     fprintf(stderr, "                      tripel       64 reds, 64 greens, 64 blues tripel\n");
  72.     fprintf(stderr, "                      freqR:G:B:N  keep R red, G green, b blue bits, and map to\n");
  73.     fprintf(stderr, "                                   N most used colours in 8 bit palette\n");
  74.     fprintf(stderr, "                      mcutN        median cut to N colours\n");
  75.     fprintf(stderr, "                      R:G:B        keep R red, G green, B blue bits (eg: 8:8:8)\n");
  76.     fprintf(stderr, "       -e             enable error-diffusion (default is to truncate)\n");
  77.     fprintf(stderr, "                      -e only with -m bw, vga, 4g, 7x8x4, 6x6x6, with no -h\n");
  78.     fprintf(stderr, "       -h             enable halftoning (default is to truncate)\n");
  79.     fprintf(stderr, "                      -h only with -m 7x8x4, 6x6x6, 8, vga or R:G:B, with no -e\n");
  80.     fprintf(stderr, "                      N is a halftoning algorithm number (default 0)\n");
  81.     fprintf(stderr, "       fn1.ext{,opt}  input filename (with any format specific options)\n");
  82.     fprintf(stderr, "       fn2.ext{,opt}  optional output filename (or will use fn1 if not present)\n");
  83.     fprintf(stderr, "                      ext's are used to deduce desired bitmap file formats\n");
  84.  
  85.     gbm_init();
  86.     gbm_query_n_filetypes(&n_ft);
  87.     for ( ft = 0; ft < n_ft; ft++ )
  88.         {
  89.         GBMFT gbmft;
  90.  
  91.         gbm_query_filetype(ft, &gbmft);
  92.         fprintf(stderr, "                      %s when ext in [%s]\n",
  93.             gbmft.short_name, gbmft.extensions);
  94.         }
  95.     gbm_deinit();
  96.  
  97.     fprintf(stderr, "       opt's          bitmap format specific options\n");
  98.  
  99.     exit(1);
  100.     }
  101. /*...e*/
  102. /*...ssame:0:*/
  103. static BOOLEAN same(const char *s1, const char *s2, int n)
  104.     {
  105.     for ( ; n--; s1++, s2++ )
  106.         if ( tolower(*s1) != tolower(*s2) )
  107.             return FALSE;
  108.     return TRUE;
  109.     }
  110. /*...e*/
  111. /*...smain:0:*/
  112. /*...smapinfos:0:*/
  113. #define    CVT_BW        0
  114. #define    CVT_VGA        1
  115. #define    CVT_8        2
  116. #define    CVT_4G        3
  117. #define    CVT_784        4
  118. #define    CVT_666        5
  119. #define    CVT_8G        6
  120. #define    CVT_TRIPEL    7
  121. #define    CVT_RGB        8
  122. #define    CVT_FREQ    9
  123. #define    CVT_MCUT    10
  124. #define    CVT_ERRDIFF    0x4000
  125. #define    CVT_HALFTONE    0x2000
  126.  
  127. typedef struct { char *name; int m; int dest_bpp; } MAPINFO;
  128.  
  129. static MAPINFO mapinfos[] =
  130.     {
  131.     "bw",        CVT_BW,        1,
  132.     "vga",        CVT_VGA,    4,
  133.     "8",        CVT_8,        4,
  134.     "4g",        CVT_4G,        4,
  135.     "7x8x4",    CVT_784,    8,
  136.     "6x6x6",    CVT_666,    8,
  137.     "8g",        CVT_8G,        8,
  138.     "tripel",    CVT_TRIPEL,    8,
  139.     };
  140.  
  141. #define    N_MAPINFOS    (sizeof(mapinfos)/sizeof(mapinfos[0]))
  142. /*...e*/
  143. /*...sget_masks:0:*/
  144. /*
  145. Returns TRUE if a set of masks given at map.
  146. Also sets *rm, *gm, *bm from these.
  147. Else returns FALSE.
  148. */
  149.  
  150. static byte mask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
  151.  
  152. static BOOLEAN get_masks(char *map, byte *rm, byte *gm, byte *bm)
  153.     {
  154.     if ( map[0] <  '0' || map[0] > '8' ||
  155.          map[1] != ':' ||
  156.          map[2] <  '0' || map[2] > '8' ||
  157.          map[3] != ':' ||
  158.          map[4] <  '0' || map[4] > '8' )
  159.         return FALSE;
  160.  
  161.     *rm = mask[map[0] - '0'];
  162.     *gm = mask[map[2] - '0'];
  163.     *bm = mask[map[4] - '0'];
  164.     return TRUE;
  165.     }
  166. /*...e*/
  167. /*...sexpand_to_24bit:0:*/
  168. static void expand_to_24bit(GBM *gbm, GBMRGB *gbmrgb, byte **data)
  169.     {
  170.     int stride = ((gbm->w * gbm->bpp + 31)/32) * 4;
  171.     int new_stride = ((gbm->w * 3 + 3) & ~3);
  172.     int bytes, y;
  173.     byte *new_data;
  174.  
  175.     if ( gbm->bpp == 24 )
  176.         return;
  177.  
  178.     bytes = new_stride * gbm->h;
  179.     if ( (new_data = malloc((size_t) bytes)) == NULL )
  180.         fatal("out of memory allocating %d bytes", bytes);
  181.  
  182.     for ( y = 0; y < gbm->h; y++ )
  183.         {
  184.         byte    *src = *data + y * stride;
  185.         byte    *dest = new_data + y * new_stride;
  186.         int    x;
  187.  
  188.         switch ( gbm->bpp )
  189.             {
  190. /*...s1:24:*/
  191. case 1:
  192.     {
  193.     byte    c;
  194.  
  195.     for ( x = 0; x < gbm->w; x++ )
  196.         {
  197.         if ( (x & 7) == 0 )
  198.             c = *src++;
  199.         else
  200.             c <<= 1;
  201.  
  202.         *dest++ = gbmrgb[c >> 7].b;
  203.         *dest++ = gbmrgb[c >> 7].g;
  204.         *dest++ = gbmrgb[c >> 7].r;
  205.         }
  206.     }
  207.     break;
  208. /*...e*/
  209. /*...s4:24:*/
  210. case 4:
  211.     for ( x = 0; x + 1 < gbm->w; x += 2 )
  212.         {
  213.         byte    c = *src++;
  214.  
  215.         *dest++ = gbmrgb[c >> 4].b;
  216.         *dest++ = gbmrgb[c >> 4].g;
  217.         *dest++ = gbmrgb[c >> 4].r;
  218.         *dest++ = gbmrgb[c & 15].b;
  219.         *dest++ = gbmrgb[c & 15].g;
  220.         *dest++ = gbmrgb[c & 15].r;
  221.         }
  222.  
  223.     if ( x < gbm->w )
  224.         {
  225.         byte    c = *src;
  226.  
  227.         *dest++ = gbmrgb[c >> 4].b;
  228.         *dest++ = gbmrgb[c >> 4].g;
  229.         *dest++ = gbmrgb[c >> 4].r;
  230.         }
  231.     break;
  232. /*...e*/
  233. /*...s8:24:*/
  234. case 8:
  235.     for ( x = 0; x < gbm->w; x++ )
  236.         {
  237.         byte    c = *src++;
  238.  
  239.         *dest++ = gbmrgb[c].b;
  240.         *dest++ = gbmrgb[c].g;
  241.         *dest++ = gbmrgb[c].r;
  242.         }
  243.     break;
  244. /*...e*/
  245.             }
  246.         }
  247.     free(*data);
  248.     *data = new_data;
  249.     gbm->bpp = 24;
  250.     }
  251. /*...e*/
  252. /*...sto_grey_pal:0:*/
  253. static void to_grey_pal(GBMRGB *gbmrgb)
  254.     {
  255.     int i;
  256.  
  257.     for ( i = 0; i < 0x100; i++ )
  258.         gbmrgb[i].r =
  259.         gbmrgb[i].g =
  260.         gbmrgb[i].b = (byte) i;
  261.     }
  262. /*...e*/
  263. /*...sto_grey:0:*/
  264. static void to_grey(GBM *gbm, const byte *src_data, byte *dest_data)
  265.     {
  266.     int src_stride  = ((gbm->w * 3 + 3) & ~3);
  267.     int dest_stride = ((gbm->w     + 3) & ~3);
  268.     int y;
  269.  
  270.     for ( y = 0; y < gbm->h; y++ )
  271.         {
  272.         const byte *src  = src_data;
  273.               byte *dest = dest_data;
  274.         int x;
  275.  
  276.         for ( x = 0; x < gbm->w; x++ )
  277.             {
  278.             byte b = *src++;
  279.             byte g = *src++;
  280.             byte r = *src++;
  281.  
  282.             *dest++ = (byte) (((word) r * 77U + (word) g * 150U + (word) b * 29U) >> 8);
  283.             }
  284.  
  285.         src_data  += src_stride;
  286.         dest_data += dest_stride;
  287.         }
  288.     gbm->bpp = 8;
  289.     }
  290. /*...e*/
  291. /*...stripel_pal:0:*/
  292. static void tripel_pal(GBMRGB *gbmrgb)
  293.     {
  294.     int    i;
  295.  
  296.     memset(gbmrgb, 0, 0x100 * sizeof(GBMRGB));
  297.  
  298.     for ( i = 0; i < 0x40; i++ )
  299.         {
  300.         gbmrgb[i       ].r = (byte) (i << 2);
  301.         gbmrgb[i + 0x40].g = (byte) (i << 2);
  302.         gbmrgb[i + 0x80].b = (byte) (i << 2);
  303.         }
  304.     }
  305. /*...e*/
  306. /*...stripel:0:*/
  307. static void tripel(GBM *gbm, const byte *src_data, byte *dest_data)
  308.     {
  309.     int src_stride  = ((gbm->w * 3 + 3) & ~3);
  310.     int dest_stride = ((gbm->w     + 3) & ~3);
  311.     int y;
  312.  
  313.     for ( y = 0; y < gbm->h; y++ )
  314.         {
  315.         const byte *src  = src_data;
  316.               byte *dest = dest_data;
  317.         int x;
  318.  
  319.         for ( x = 0; x < gbm->w; x++ )
  320.             {
  321.             byte b = *src++;
  322.             byte g = *src++;
  323.             byte r = *src++;
  324.  
  325.             switch ( (x+y)%3 )
  326.                 {
  327.                 case 0:    *dest++ = (byte)         (r >> 2) ;    break;
  328.                 case 1:    *dest++ = (byte) (0x40 + (g >> 2));    break;
  329.                 case 2:    *dest++ = (byte) (0x80 + (b >> 2));    break;
  330.                 }
  331.             }
  332.  
  333.         src_data  += src_stride;
  334.         dest_data += dest_stride;
  335.         }
  336.     gbm->bpp = 8;
  337.     }
  338. /*...e*/
  339.  
  340. int main(int argc, char *argv[])
  341.     {
  342.     BOOLEAN    errdiff = FALSE, halftone = FALSE, ok = TRUE;
  343.     int    htmode = 0;
  344.     char    *map = "7x8x4";
  345.     char    fn_src[500+1], fn_dst[500+1], *opt_src, *opt_dst;
  346.     int    fd, ft_src, ft_dst, i, stride, bytes, flag, m, dest_bpp;
  347.     byte    rm, gm, bm;
  348.     int    ncols;
  349.     GBM_ERR    rc;
  350.     GBMFT    gbmft;
  351.     GBM    gbm;
  352.     GBMRGB    gbmrgb[0x100];
  353.     byte    *data;
  354.  
  355. /*...sprocess command line options:8:*/
  356. for ( i = 1; i < argc; i++ )
  357.     {
  358.     if ( argv[i][0] != '-' )
  359.         break;
  360.     else if ( argv[i][1] == '-' )
  361.         { ++i; break; }
  362.     switch ( argv[i][1] )
  363.         {
  364.         case 'e':    errdiff = TRUE;
  365.                 break;
  366.         case 'h':    halftone = TRUE;
  367.                 if ( argv[i][2] != '\0' && isdigit(argv[i][2]) )
  368.                     htmode = argv[i][2] - '0';
  369.                 break;
  370.         case 'm':    if ( ++i == argc )
  371.                     fatal("expected map argument");
  372.                 map = argv[i];
  373.                 break;
  374.         default:    usage();
  375.                 break;
  376.         }
  377.     }
  378.  
  379. if ( errdiff && halftone )
  380.     fatal("error-diffusion and halftoning can't both be done at once");
  381. /*...e*/
  382. /*...sdeduce mapping and bits per pixel etc\46\:8:*/
  383. if ( get_masks(map, &rm, &gm, &bm) && map[5] == '\0' )
  384.     {
  385.     m = CVT_RGB;
  386.     dest_bpp = 24;
  387.     }
  388. else if ( same(map, "freq", 4) )
  389.     {
  390.     m = CVT_FREQ;
  391.     dest_bpp = 8;
  392.     if ( !get_masks(map+4, &rm, &gm, &bm) )
  393.         fatal("freqR:G:B:N has bad/missing R:G:B");
  394.     if ( map[9] != ':' )
  395.         fatal("freqR:G:B:N has bad/missing :N");
  396.     sscanf(map+10, "%i", &ncols);
  397.     if ( ncols < 1 || ncols > 256 )
  398.         fatal("freqR:G:B:N N number between 1 and 256 required");
  399.     }
  400. else if ( same(map, "mcut", 4) )
  401.     {
  402.     m = CVT_MCUT;
  403.     dest_bpp = 8;
  404.     sscanf(map+4, "%i", &ncols);
  405.     if ( ncols < 1 || ncols > 256 )
  406.         fatal("mcutN N number between 1 and 256 required");
  407.     }
  408. else
  409.     {
  410.     int j;
  411.  
  412.     for ( j = 0; j < N_MAPINFOS; j++ )
  413.         if ( same(map, mapinfos[j].name, strlen(map) + 1) )
  414.             break;
  415.     if ( j == N_MAPINFOS )
  416.         fatal("unrecognised mapping %s", map);
  417.     m        = mapinfos[j].m;
  418.     dest_bpp = mapinfos[j].dest_bpp;
  419.     }
  420. /*...e*/
  421.  
  422.     if ( i == argc )
  423.         usage();
  424.     strcpy(fn_src, argv[i++]);
  425.     strcpy(fn_dst, ( i == argc ) ? fn_src : argv[i++]);
  426.     if ( i < argc )
  427.         usage();
  428.  
  429.     if ( (opt_src = strchr(fn_src, ',')) != NULL )
  430.         *opt_src++ = '\0';
  431.     else
  432.         opt_src = "";
  433.  
  434.     if ( (opt_dst = strchr(fn_dst, ',')) != NULL )
  435.         *opt_dst++ = '\0';
  436.     else
  437.         opt_dst = "";
  438.  
  439.     gbm_init();
  440.  
  441.     if ( gbm_guess_filetype(fn_src, &ft_src) != GBM_ERR_OK )
  442.         fatal("can't guess bitmap file format for %s", fn_src);
  443.  
  444.     if ( gbm_guess_filetype(fn_dst, &ft_dst) != GBM_ERR_OK )
  445.         fatal("can't guess bitmap file format for %s", fn_dst);
  446.  
  447.     if ( (fd = gbm_io_open(fn_src, O_RDONLY|O_BINARY)) == -1 )
  448.         fatal("can't open %s", fn_src);
  449.  
  450.     if ( (rc = gbm_read_header(fn_src, fd, ft_src, &gbm, opt_src)) != GBM_ERR_OK )
  451.         {
  452.         gbm_io_close(fd);
  453.         fatal("can't read header of %s: %s", fn_src, gbm_err(rc));
  454.         }
  455.  
  456.     gbm_query_filetype(ft_dst, &gbmft);
  457.     switch ( dest_bpp )
  458.         {
  459.         case 24:    flag = GBM_FT_W24;    break;
  460.         case 8:        flag = GBM_FT_W8;    break;
  461.         case 4:        flag = GBM_FT_W4;    break;
  462.         case 1:        flag = GBM_FT_W1;    break;
  463.         }
  464.  
  465.     if ( (gbmft.flags & flag) == 0 )
  466.         {
  467.         gbm_io_close(fd);
  468.         fatal("output bitmap format %s does not support writing %d bpp data",
  469.             gbmft.short_name, dest_bpp);
  470.         }
  471.  
  472.     if ( (rc = gbm_read_palette(fd, ft_src, &gbm, gbmrgb)) != GBM_ERR_OK )
  473.         {
  474.         gbm_io_close(fd);
  475.         fatal("can't read palette of %s: %s", fn_src, gbm_err(rc));
  476.         }
  477.  
  478.     stride = ( ((gbm.w * gbm.bpp + 31)/32) * 4 );
  479.     bytes = stride * gbm.h;
  480.     if ( (data = malloc((size_t) bytes)) == NULL )
  481.         {
  482.         gbm_io_close(fd);
  483.         fatal("out of memory allocating %d bytes", bytes);
  484.         }
  485.  
  486.     if ( (rc = gbm_read_data(fd, ft_src, &gbm, data)) != GBM_ERR_OK )
  487.         {
  488.         free(data);
  489.         gbm_io_close(fd);
  490.         fatal("can't read bitmap data of %s: %s", fn_src, gbm_err(rc));
  491.         }
  492.  
  493.     gbm_io_close(fd);
  494.  
  495.     /* Now expand bits per pixel if necessary */
  496.  
  497.     expand_to_24bit(&gbm, gbmrgb, &data);
  498.  
  499.     if ( errdiff )
  500.         m |= CVT_ERRDIFF;
  501.  
  502.     if ( halftone )
  503.         m |= CVT_HALFTONE;
  504.  
  505.     switch ( m )
  506.         {
  507.         case CVT_BW:
  508.             gbm_trunc_pal_BW(gbmrgb);
  509.             gbm_trunc_BW(&gbm, data, data);
  510.             break;
  511.         case CVT_4G:
  512.             gbm_trunc_pal_4G(gbmrgb);
  513.             gbm_trunc_4G(&gbm, data, data);
  514.             break;
  515.         case CVT_8:
  516.             gbm_trunc_pal_8(gbmrgb);
  517.             gbm_trunc_8(&gbm, data, data);
  518.             break;
  519.         case CVT_VGA:
  520.             gbm_trunc_pal_VGA(gbmrgb);
  521.             gbm_trunc_VGA(&gbm, data, data);
  522.             break;
  523.         case CVT_784:
  524.             gbm_trunc_pal_7R8G4B(gbmrgb);
  525.             gbm_trunc_7R8G4B(&gbm, data, data);
  526.             break;
  527.         case CVT_666:
  528.             gbm_trunc_pal_6R6G6B(gbmrgb);
  529.             gbm_trunc_6R6G6B(&gbm, data, data);
  530.             break;
  531.         case CVT_8G:
  532.             to_grey_pal(gbmrgb);
  533.             to_grey(&gbm, data, data);
  534.             break;
  535.         case CVT_TRIPEL:
  536.             tripel_pal(gbmrgb);
  537.             tripel(&gbm, data, data);
  538.             break;
  539.         case CVT_FREQ:
  540.             memset(gbmrgb, 0, sizeof(gbmrgb));
  541.             ok = gbm_hist(&gbm, data, gbmrgb, data, ncols, rm, gm, bm);
  542.             break;
  543.         case CVT_RGB:
  544.             gbm_trunc_24(&gbm, data, data, rm, gm, bm);
  545.             break;
  546.         case CVT_MCUT:
  547.             ok = gbm_mcut(&gbm, data, gbmrgb, data, ncols);
  548.             break;
  549.         case CVT_BW | CVT_ERRDIFF:
  550.             gbm_errdiff_pal_BW(gbmrgb);
  551.             ok = gbm_errdiff_BW(&gbm, data, data);
  552.             break;
  553.         case CVT_4G | CVT_ERRDIFF:
  554.             gbm_errdiff_pal_4G(gbmrgb);
  555.             ok = gbm_errdiff_4G(&gbm, data, data);
  556.             break;
  557.         case CVT_8 | CVT_ERRDIFF:
  558.             gbm_errdiff_pal_8(gbmrgb);
  559.             ok = gbm_errdiff_8(&gbm, data, data);
  560.             break;
  561.         case CVT_VGA | CVT_ERRDIFF:
  562.             gbm_errdiff_pal_VGA(gbmrgb);
  563.             ok = gbm_errdiff_VGA(&gbm, data, data);
  564.             break;
  565.         case CVT_784 | CVT_ERRDIFF:
  566.             gbm_errdiff_pal_7R8G4B(gbmrgb);
  567.             ok = gbm_errdiff_7R8G4B(&gbm, data, data);
  568.             break;
  569.         case CVT_666 | CVT_ERRDIFF:
  570.             gbm_errdiff_pal_6R6G6B(gbmrgb);
  571.             ok = gbm_errdiff_6R6G6B(&gbm, data, data);
  572.             break;
  573.         case CVT_RGB | CVT_ERRDIFF:
  574.             ok = gbm_errdiff_24(&gbm, data, data, rm, gm, bm);
  575.             break;
  576.         case CVT_784 | CVT_HALFTONE:
  577.             gbm_ht_pal_7R8G4B(gbmrgb);
  578.             gbm_ht_7R8G4B_2x2(&gbm, data, data);
  579.             break;
  580.         case CVT_666 | CVT_HALFTONE:
  581.             gbm_ht_pal_6R6G6B(gbmrgb);
  582.             gbm_ht_6R6G6B_2x2(&gbm, data, data);
  583.             break;
  584.         case CVT_8 | CVT_HALFTONE:
  585.             gbm_ht_pal_8(gbmrgb);
  586.             switch ( htmode )
  587.                 {
  588.                 default:
  589.                 case 0: gbm_ht_8_3x3(&gbm, data, data); break;
  590.                 case 1: gbm_ht_8_2x2(&gbm, data, data); break;
  591.                 }
  592.             break;
  593.         case CVT_VGA | CVT_HALFTONE:
  594.             gbm_ht_pal_VGA(gbmrgb);
  595.             switch ( htmode )
  596.                 {
  597.                 default:
  598.                 case 0: gbm_ht_VGA_3x3(&gbm, data, data); break;
  599.                 case 1: gbm_ht_VGA_2x2(&gbm, data, data); break;
  600.                 }
  601.             break;
  602.         case CVT_RGB | CVT_HALFTONE:
  603.             gbm_ht_24_2x2(&gbm, data, data, rm, gm, bm);
  604.             break;
  605.         default:
  606.             fatal("bad mapping/error-diffusion/halftone combination");
  607.         }
  608.  
  609.     if ( !ok )
  610.         fatal("unable to perform mapping");
  611.  
  612.     gbm.bpp = dest_bpp;
  613.  
  614.     if ( (fd = gbm_io_create(fn_dst, O_WRONLY|O_BINARY)) == -1 )
  615.         fatal("can't create %s", fn_dst);
  616.  
  617.     if ( (rc = gbm_write(fn_dst, fd, ft_dst, &gbm, gbmrgb, data, opt_dst)) != GBM_ERR_OK )
  618.         {
  619.         gbm_io_close(fd);
  620.         remove(fn_dst);
  621.         fatal("can't write %s: %s", fn_dst, gbm_err(rc));
  622.         }
  623.  
  624.     gbm_io_close(fd);
  625.  
  626.     free(data);
  627.  
  628.     gbm_deinit();
  629.  
  630.     return 0;
  631.     }
  632. /*...e*/
  633.