code wiki / (root) / nx_imgfacts.nx

nx_imgfacts.nx source

↩ module page · 175 lines · 6743 B

1// nx_imgfacts.nx -- per-asset DIMENSIONS + bytes for a gathered corpus, and a real GALLERY page. 2// 3// The operator's question is a product question, not a plumbing one: "are we getting too small of images?" 4// A contact sheet cannot answer it -- every tile is normalised to the same box, so a 120px thumbnail and a 5// 3000px original look identical. This decodes each asset for its TRUE pixel size, reports the distribution, 6// and emits a gallery that shows every image at its own scale with its dimensions stated. 7// 8// usage: nx_imgfacts <dir> <out.html> <url-prefix> [title] 9 10import "nx_str.nx" 11import "nx_syscalls.nx" 12import "nx_dir.nx" 13import "nx_img_to_rgb.nx" 14const IF_MAGIC_1024: i64 = 1024 15 16const IF_MAXROWS: i64 = 4096 17const IF_ARENA: i64 = 1048576 18const IF_PATH: i64 = 4096 19const IF_HTML: i64 = 4194304 20 21func if_puts(s: *u8) -> i64 { sys_write(1, s, nx_str_len(s)); return 0 } 22 23func if_num(v: i64, o: *u8) -> i64 { 24 let t: *u8 = sys_mmap(32) 25 var m: i64 = v 26 var k: i64 = 0 27 if m < 0 { m = 0 - m } 28 if m == 0 { t[0] = 48; k = 1 } 29 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 } 30 var i: i64 = 0 31 while i < k { o[i] = t[k - 1 - i]; i = i + 1 } 32 o[k] = 0 as u8 33 return k 34} 35 36func if_pi(v: i64) -> i64 { let o: *u8 = sys_mmap(32); let n: i64 = if_num(v, o); sys_write(1, o, n); return 0 } 37 38func if_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 } 39func if_catb(dst: *u8, off: i64, s: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { dst[off+i] = s[i]; i = i + 1 } return off + n } 40func if_catn(dst: *u8, off: i64, v: i64) -> i64 { let o: *u8 = sys_mmap(32); let n: i64 = if_num(v, o); return if_catb(dst, off, o, n) } 41 42func if_fsize(path: *u8) -> i64 { 43 let box: *i64 = sys_mmap(16) as *i64 44 let b: *u8 = sys_read_file(path, box) 45 if b == 0 as *u8 { return 0 } 46 return box[0] 47} 48 49func main(argc: i64, argv: *i64) -> i64 { 50 if argc < 4 { 51 if_puts("usage: nx_imgfacts <dir> <out.html> <url-prefix> [title]\n" as *u8) 52 sys_exit(2); return 2 53 } 54 let dir: *u8 = argv[1] as *u8 55 let outp: *u8 = argv[2] as *u8 56 let pfx: *u8 = argv[3] as *u8 57 var title: *u8 = "Gathered corpus" as *u8 58 if argc >= 5 { title = argv[4] as *u8 } 59 60 let rows: *NxDirRow = sys_mmap(NX_DIR_ROW_BYTES * IF_MAXROWS) as *NxDirRow 61 let arena: *u8 = sys_mmap(IF_ARENA) 62 let res: *NxDirResult = sys_mmap(NX_DIR_RESULT_BYTES) as *NxDirResult 63 nx_dir_list(dir, rows, IF_MAXROWS, arena, IF_ARENA, 0, res) 64 65 let path: *u8 = sys_mmap(IF_PATH) 66 let wh: *i64 = sys_mmap(32) as *i64 67 let html: *u8 = sys_mmap(IF_HTML) 68 var ho: i64 = 0 69 70 ho = if_cat(html, ho, "<section class='gal'>\n" as *u8) 71 72 var n_ok: i64 = 0 73 var n_bad: i64 = 0 74 var min_w: i64 = 0 75 var max_w: i64 = 0 76 var sum_w: i64 = 0 77 var n_tiny: i64 = 0 // widest side < 400 px = a thumbnail, not an original 78 var n_small: i64 = 0 // 400..799 79 var n_big: i64 = 0 // >= 800 80 var bytes_total: i64 = 0 81 82 var i: i64 = 0 83 while i < res.n_filled { 84 let row: *NxDirRow = nx_dir_row_at(rows, i) 85 var st: i64 = 0 86 if nx_dir_row_is_regular_file(row) != 1 { st = 1 } 87 88 if st == 0 { 89 var po: i64 = if_cat(path, 0, dir) 90 po = if_cat(path, po, "/" as *u8) 91 var c: i64 = 0 92 while c < row.name_len { path[po + c] = row.name_ptr[c]; c = c + 1 } 93 path[po + row.name_len] = 0 as u8 94 } 95 96 var fsz: i64 = 0 97 if st == 0 { fsz = if_fsize(path) } 98 99 var rgb: *u8 = 0 as *u8 100 if st == 0 { 101 wh[0] = 0 102 wh[1] = 0 103 rgb = nx_img_to_rgb(path, wh) 104 if rgb == 0 as *u8 { st = 1; n_bad = n_bad + 1 } 105 } 106 if st == 0 { if wh[0] <= 0 { st = 1; n_bad = n_bad + 1 } } 107 108 if st == 0 { 109 let w: i64 = wh[0] 110 let h: i64 = wh[1] 111 var big: i64 = w 112 if h > big { big = h } 113 n_ok = n_ok + 1 114 sum_w = sum_w + big 115 bytes_total = bytes_total + fsz 116 if min_w == 0 { min_w = big } 117 if big < min_w { min_w = big } 118 if big > max_w { max_w = big } 119 if big < 400 { n_tiny = n_tiny + 1 } 120 if big >= 400 { if big < 800 { n_small = n_small + 1 } } 121 if big >= 800 { n_big = n_big + 1 } 122 123 ho = if_cat(html, ho, "<figure><a href='" as *u8) 124 ho = if_cat(html, ho, pfx) 125 ho = if_catb(html, ho, row.name_ptr, row.name_len) 126 ho = if_cat(html, ho, "'><img loading='lazy' src='" as *u8) 127 ho = if_cat(html, ho, pfx) 128 ho = if_catb(html, ho, row.name_ptr, row.name_len) 129 ho = if_cat(html, ho, "' width='" as *u8) 130 ho = if_catn(html, ho, w) 131 ho = if_cat(html, ho, "' height='" as *u8) 132 ho = if_catn(html, ho, h) 133 ho = if_cat(html, ho, "' alt='Gathered asset, " as *u8) 134 ho = if_catn(html, ho, w) 135 ho = if_cat(html, ho, " by " as *u8) 136 ho = if_catn(html, ho, h) 137 ho = if_cat(html, ho, " pixels'></a><figcaption>" as *u8) 138 ho = if_catn(html, ho, w) 139 ho = if_cat(html, ho, "&times;" as *u8) 140 ho = if_catn(html, ho, h) 141 ho = if_cat(html, ho, " &middot; " as *u8) 142 ho = if_catn(html, ho, fsz / IF_MAGIC_1024) 143 ho = if_cat(html, ho, " KB" as *u8) 144 if big < 400 { ho = if_cat(html, ho, " <b class='tiny'>THUMBNAIL</b>" as *u8) } 145 ho = if_cat(html, ho, "</figcaption></figure>\n" as *u8) 146 } 147 148 i = i + 1 149 } 150 151 ho = if_cat(html, ho, "</section>\n" as *u8) 152 153 let fd: i64 = sys_openat_wr(outp, 0x1a4) 154 if fd < 0 { if_puts("IMGFACTS-FAIL open-out\n" as *u8); sys_exit(1); return 1 } 155 sys_write(fd, html, ho) 156 sys_close(fd) 157 158 var avg: i64 = 0 159 if n_ok > 0 { avg = sum_w / n_ok } 160 if_puts("{\"tool\":\"nx_imgfacts\",\"dir\":\"" as *u8); if_puts(dir) 161 if_puts("\",\"files\":" as *u8); if_pi(res.n_filled) 162 if_puts(",\"decoded\":" as *u8); if_pi(n_ok) 163 if_puts(",\"undecodable\":" as *u8); if_pi(n_bad) 164 if_puts(",\"longest_side_min\":" as *u8); if_pi(min_w) 165 if_puts(",\"longest_side_avg\":" as *u8); if_pi(avg) 166 if_puts(",\"longest_side_max\":" as *u8); if_pi(max_w) 167 if_puts(",\"thumbnails_under_400px\":" as *u8); if_pi(n_tiny) 168 if_puts(",\"mid_400_799\":" as *u8); if_pi(n_small) 169 if_puts(",\"full_800_plus\":" as *u8); if_pi(n_big) 170 if_puts(",\"bytes\":" as *u8); if_pi(bytes_total) 171 if_puts(",\"html\":\"" as *u8); if_puts(outp) 172 if_puts("\"}\nIMGFACTS-OK\n" as *u8) 173 sys_exit(0) 174 return 0 175}