code wiki / (root) / nx_contactsheet.nx

nx_contactsheet.nx source

↩ module page · 196 lines · 6859 B

1// nx_contactsheet.nx -- VISUAL VALIDATION: render a whole gathered corpus as ONE tiled PNG. 2// 3// Numbers prove a pipeline ran; pixels prove it ran CORRECTLY. Every tile here is decoded through OUR 4// decoder (nx_img_to_rgb -> the same path the fingerprinter uses), box-average downscaled and composited. 5// So the sheet is simultaneously (a) a look at the corpus and (b) proof the decode path yields real pixels: 6// a broken decoder produces noise or a hole, not a recognisable thumbnail. 7// 8// usage: nx_contactsheet <dir> <out.png> [tile_px] [cols] 9 10import "nx_str.nx" 11import "nx_syscalls.nx" 12import "nx_dir.nx" 13import "nx_img_to_rgb.nx" 14import "nx_png_write.nx" 15 16const CS_MAXROWS: i64 = 4096 17const CS_ARENA: i64 = 1048576 18const CS_PATH: i64 = 4096 19const CS_PAD: i64 = 4 20 21func cs_puts(s: *u8) -> i64 { sys_write(1, s, nx_str_len(s)); return 0 } 22 23func cs_pi(v: i64) -> i64 { 24 let t: *u8 = sys_mmap(32) 25 let o: *u8 = sys_mmap(32) 26 var m: i64 = v 27 var k: i64 = 0 28 if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) } 29 if m == 0 { t[0] = 48; k = 1 } 30 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 } 31 var i: i64 = 0 32 while i < k { o[i] = t[k - 1 - i]; i = i + 1 } 33 sys_write(1, o, k) 34 return 0 35} 36 37func cs_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[off+i] = s[i]; i = i + 1 } return off + i } 38 39func cs_atoi(s: *u8) -> i64 { 40 var i: i64 = 0 41 var v: i64 = 0 42 while s[i] != (0 as u8) { 43 let c: i64 = s[i] as i64 44 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } 45 i = i + 1 46 } 47 return v 48} 49 50// box-average blit of src (sw x sh RGB) into sheet at (ox,oy) scaled to fw x fh 51func cs_draw(sheet: *u8, SW: i64, ox: i64, oy: i64, fw: i64, fh: i64, src: *u8, sw: i64, sh: i64) -> i64 { 52 var y: i64 = 0 53 while y < fh { 54 var x: i64 = 0 55 while x < fw { 56 let sx0: i64 = (x * sw) / fw 57 let sy0: i64 = (y * sh) / fh 58 var sx1: i64 = ((x + 1) * sw) / fw 59 var sy1: i64 = ((y + 1) * sh) / fh 60 if sx1 <= sx0 { sx1 = sx0 + 1 } 61 if sy1 <= sy0 { sy1 = sy0 + 1 } 62 if sx1 > sw { sx1 = sw } 63 if sy1 > sh { sy1 = sh } 64 var r: i64 = 0 65 var g: i64 = 0 66 var b: i64 = 0 67 var n: i64 = 0 68 var yy: i64 = sy0 69 while yy < sy1 { 70 var xx: i64 = sx0 71 while xx < sx1 { 72 let o: i64 = (yy * sw + xx) * 3 73 r = r + (src[o] as i64) 74 g = g + (src[o+1] as i64) 75 b = b + (src[o+2] as i64) 76 n = n + 1 77 xx = xx + 1 78 } 79 yy = yy + 1 80 } 81 if n > 0 { 82 let d: i64 = ((oy + y) * SW + (ox + x)) * 3 83 sheet[d] = (r / n) as u8 84 sheet[d+1] = (g / n) as u8 85 sheet[d+2] = (b / n) as u8 86 } 87 x = x + 1 88 } 89 y = y + 1 90 } 91 return 0 92} 93 94func main(argc: i64, argv: *i64) -> i64 { 95 var dir: *u8 = "knowledge/media/barack_obama" as *u8 96 var outp: *u8 = "knowledge/status/contactsheet.png" as *u8 97 var tile: i64 = 96 98 var cols: i64 = 10 99 if argc >= 2 { dir = argv[1] as *u8 } 100 if argc >= 3 { outp = argv[2] as *u8 } 101 if argc >= 4 { tile = cs_atoi(argv[3] as *u8) } 102 if argc >= 5 { cols = cs_atoi(argv[4] as *u8) } 103 if tile < 16 { tile = 16 } 104 if tile > 512 { tile = 512 } 105 if cols < 1 { cols = 1 } 106 if cols > 64 { cols = 64 } 107 108 let rows_a: *NxDirRow = sys_mmap(NX_DIR_ROW_BYTES * CS_MAXROWS) as *NxDirRow 109 let arena: *u8 = sys_mmap(CS_ARENA) 110 let res: *NxDirResult = sys_mmap(NX_DIR_RESULT_BYTES) as *NxDirResult 111 let lrc: i64 = nx_dir_list(dir, rows_a, CS_MAXROWS, arena, CS_ARENA, 0, res) 112 cs_puts("=== nx_contactsheet dir=" as *u8); cs_puts(dir) 113 cs_puts(" list_rc=" as *u8); cs_pi(lrc) 114 cs_puts(" entries=" as *u8); cs_pi(res.n_filled); cs_puts("\n" as *u8) 115 if res.n_filled <= 0 { cs_puts("CONTACTSHEET-FAIL empty-dir\n" as *u8); sys_exit(1); return 1 } 116 117 let nfiles: i64 = res.n_filled 118 var nrows: i64 = (nfiles + cols - 1) / cols 119 if nrows < 1 { nrows = 1 } 120 let SW: i64 = cols * (tile + CS_PAD) + CS_PAD 121 let SH: i64 = nrows * (tile + CS_PAD) + CS_PAD 122 let sheet: *u8 = sys_mmap(SW * SH * 3 + 64) 123 124 // background 125 var p: i64 = 0 126 while p < SW * SH { 127 sheet[p*3] = 18 as u8 128 sheet[p*3+1] = 20 as u8 129 sheet[p*3+2] = 26 as u8 130 p = p + 1 131 } 132 133 let path: *u8 = sys_mmap(CS_PATH) 134 let wh: *i64 = sys_mmap(32) as *i64 135 var placed: i64 = 0 136 var undec: i64 = 0 137 138 var i: i64 = 0 139 while i < nfiles { 140 let row: *NxDirRow = nx_dir_row_at(rows_a, i) 141 var st: i64 = 0 142 if nx_dir_row_is_regular_file(row) != 1 { st = 1 } 143 144 if st == 0 { 145 var po: i64 = cs_cat(path, 0, dir) 146 po = cs_cat(path, po, "/" as *u8) 147 var c: i64 = 0 148 while c < row.name_len { path[po + c] = row.name_ptr[c]; c = c + 1 } 149 path[po + row.name_len] = 0 as u8 150 } 151 152 var rgb: *u8 = 0 as *u8 153 if st == 0 { 154 wh[0] = 0 155 wh[1] = 0 156 rgb = nx_img_to_rgb(path, wh) 157 if rgb == 0 as *u8 { st = 1; undec = undec + 1 } 158 } 159 if st == 0 { if wh[0] <= 0 { st = 1; undec = undec + 1 } } 160 if st == 0 { if wh[1] <= 0 { st = 1; undec = undec + 1 } } 161 162 if st == 0 { 163 let sw: i64 = wh[0] 164 let sh: i64 = wh[1] 165 // aspect-fit inside the tile 166 var fw: i64 = tile 167 var fh: i64 = tile 168 if sw >= sh { fh = (tile * sh) / sw } else { fw = (tile * sw) / sh } 169 if fw < 1 { fw = 1 } 170 if fh < 1 { fh = 1 } 171 let cx: i64 = placed % cols 172 let cy: i64 = placed / cols 173 let ox: i64 = CS_PAD + cx * (tile + CS_PAD) + (tile - fw) / 2 174 let oy: i64 = CS_PAD + cy * (tile + CS_PAD) + (tile - fh) / 2 175 cs_draw(sheet, SW, ox, oy, fw, fh, rgb, sw, sh) 176 placed = placed + 1 177 } 178 179 i = i + 1 180 } 181 182 let wrc: i64 = nx_png_write_rgb(outp, sheet, SW, SH) 183 cs_puts("{\"tool\":\"nx_contactsheet\",\"dir\":\"" as *u8); cs_puts(dir) 184 cs_puts("\",\"files\":" as *u8); cs_pi(nfiles) 185 cs_puts(",\"placed\":" as *u8); cs_pi(placed) 186 cs_puts(",\"undecodable\":" as *u8); cs_pi(undec) 187 cs_puts(",\"sheet_w\":" as *u8); cs_pi(SW) 188 cs_puts(",\"sheet_h\":" as *u8); cs_pi(SH) 189 cs_puts(",\"tile\":" as *u8); cs_pi(tile) 190 cs_puts(",\"cols\":" as *u8); cs_pi(cols) 191 cs_puts(",\"png_rc\":" as *u8); cs_pi(wrc) 192 cs_puts(",\"out\":\"" as *u8); cs_puts(outp) 193 cs_puts("\"}\nCONTACTSHEET-OK\n" as *u8) 194 sys_exit(0) 195 return 0 196}