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, "×" as *u8)
140 ho = if_catn(html, ho, h)
141 ho = if_cat(html, ho, " · " 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}