all repos — mgba @ travis

mGBA Game Boy Advance Emulator

src/third-party/libpng/contrib/tools/cvtcolor.c (view raw)

  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
 24static void
 25usage(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
 33unsigned long
 34component(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
 48int
 49main(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}