(root)/
libpng-1.6.40/
contrib/
tools/
cvtcolor.c
       1  /* convert.c
       2   *
       3   * COPYRIGHT: Written by John Cunningham Bowler, 2013.
       4   * To the extent possible under law, the author has waived all copyright and
       5   * related or neighboring rights to this work.  This work is published from:
       6   * United States.
       7   *
       8   * Convert 8-bit sRGB or 16-bit linear values to another format.
       9   */
      10  
      11  #define _ISOC99_SOURCE 1
      12  
      13  #include <stdlib.h>
      14  #include <string.h>
      15  #include <math.h>
      16  #include <stdio.h>
      17  
      18  #include <fenv.h>
      19  
      20  #include "sRGB.h"
      21  
      22  static void
      23  usage(const char *prog)
      24  {
      25     fprintf(stderr,
      26        "%s: usage: %s [-linear|-sRGB] [-gray|-color] component{1,4}\n",
      27        prog, prog);
      28     exit(1);
      29  }
      30  
      31  unsigned long
      32  component(const char *prog, const char *arg, int issRGB)
      33  {
      34     char *ep;
      35     unsigned long c = strtoul(arg, &ep, 0);
      36  
      37     if (ep <= arg || *ep || c > 65535 || (issRGB && c > 255))
      38     {
      39        fprintf(stderr, "%s: %s: invalid component value (%lu)\n", prog, arg, c);
      40        usage(prog);
      41     }
      42  
      43     return c;
      44  }
      45  
      46  int
      47  main(int argc, const char **argv)
      48  {
      49     const char *prog = *argv++;
      50     int to_linear = 0, to_gray = 0, to_color = 0;
      51     int channels = 0;
      52     double c[4];
      53  
      54     /* FE_TONEAREST is the IEEE754 round to nearest, preferring even, mode; i.e.
      55      * everything rounds to the nearest value except that '.5' rounds to the
      56      * nearest even value.
      57      */
      58     fesetround(FE_TONEAREST);
      59  
      60     c[3] = c[2] = c[1] = c[0] = 0;
      61  
      62     while (--argc > 0 && **argv == '-')
      63     {
      64        const char *arg = 1+*argv++;
      65  
      66        if (strcmp(arg, "sRGB") == 0)
      67           to_linear = 0;
      68  
      69        else if (strcmp(arg, "linear") == 0)
      70           to_linear = 1;
      71  
      72        else if (strcmp(arg, "gray") == 0)
      73           to_gray = 1, to_color = 0;
      74  
      75        else if (strcmp(arg, "color") == 0)
      76           to_gray = 0, to_color = 1;
      77  
      78        else
      79           usage(prog);
      80     }
      81  
      82     switch (argc)
      83     {
      84        default:
      85           usage(prog);
      86           break;
      87  
      88        case 4:
      89           c[3] = component(prog, argv[3], to_linear);
      90           ++channels;
      91        case 3:
      92           c[2] = component(prog, argv[2], to_linear);
      93           ++channels;
      94        case 2:
      95           c[1] = component(prog, argv[1], to_linear);
      96           ++channels;
      97        case 1:
      98           c[0] = component(prog, argv[0], to_linear);
      99           ++channels;
     100           break;
     101        }
     102  
     103     if (to_linear)
     104     {
     105        int i;
     106        int components = channels;
     107  
     108        if ((components & 1) == 0)
     109           --components;
     110  
     111        for (i=0; i<components; ++i) c[i] = linear_from_sRGB(c[i] / 255);
     112        if (components < channels)
     113           c[components] = c[components] / 255;
     114     }
     115  
     116     else
     117     {
     118        int i;
     119        for (i=0; i<4; ++i) c[i] /= 65535;
     120  
     121        if ((channels & 1) == 0)
     122        {
     123           double alpha = c[channels-1];
     124  
     125           if (alpha > 0)
     126              for (i=0; i<channels-1; ++i) c[i] /= alpha;
     127           else
     128              for (i=0; i<channels-1; ++i) c[i] = 1;
     129        }
     130     }
     131  
     132     if (to_gray)
     133     {
     134        if (channels < 3)
     135        {
     136           fprintf(stderr, "%s: too few channels (%d) for -gray\n",
     137              prog, channels);
     138           usage(prog);
     139        }
     140  
     141        c[0] = YfromRGB(c[0], c[1], c[2]);
     142        channels -= 2;
     143     }
     144  
     145     if (to_color)
     146     {
     147        if (channels > 2)
     148        {
     149           fprintf(stderr, "%s: too many channels (%d) for -color\n",
     150              prog, channels);
     151           usage(prog);
     152        }
     153  
     154        c[3] = c[1]; /* alpha, if present */
     155        c[2] = c[1] = c[0];
     156     }
     157  
     158     if (to_linear)
     159     {
     160        int i;
     161        if ((channels & 1) == 0)
     162        {
     163           double alpha = c[channels-1];
     164           for (i=0; i<channels-1; ++i) c[i] *= alpha;
     165        }
     166  
     167        for (i=0; i<channels; ++i) c[i] = nearbyint(c[i] * 65535);
     168     }
     169  
     170     else /* to sRGB */
     171     {
     172        int i = (channels+1)&~1;
     173        while (--i >= 0)
     174           c[i] = sRGB_from_linear(c[i]);
     175  
     176        for (i=0; i<channels; ++i) c[i] = nearbyint(c[i] * 255);
     177     }
     178  
     179     {
     180        int i;
     181        for (i=0; i<channels; ++i) printf(" %g", c[i]);
     182     }
     183     printf("\n");
     184  
     185     return 0;
     186  }