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 } 189