]> git.tdb.fi Git - ext/libpng.git/blob - contrib/tools/cvtcolor.c
Import libpng 1.6.39
[ext/libpng.git] / 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 }