blind-to-image.c (3846B)
1 /* See LICENSE file for copyright and license details. */ 2 #include "common.h" 3 4 USAGE("[-d depth | -f]") 5 6 static int luma_warning_triggered = 0; 7 static int gamut_warning_triggered = 0; 8 static int alpha_warning_triggered = 0; 9 static unsigned long long int max; 10 static int bytes; 11 12 #define WRITE_PIXEL(TYPE)\ 13 do {\ 14 unsigned long long int colours[4];\ 15 unsigned char buf[4 * 8];\ 16 int i, j, k, bm = bytes - 1;\ 17 \ 18 if (R < 0 || G < 0 || B < 0 || R > 1 || G > 1 || B > 1) {\ 19 if (gamut_warning_triggered) {\ 20 gamut_warning_triggered = 1;\ 21 weprintf("warning: out-of-gamut colour detected\n");\ 22 }\ 23 ; /* TODO gamut */\ 24 R = CLIP(0, R, 1);\ 25 G = CLIP(0, G, 1);\ 26 B = CLIP(0, B, 1);\ 27 }\ 28 \ 29 if (A < 0 || A > 1) {\ 30 if (alpha_warning_triggered) {\ 31 alpha_warning_triggered = 1;\ 32 weprintf("warning: alpha values truncated\n");\ 33 }\ 34 A = A < 0 ? 0 : 1;\ 35 }\ 36 \ 37 colours[0] = (unsigned long long int)(srgb_encode(R) * (TYPE)max + (TYPE)0.5);\ 38 colours[1] = (unsigned long long int)(srgb_encode(G) * (TYPE)max + (TYPE)0.5);\ 39 colours[2] = (unsigned long long int)(srgb_encode(B) * (TYPE)max + (TYPE)0.5);\ 40 colours[3] = (unsigned long long int)(A * (TYPE)max + (TYPE)0.5);\ 41 \ 42 for (i = k = 0; i < 4; i++, k += bytes) {\ 43 for (j = 0; j < bytes; j++) {\ 44 buf[k + bm - j] = (unsigned char)(colours[i]);\ 45 colours[i] >>= 8;\ 46 }\ 47 }\ 48 \ 49 ewriteall(STDOUT_FILENO, buf, (size_t)k, "<stdout>");\ 50 } while (0) 51 52 #define PROCESS(TYPE, SUFFIX)\ 53 do {\ 54 size_t i;\ 55 TYPE X, Y, Z, A, R, G, B;\ 56 for (i = 0; i < n; i += stream->pixel_size) {\ 57 X = ((TYPE *)(stream->buf + i))[0];\ 58 Y = ((TYPE *)(stream->buf + i))[1];\ 59 Z = ((TYPE *)(stream->buf + i))[2];\ 60 A = ((TYPE *)(stream->buf + i))[3];\ 61 \ 62 if (Y < 0 || Y > 1) {\ 63 if (luma_warning_triggered) {\ 64 luma_warning_triggered = 1;\ 65 weprintf("warning: %s colour detected\n",\ 66 Y < 0 ? "subblack" : "superwhite");\ 67 }\ 68 }\ 69 \ 70 ciexyz_to_srgb(X, Y, Z, &R, &G, &B);\ 71 write_pixel##SUFFIX(R, G, B, A);\ 72 }\ 73 } while (0) 74 75 static void write_pixel_d(double R, double G, double B, double A) {WRITE_PIXEL(double);} 76 static void write_pixel_f(float R, float G, float B, float A) {WRITE_PIXEL(float);} 77 78 static void process_xyza (struct stream *stream, size_t n) {PROCESS(double, _d);} 79 static void process_xyzaf(struct stream *stream, size_t n) {PROCESS(float, _f);} 80 81 int 82 main(int argc, char *argv[]) 83 { 84 struct stream stream; 85 int depth = 16, farbfeld = 0; 86 void (*process)(struct stream *stream, size_t n); 87 88 ARGBEGIN { 89 case 'd': 90 depth = etoi_flag('d', UARGF(), 1, 64); 91 break; 92 case 'f': 93 farbfeld = 1; 94 break; 95 default: 96 usage(); 97 } ARGEND; 98 99 if (argc || (farbfeld && depth != 16)) 100 usage(); 101 102 eopen_stream(&stream, NULL); 103 104 max = 1ULL << (depth - 1); 105 max |= max - 1; 106 bytes = (depth + 7) / 8; 107 108 if (!strcmp(stream.pixfmt, "xyza")) 109 process = process_xyza; 110 else if (!strcmp(stream.pixfmt, "xyza f")) 111 process = process_xyzaf; 112 else 113 eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); 114 115 if (farbfeld) { 116 uint32_t width = (uint32_t)(stream.width); 117 uint32_t height = (uint32_t)(stream.height); 118 if (stream.width > UINT32_MAX) 119 eprintf("%s: frame is too wide\n", stream.file); 120 if (stream.height > UINT32_MAX) 121 eprintf("%s: frame is too tall\n", stream.file); 122 width = htonl(width); 123 height = htonl(height); 124 ewriteall(STDOUT_FILENO, "farbfeld", 8, "<stdout>"); 125 ewriteall(STDOUT_FILENO, &width, 4, "<stdout>"); 126 ewriteall(STDOUT_FILENO, &height, 4, "<stdout>"); 127 } else { 128 printf("P7\n" 129 "WIDTH %zu\n" 130 "HEIGHT %zu\n" 131 "DEPTH 4\n" /* channels */ 132 "MAXVAL %llu\n" 133 "TUPLTYPE RGB_ALPHA\n" 134 "ENDHDR\n", stream.width, stream.height, max); 135 efflush(stdout, "<stdout>"); 136 } 137 138 process_stream(&stream, process); 139 return 0; 140 }