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

  1. /*
  2.  
  3. gbmgamma.c - Gamma correct General Bitmap
  4.  
  5. */
  6.  
  7. /*...sincludes:0:*/
  8. #include <stdio.h>
  9. #include <ctype.h>
  10. #include <math.h>
  11. #include <string.h>
  12. #include <stddef.h>
  13. #include <stdlib.h>
  14. #include <stdarg.h>
  15. #include <memory.h>
  16. #include <malloc.h>
  17. #if defined(AIX) || defined(LINUX)
  18. #include <unistd.h>
  19. #else
  20. #include <io.h>
  21. #endif
  22. #include <fcntl.h>
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25. #ifndef O_BINARY
  26. #define    O_BINARY    0
  27. #endif
  28. #include "gbm.h"
  29.  
  30. /*...vgbm\46\h:0:*/
  31. /*...e*/
  32.  
  33. static char progname[] = "gbmgamma";
  34.  
  35. /*...sfatal:0:*/
  36. static void fatal(const char *fmt, ...)
  37.     {
  38.     va_list    vars;
  39.     char s[256+1];
  40.  
  41.     va_start(vars, fmt);
  42.     vsprintf(s, fmt, vars);
  43.     va_end(vars);
  44.     fprintf(stderr, "%s: %s\n", progname, s);
  45.     exit(1);
  46.     }
  47. /*...e*/
  48. /*...susage:0:*/
  49. static void usage(void)
  50.     {
  51.     int ft, n_ft;
  52.  
  53.     fprintf(stderr, "usage: %s [-m map] [-g gamma] [-s shelf] fn1.ext{,opt} [--] [fn2.ext{,opt}]\n", progname);
  54.     fprintf(stderr, "flags: -m map         mapping in the form ?_to_? (default: i_to_l), where ? is\n");
  55.     fprintf(stderr, "                      i  physical intensitys (eg: raytracer output)\n");
  56.     fprintf(stderr, "                      p  gamma corrected for a specific monitor\n");
  57.     fprintf(stderr, "                      l  L* cyclometric linear perceived intensitys (as in PM)\n");
  58.     fprintf(stderr, "       -g gamma       set monitor gamma (default 2.1)\n");
  59.     fprintf(stderr, "       -s shelf       set monitor shelf (default 0.0)\n");
  60.     fprintf(stderr, "                      gamma and shelf only used for mapping to or from p\n");
  61.     fprintf(stderr, "                      for 8514 monitor gamma=2.3,shelf=0.136\n");
  62.     fprintf(stderr, "                      for 8515 monitor gamma=2.1,shelf=0.0\n");
  63.     fprintf(stderr, "       fn1.ext{,opt}  input filename (with any format specific options)\n");
  64.     fprintf(stderr, "       fn2.ext{,opt}  optional output filename (or will use fn1 if not present)\n");
  65.     fprintf(stderr, "                      ext's are used to deduce desired bitmap file formats\n");
  66.  
  67.     gbm_init();
  68.     gbm_query_n_filetypes(&n_ft);
  69.     for ( ft = 0; ft < n_ft; ft++ )
  70.         {
  71.         GBMFT gbmft;
  72.  
  73.         gbm_query_filetype(ft, &gbmft);
  74.         fprintf(stderr, "                      %s when ext in [%s]\n",
  75.             gbmft.short_name, gbmft.extensions);
  76.         }
  77.     gbm_deinit();
  78.  
  79.     fprintf(stderr, "       opt's          bitmap format specific options\n");
  80.  
  81.     exit(1);
  82.     }
  83. /*...e*/
  84. /*...sget_opt_double:0:*/
  85. static double get_opt_double(const char *s, const char *name)
  86.     {
  87.     double v;
  88.  
  89.     if ( s == NULL )
  90.         fatal("missing %s argument", name);
  91.     sscanf(s, "%lf", &v);
  92.  
  93.     return v;
  94.     }
  95. /*...e*/
  96. /*...ssame:0:*/
  97. static BOOLEAN same(const char *s1, const char *s2, int n)
  98.     {
  99.     for ( ; n--; s1++, s2++ )
  100.         if ( tolower(*s1) != tolower(*s2) )
  101.             return FALSE;
  102.     return TRUE;
  103.     }
  104. /*...e*/
  105. /*...smain:0:*/
  106. /*...smapinfos:0:*/
  107. #define    CVT_NONE    0
  108. #define    CVT_I_TO_P    1
  109. #define    CVT_P_TO_I    2
  110. #define    CVT_I_TO_L    3
  111. #define    CVT_L_TO_I    4
  112. #define    CVT_P_TO_L    5
  113. #define    CVT_L_TO_P    6
  114.  
  115. typedef struct { char *name; int m; } MAPINFO;
  116.  
  117. static MAPINFO mapinfos[] =
  118.     {
  119.     "none",        CVT_NONE,
  120.     "i_to_p",    CVT_I_TO_P,
  121.     "p_to_i",    CVT_P_TO_I,
  122.     "i_to_l",    CVT_I_TO_L,
  123.     "l_to_i",    CVT_L_TO_I,
  124.     "p_to_l",    CVT_P_TO_L,
  125.     "l_to_p",    CVT_L_TO_P,
  126.     };
  127.  
  128. #define    N_MAPINFOS    (sizeof(mapinfos)/sizeof(mapinfos[0]))
  129. /*...e*/
  130.  
  131. /*...smap_compute:0:*/
  132. /*...slstar_from_i:0:*/
  133. static double lstar_from_i(double y)
  134.     {
  135.     y = pow(1.16 * y, 1.0/3.0) - 0.16;
  136.  
  137.     if ( y < 0.0 ) y = 0.0; else if ( y > 1.0 ) y = 1.0;
  138.  
  139.     return y;
  140.     }
  141. /*...e*/
  142. /*...si_from_lstar:0:*/
  143. static double i_from_lstar(double y)
  144.     {
  145.     y = pow(y + 0.16, 3.0) / 1.16;
  146.  
  147.     if ( y < 0.0 ) y = 0.0; else if ( y > 1.0 ) y = 1.0;
  148.  
  149.     return y;
  150.     }
  151. /*...e*/
  152. /*...spal_from_i:0:*/
  153. static double pal_from_i(double y, double gam, double shelf)
  154.     {
  155.     y = pow(y,1.0 / gam) * (1.0 - shelf) + shelf;
  156.  
  157.     if ( y < 0.0 ) y = 0.0; else if ( y > 1.0 ) y = 1.0;
  158.  
  159.     return y;
  160.     }
  161. /*...e*/
  162. /*...si_from_pal:0:*/
  163. static double i_from_pal(double y, double gam, double shelf)
  164.     {
  165.     if ( y >= shelf )
  166.         y = pow((y - shelf) / (1.0 - shelf), gam);
  167.     else
  168.         y = 0.0;
  169.  
  170.     if ( y < 0.0 ) y = 0.0; else if ( y > 1.0 ) y = 1.0;
  171.  
  172.     return y;
  173.     }
  174. /*...e*/
  175.  
  176. static void map_compute(int m, byte remap[], double gam, double shelf)
  177.     {
  178.     int    i;
  179.  
  180.     for ( i = 0; i < 0x100; i++ )
  181.         {
  182.         double y = (double) i / 255.0;
  183.  
  184.         switch ( m )
  185.             {
  186.             case CVT_I_TO_P: y = pal_from_i(y, gam, shelf); break;
  187.             case CVT_P_TO_I: y = i_from_pal(y, gam, shelf); break;
  188.             case CVT_I_TO_L: y = lstar_from_i(y); break;
  189.             case CVT_L_TO_I: y = i_from_lstar(y); break;
  190.             case CVT_P_TO_L: y = lstar_from_i(i_from_pal(y, gam, shelf)); break;
  191.             case CVT_L_TO_P: y = pal_from_i(i_from_lstar(y), gam, shelf); break;
  192.             }
  193.  
  194.         remap[i] = (byte) (y * 255.0);
  195.         }
  196.     }
  197. /*...e*/
  198. /*...smap_data:0:*/
  199. static void map_data(byte *data, int w, int h, const byte remap[])
  200.     {
  201.     int stride = ((w * 3 + 3) & ~3);
  202.     int x, y;
  203.  
  204.     for ( y = 0; y < h; y++, data += stride )
  205.         for ( x = 0; x < w * 3; x++ )
  206.             data[x] = remap[data[x]];
  207.     }
  208. /*...e*/
  209. /*...smap_palette:0:*/
  210. static void map_palette(GBMRGB *gbmrgb, int npals, const byte remap[])
  211.     {
  212.     for ( ; npals--; gbmrgb++ )
  213.         {
  214.         gbmrgb->b = remap[gbmrgb->b];
  215.         gbmrgb->g = remap[gbmrgb->g];
  216.         gbmrgb->r = remap[gbmrgb->r];
  217.         }
  218.     }
  219. /*...e*/
  220.  
  221. int main(int argc, char *argv[])
  222.     {
  223.     char    fn_src[500+1], fn_dst[500+1], *opt_src, *opt_dst;
  224.     int    fd, ft_src, ft_dst, i, stride, bytes, flag, m;
  225.     GBM_ERR    rc;
  226.     GBMFT    gbmft;
  227.     GBM    gbm;
  228.     GBMRGB    gbmrgb[0x100];
  229.     byte    *data;
  230.     char    *map = "none";
  231.     byte    remap[0x100];
  232.     double gam = 2.1, shelf = 0.0;
  233.  
  234. /*...scommand line arguments:8:*/
  235. for ( i = 1; i < argc; i++ )
  236.     {
  237.     if ( argv[i][0] != '-' )
  238.         break;
  239.     else if ( argv[i][1] == '-' )
  240.         { ++i; break; }
  241.     switch ( argv[i][1] )
  242.         {
  243.         case 'm':
  244.             if ( ++i == argc )
  245.                 fatal("expected map argument");
  246.             map = argv[i];
  247.             break;
  248.         case 'g':
  249.             if ( ++i == argc ) usage();
  250.             gam = get_opt_double(argv[i], "gam");
  251.             if ( gam < 0.1 || gam > 10.0 )
  252.                 fatal("only gammas in the range 0.1 to 10.0 are sensible");
  253.             break;
  254.         case 's':
  255.             if ( ++i == argc ) usage();
  256.             shelf = get_opt_double(argv[i], "shelf");
  257.             break;
  258.         default:
  259.             usage();
  260.             break;
  261.         }
  262.     }
  263. /*...e*/
  264.  
  265. /*...sdeduce mapping and bits per pixel etc\46\:8:*/
  266. {
  267. int j;
  268.  
  269. for ( j = 0; j < N_MAPINFOS; j++ )
  270.     if ( same(map, mapinfos[j].name, (int) strlen(map) + 1) )
  271.         break;
  272. if ( j == N_MAPINFOS )
  273.     fatal("unrecognised mapping %s", map);
  274. m = mapinfos[j].m;
  275. }
  276. /*...e*/
  277.  
  278.     if ( i == argc )
  279.         usage();
  280.     strcpy(fn_src, argv[i++]);
  281.     strcpy(fn_dst, ( i == argc ) ? fn_src : argv[i++]);
  282.     if ( i < argc )
  283.         usage();
  284.  
  285.     if ( (opt_src = strchr(fn_src, ',')) != NULL )
  286.         *opt_src++ = '\0';
  287.     else
  288.         opt_src = "";
  289.  
  290.     if ( (opt_dst = strchr(fn_dst, ',')) != NULL )
  291.         *opt_dst++ = '\0';
  292.     else
  293.         opt_dst = "";
  294.  
  295.     gbm_init();
  296.  
  297.     if ( gbm_guess_filetype(fn_src, &ft_src) != GBM_ERR_OK )
  298.         fatal("can't guess bitmap file format for %s", fn_src);
  299.  
  300.     if ( gbm_guess_filetype(fn_dst, &ft_dst) != GBM_ERR_OK )
  301.         fatal("can't guess bitmap file format for %s", fn_dst);
  302.  
  303.     if ( (fd = gbm_io_open(fn_src, O_RDONLY|O_BINARY)) == -1 )
  304.         fatal("can't open %s", fn_src);
  305.  
  306.     if ( (rc = gbm_read_header(fn_src, fd, ft_src, &gbm, opt_src)) != GBM_ERR_OK )
  307.         {
  308.         gbm_io_close(fd);
  309.         fatal("can't read header of %s: %s", fn_src, gbm_err(rc));
  310.         }
  311.  
  312.     gbm_query_filetype(ft_dst, &gbmft);
  313.     switch ( gbm.bpp )
  314.         {
  315.         case 24:    flag = GBM_FT_W24;    break;
  316.         case 8:        flag = GBM_FT_W8;    break;
  317.         case 4:        flag = GBM_FT_W4;    break;
  318.         case 1:        flag = GBM_FT_W1;    break;
  319.         }
  320.     if ( (gbmft.flags & flag) == 0 )
  321.         {
  322.         gbm_io_close(fd);
  323.         fatal("output bitmap format %s does not support writing %d bpp data",
  324.             gbmft.short_name, gbm.bpp);
  325.         }
  326.  
  327.     if ( (rc = gbm_read_palette(fd, ft_src, &gbm, gbmrgb)) != GBM_ERR_OK )
  328.         {
  329.         gbm_io_close(fd);
  330.         fatal("can't read palette of %s: %s", fn_src, gbm_err(rc));
  331.         }
  332.  
  333.     stride = ( ((gbm.w * gbm.bpp + 31)/32) * 4 );
  334.     bytes = stride * gbm.h;
  335.     if ( (data = malloc((size_t) bytes)) == NULL )
  336.         {
  337.         gbm_io_close(fd);
  338.         fatal("out of memory allocating %d bytes for bitmap", bytes);
  339.         }
  340.  
  341.     if ( (rc = gbm_read_data(fd, ft_src, &gbm, data)) != GBM_ERR_OK )
  342.         {
  343.         gbm_io_close(fd);
  344.         fatal("can't read bitmap data of %s: %s", fn_src, gbm_err(rc));
  345.         }
  346.  
  347.     gbm_io_close(fd);
  348.  
  349.     map_compute(m, remap, gam, shelf);
  350.  
  351.     if ( gbm.bpp == 24 )
  352.         map_data(data, gbm.w, gbm.h, remap);
  353.     else
  354.         map_palette(gbmrgb, 1 << gbm.bpp, remap);
  355.  
  356.     if ( (fd = gbm_io_create(fn_dst, O_WRONLY|O_BINARY)) == -1 )
  357.         fatal("can't create %s", fn_dst);
  358.  
  359.     if ( (rc = gbm_write(fn_dst, fd, ft_dst, &gbm, gbmrgb, data, opt_dst)) != GBM_ERR_OK )
  360.         {
  361.         gbm_io_close(fd);
  362.         remove(fn_dst);
  363.         fatal("can't write %s: %s", fn_dst, gbm_err(rc));
  364.         }
  365.  
  366.     gbm_io_close(fd);
  367.  
  368.     free(data);
  369.  
  370.     gbm_deinit();
  371.  
  372.     return 0;
  373.     }
  374. /*...e*/
  375.