cvtcolor.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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. #include <stdlib.h>
  15. #include <string.h>
  16. #include <math.h>
  17. #include <stdio.h>
  18. #include <fenv.h>
  19. #include "sRGB.h"
  20. static void
  21. usage(const char *prog)
  22. {
  23. fprintf(stderr,
  24. "%s: usage: %s [-linear|-sRGB] [-gray|-color] component{1,4}\n",
  25. prog, prog);
  26. exit(1);
  27. }
  28. unsigned long
  29. component(const char *prog, const char *arg, int issRGB)
  30. {
  31. char *ep;
  32. unsigned long c = strtoul(arg, &ep, 0);
  33. if (ep <= arg || *ep || c > 65535 || (issRGB && c > 255))
  34. {
  35. fprintf(stderr, "%s: %s: invalid component value (%lu)\n", prog, arg, c);
  36. usage(prog);
  37. }
  38. return c;
  39. }
  40. int
  41. main(int argc, const char **argv)
  42. {
  43. const char *prog = *argv++;
  44. int to_linear = 0, to_gray = 0, to_color = 0;
  45. int channels = 0;
  46. double c[4];
  47. /* FE_TONEAREST is the IEEE754 round to nearest, preferring even, mode; i.e.
  48. * everything rounds to the nearest value except that '.5' rounds to the
  49. * nearest even value.
  50. */
  51. fesetround(FE_TONEAREST);
  52. c[3] = c[2] = c[1] = c[0] = 0;
  53. while (--argc > 0 && **argv == '-')
  54. {
  55. const char *arg = 1+*argv++;
  56. if (strcmp(arg, "sRGB") == 0)
  57. to_linear = 0;
  58. else if (strcmp(arg, "linear") == 0)
  59. to_linear = 1;
  60. else if (strcmp(arg, "gray") == 0)
  61. to_gray = 1, to_color = 0;
  62. else if (strcmp(arg, "color") == 0)
  63. to_gray = 0, to_color = 1;
  64. else
  65. usage(prog);
  66. }
  67. switch (argc)
  68. {
  69. default:
  70. usage(prog);
  71. break;
  72. case 4:
  73. c[3] = component(prog, argv[3], to_linear);
  74. ++channels;
  75. case 3:
  76. c[2] = component(prog, argv[2], to_linear);
  77. ++channels;
  78. case 2:
  79. c[1] = component(prog, argv[1], to_linear);
  80. ++channels;
  81. case 1:
  82. c[0] = component(prog, argv[0], to_linear);
  83. ++channels;
  84. break;
  85. }
  86. if (to_linear)
  87. {
  88. int i;
  89. int components = channels;
  90. if ((components & 1) == 0)
  91. --components;
  92. for (i=0; i<components; ++i) c[i] = linear_from_sRGB(c[i] / 255);
  93. if (components < channels)
  94. c[components] = c[components] / 255;
  95. }
  96. else
  97. {
  98. int i;
  99. for (i=0; i<4; ++i) c[i] /= 65535;
  100. if ((channels & 1) == 0)
  101. {
  102. double alpha = c[channels-1];
  103. if (alpha > 0)
  104. for (i=0; i<channels-1; ++i) c[i] /= alpha;
  105. else
  106. for (i=0; i<channels-1; ++i) c[i] = 1;
  107. }
  108. }
  109. if (to_gray)
  110. {
  111. if (channels < 3)
  112. {
  113. fprintf(stderr, "%s: too few channels (%d) for -gray\n",
  114. prog, channels);
  115. usage(prog);
  116. }
  117. c[0] = YfromRGB(c[0], c[1], c[2]);
  118. channels -= 2;
  119. }
  120. if (to_color)
  121. {
  122. if (channels > 2)
  123. {
  124. fprintf(stderr, "%s: too many channels (%d) for -color\n",
  125. prog, channels);
  126. usage(prog);
  127. }
  128. c[3] = c[1]; /* alpha, if present */
  129. c[2] = c[1] = c[0];
  130. }
  131. if (to_linear)
  132. {
  133. int i;
  134. if ((channels & 1) == 0)
  135. {
  136. double alpha = c[channels-1];
  137. for (i=0; i<channels-1; ++i) c[i] *= alpha;
  138. }
  139. for (i=0; i<channels; ++i) c[i] = nearbyint(c[i] * 65535);
  140. }
  141. else /* to sRGB */
  142. {
  143. int i = (channels+1)&~1;
  144. while (--i >= 0)
  145. c[i] = sRGB_from_linear(c[i]);
  146. for (i=0; i<channels; ++i) c[i] = nearbyint(c[i] * 255);
  147. }
  148. {
  149. int i;
  150. for (i=0; i<channels; ++i) printf(" %g", c[i]);
  151. }
  152. printf("\n");
  153. return 0;
  154. }