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