/*- * convert.c * * Last changed in libpng 1.6.0 [February 14, 2013] * * COPYRIGHT: Written by John Cunningham Bowler, 2013. * To the extent possible under law, the author has waived all copyright and * related or neighboring rights to this work. This work is published from: * United States. * * Convert 8-bit sRGB or 16-bit linear values to another format. */ #define _ISOC99_SOURCE 1 #include <stdlib.h> #include <string.h> #include <math.h> #include <stdio.h> #include <fenv.h> #include "sRGB.h" static void usage(const char *prog) { fprintf(stderr, "%s: usage: %s [-linear|-sRGB] [-gray|-color] component{1,4}\n", prog, prog); exit(1); } unsigned long component(const char *prog, const char *arg, int issRGB) { char *ep; unsigned long c = strtoul(arg, &ep, 0); if (ep <= arg || *ep || c > 65535 || (issRGB && c > 255)) { fprintf(stderr, "%s: %s: invalid component value (%lu)\n", prog, arg, c); usage(prog); } return c; } int main(int argc, const char **argv) { const char *prog = *argv++; int to_linear = 0, to_gray = 0, to_color = 0; int channels = 0; double c[4]; /* FE_TONEAREST is the IEEE754 round to nearest, preferring even, mode; i.e. * everything rounds to the nearest value except that '.5' rounds to the * nearest even value. */ fesetround(FE_TONEAREST); c[3] = c[2] = c[1] = c[0] = 0; while (--argc > 0 && **argv == '-') { const char *arg = 1+*argv++; if (strcmp(arg, "sRGB") == 0) to_linear = 0; else if (strcmp(arg, "linear") == 0) to_linear = 1; else if (strcmp(arg, "gray") == 0) to_gray = 1, to_color = 0; else if (strcmp(arg, "color") == 0) to_gray = 0, to_color = 1; else usage(prog); } switch (argc) { default: usage(prog); break; case 4: c[3] = component(prog, argv[3], to_linear); ++channels; case 3: c[2] = component(prog, argv[2], to_linear); ++channels; case 2: c[1] = component(prog, argv[1], to_linear); ++channels; case 1: c[0] = component(prog, argv[0], to_linear); ++channels; break; } if (to_linear) { int i; int components = channels; if ((components & 1) == 0) --components; for (i=0; i<components; ++i) c[i] = linear_from_sRGB(c[i] / 255); if (components < channels) c[components] = c[components] / 255; } else { int i; for (i=0; i<4; ++i) c[i] /= 65535; if ((channels & 1) == 0) { double alpha = c[channels-1]; if (alpha > 0) for (i=0; i<channels-1; ++i) c[i] /= alpha; else for (i=0; i<channels-1; ++i) c[i] = 1; } } if (to_gray) { if (channels < 3) { fprintf(stderr, "%s: too few channels (%d) for -gray\n", prog, channels); usage(prog); } c[0] = YfromRGB(c[0], c[1], c[2]); channels -= 2; } if (to_color) { if (channels > 2) { fprintf(stderr, "%s: too many channels (%d) for -color\n", prog, channels); usage(prog); } c[3] = c[1]; /* alpha, if present */ c[2] = c[1] = c[0]; } if (to_linear) { int i; if ((channels & 1) == 0) { double alpha = c[channels-1]; for (i=0; i<channels-1; ++i) c[i] *= alpha; } for (i=0; i<channels; ++i) c[i] = nearbyint(c[i] * 65535); } else /* to sRGB */ { int i = (channels+1)&~1; while (--i >= 0) c[i] = sRGB_from_linear(c[i]); for (i=0; i<channels; ++i) c[i] = nearbyint(c[i] * 255); } { int i; for (i=0; i<channels; ++i) printf(" %g", c[i]); } printf("\n"); return 0; }