blind-to-image.c - blind - suckless command-line video editing utility
(HTM) git clone git://git.suckless.org/blind
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
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 }