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 }