blind

suckless command-line video editing utility
git clone git://git.suckless.org/blind
Log | Files | Refs | README | 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 }