blind

suckless command-line video editing utility
git clone git://git.suckless.org/blind
Log | Files | Refs | README | LICENSE

blind-apply-palette.c (3026B)


      1 /* See LICENSE file for copyright and license details. */
      2 #ifndef TYPE
      3 #include "common.h"
      4 
      5 USAGE("palette-stream")
      6 
      7 static double (*compare)(double x1, double y1, double z1, double a1, double x2, double y2, double z2, double a2);
      8 /* TODO add more formulae: https://en.wikipedia.org/wiki/Color_difference */
      9 
     10 static double
     11 distance_xyz(double x1, double y1, double z1, double a1, double x2, double y2, double z2, double a2)
     12 {
     13 	x2 -= x1, x2 *= x2;
     14 	y2 -= y1, y2 *= y2;
     15 	z2 -= z1, z2 *= z2;
     16 	a2 -= a1, a2 *= a2;
     17 	return sqrt(x2 + y2 + z2 + a2);
     18 }
     19 
     20 #define FILE "blind-apply-palette.c"
     21 #include "define-functions.h"
     22 
     23 int
     24 main(int argc, char *argv[])
     25 {
     26 	struct stream stream, palette;
     27 	void (*process)(struct stream *stream, struct stream *palette, char *pal);
     28 	char *pal;
     29 
     30 	compare = distance_xyz;
     31 
     32 	UNOFLAGS(argc != 1);
     33 
     34 	eopen_stream(&stream, NULL);
     35 	eopen_stream(&palette, argv[0]);
     36 
     37 	SELECT_PROCESS_FUNCTION(&stream);
     38 	CHECK_N_CHAN(&stream, 4, 4);
     39 
     40 	if (strcmp(stream.pixfmt, palette.pixfmt))
     41 		eprintf("videos use incompatible pixel formats\n");
     42 
     43 	echeck_dimensions(&stream, WIDTH | HEIGHT, NULL);
     44 	echeck_dimensions(&palette, WIDTH | HEIGHT, NULL);
     45 	pal = emalloc(palette.frame_size);
     46 	fprint_stream_head(stdout, &stream);
     47 	efflush(stdout, "<stdout>");
     48 
     49 	process(&stream, &palette, pal);
     50 
     51 	free(pal);
     52 	return 0;
     53 }
     54 
     55 #else
     56 
     57 static void
     58 PROCESS(struct stream *stream, struct stream *palette, char *pal)
     59 {
     60 	size_t i, j, n, m;
     61 	size_t palsiz = palette->width * palette->height;
     62 	size_t best = 0;
     63 	TYPE x, y, z, a, lx = 0, ly = 0, lz = 0, la = 0;
     64 	TYPE cx, cy, cz, ca;
     65 	double distance, best_distance = 0;
     66 	while (eread_frame(palette, pal)) {
     67 		m = stream->frame_size;
     68 		do {
     69 			n = MIN(stream->ptr, m) / stream->pixel_size;
     70 			for (i = 0; i < n; i++) {
     71 				x = ((TYPE *)(stream->buf + i * stream->pixel_size))[0];
     72 				y = ((TYPE *)(stream->buf + i * stream->pixel_size))[1];
     73 				z = ((TYPE *)(stream->buf + i * stream->pixel_size))[2];
     74 				a = ((TYPE *)(stream->buf + i * stream->pixel_size))[3];
     75 				if ((!i && m == stream->frame_size) || x != lx || y != ly || z != lz || a != la) {
     76 					for (j = 0; j < palsiz; j++) {
     77 						cx = ((TYPE *)(pal + j * stream->pixel_size))[0];
     78 						cy = ((TYPE *)(pal + j * stream->pixel_size))[1];
     79 						cz = ((TYPE *)(pal + j * stream->pixel_size))[2];
     80 						ca = ((TYPE *)(pal + j * stream->pixel_size))[3];
     81 						distance = compare((double)x, (double)y, (double)z, (double)a,
     82 								   (double)cx, (double)cy, (double)cz, (double)ca);
     83 						if (!j || distance < best_distance) {
     84 							best_distance = distance;
     85 							best = j;
     86 						}
     87 					}
     88 					lx = x, ly = y, lz = z, la = a;
     89 				}
     90 				memcpy(stream->buf + i * stream->pixel_size,
     91 				       pal + best * stream->pixel_size,
     92 				       stream->pixel_size);
     93 			}
     94 			m -= n *= stream->pixel_size;
     95 			ewriteall(STDOUT_FILENO, stream->buf, n, "<stdout>");
     96 			memmove(stream->buf, stream->buf + n, stream->ptr -= n);
     97 		} while (m && eread_stream(stream, SIZE_MAX));
     98 		if (m)
     99 			eprintf("%s: incomplete frame\n", stream->file);
    100 	}
    101 }
    102 
    103 #endif