Imported Upstream version 1.6.13
[platform/upstream/libpng.git] / contrib / tools / cvtcolor.c
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
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
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
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 }