ff2sp.c (1488B)
1 #include <rcx/all.h> 2 #include <stdio.h> 3 #include <string.h> 4 5 #include "common.h" 6 7 #define USAGE \ 8 "usage: %s SAND [THRESHOLD]\n" \ 9 "where SAND is decimal and THRESHOLD is 8 or 16 bit grayscale hex\n" 10 11 u32 12 parse_dec(char *s) { 13 u32 v = 0; 14 for (; *s; s++) { 15 if (*s < '0' || *s > '9') 16 r_fatalf("expected decimal numeral"); 17 u32 d = *s - '0'; 18 if (v > U32_MAX / 10 || 10 * v > U32_MAX - d) 19 r_fatalf("overflow"); 20 v = 10 * v + d; 21 } 22 return v; 23 } 24 25 Sandpile 26 sandpilify(Image img, u32 amount, u16 threshold) { 27 usize w = img.w; 28 usize h = img.h; 29 30 u32 *sand = r_eallocz((w + 2) * (h + 2) * sizeof(u32)); 31 for (usize y = 0; y < h; y++) { 32 for (usize x = 0; x < w; x++) { 33 Rgba p = img.pixels[y * w + x]; 34 if (p.r != p.g || p.g != p.b) 35 r_fatalf("expected grayscale"); 36 // XXX: Error/warn if alpha != 0xffff ? 37 sand[(y + 1) * (w + 2) + (x + 1)] = p.r >= threshold ? amount : 0; 38 } 39 } 40 41 return (Sandpile){.w = w, .h = h, .sand = sand}; 42 } 43 44 int 45 main(int argc, char **argv) { 46 CHECK_FOR_HELP_OPTION(USAGE, argc, argv); 47 48 if (argc < 2 || argc > 3) { 49 fprintf(stderr, USAGE, argv[0]); 50 return 1; 51 } 52 u32 amount = parse_dec(argv[1]); 53 u16 threshold; 54 if (argc == 2) { 55 threshold = 0x8888; 56 } else { 57 usize len = strlen(argv[2]); 58 if (len != 2 && len != 4) 59 r_fatalf("expected 2 or 4 hexadecimal numerals"); 60 threshold = parse_rgba_channel(argv[2], len == 4); 61 } 62 63 Image img = ff_fread(stdin); 64 Sandpile sp = sandpilify(img, amount, threshold); 65 sp_fwrite(stdout, sp); 66 }