nx_cdmap_pixjudge.nx source
↩ module page · 176 lines · 10472 B
1// nx_cdmap_pixjudge.nx -- the position map's PIXEL REFEREE as a program (datavis DV2, 2026-09-15). Reads an emitted
2// compare page and its api.json, redraws the cdmap's labels and marks as INK through the sovereign font engine, counts the
3// readability defects on the pixels and compares DEFECTS with the grade the page published about itself.
4// usage: nx_cdmap_pixjudge <index.html> <api.json> <regular.ttf> <bold.ttf> [journal]
5// exit 0 AGREE the pixel defect count equals the published one
6// 1 DISAGREE the picture holds a defect the self-grade cannot see, or the reverse; every offender is named above
7// 2 usage
8// 3 UNPROVEN no cdmap, no labels, unpaired labels, unreadable frame or canvas, unreadable face, no ink drawn, or
9// an api.json without the grade -- named, never acquitted
10// [journal]: when given, ONE row is appended per run so a beat leaves a per-day ledger of agreement (the DV2 done-rule's
11// second clause): pj|<epoch>|<page>|<ll>|<lm>|<off>|<mm>|<inkpx>|<published defects>|<verdict>
12// Every number the verdict rests on is printed above it; the verdict line is LAST. license_tier: ORIGINAL
13import "nx_cdmap_pixjudge_lib.nx"
14import "nx_fsops_lib.nx"
15import "nx_gate_verdict.nx"
16
17const PJ_ARGC: i64 = 5
18const PJ_ARGC_JOURNAL: i64 = 6
19const PJ_EXIT_AGREE: i64 = 0
20const PJ_EXIT_DISAGREE: i64 = 1
21const PJ_EXIT_USAGE: i64 = 2
22const PJ_EXIT_UNPROVEN: i64 = 3
23const PJ_BLOCK: *u8 = "readability_cut"
24const PJ_ROW_BYTES: i64 = 1024
25const PJ_CH_PIPE: i64 = 124
26const PJ_CH_NL: i64 = 10
27
28func pj_kv(k: *u8, v: i64) -> i64 { gv_puts(" " as *u8); gv_puts(k); gv_puts("=" as *u8); gv_num(v); return 0 }
29func pj_unproven(why: *u8) -> i64 { gv_puts(" UNPROVEN: " as *u8); gv_puts(why); gv_puts("\nverdict=UNPROVEN\n" as *u8); sys_exit(PJ_EXIT_UNPROVEN); return PJ_EXIT_UNPROVEN }
30func pj_pipe(d: *u8, o: i64) -> i64 { d[o] = PJ_CH_PIPE as u8; return o + 1 }
31func pj_journal(path: *u8, page: *u8, vec: *i64, pub: i64, verdict: *u8) -> i64 {
32 let d: *u8 = sys_mmap(PJ_ROW_BYTES)
33 var o: i64 = gv_cat(d, 0, "pj" as *u8)
34 o = pj_pipe(d, o); o = gv_catn(d, o, sys_now_realtime_sec())
35 o = pj_pipe(d, o); o = gv_cat(d, o, page)
36 o = pj_pipe(d, o); o = gv_catn(d, o, vec[CRG_V_LL])
37 o = pj_pipe(d, o); o = gv_catn(d, o, vec[CRG_V_LM])
38 o = pj_pipe(d, o); o = gv_catn(d, o, vec[CRG_V_OFF])
39 o = pj_pipe(d, o); o = gv_catn(d, o, vec[CRG_V_MM])
40 o = pj_pipe(d, o); o = gv_catn(d, o, vec[CRG_V_INKPX])
41 o = pj_pipe(d, o); o = gv_catn(d, o, pub)
42 o = pj_pipe(d, o); o = gv_cat(d, o, verdict)
43 d[o] = PJ_CH_NL as u8; o = o + 1
44 let rc: i64 = fsx_append(path, d, o)
45 gv_puts(" journal=" as *u8); gv_puts(path); pj_kv("append_rc" as *u8, rc); pj_kv("bytes" as *u8, o); gv_puts("\n" as *u8)
46 return rc
47}
48// name every offender so a DISAGREE carries its remedy: which pair shares ink, which label sits on whose mark, which
49// label leaves the frame
50func pj_explain(r: *i64) -> i64 {
51 let nl: i64 = r[CRG_R_NL]
52 let W: i64 = r[CRG_R_W]
53 let H: i64 = r[CRG_R_H]
54 let masks: *i64 = r[CRG_R_MASKS] as *i64
55 let mx: *i64 = r[CRG_R_MX] as *i64
56 let my: *i64 = r[CRG_R_MY] as *i64
57 let mr: *i64 = r[CRG_R_MR] as *i64
58 let fr: *i64 = r[CRG_R_FRAME] as *i64
59 let names: *u8 = r[CRG_R_NAMES] as *u8
60 var i: i64 = 0
61 while i < nl {
62 var j: i64 = i + 1
63 while j < nl {
64 let ov: i64 = crg_overlap(masks[i] as *u8, masks[j] as *u8, W * H)
65 if ov > 0 { gv_puts(" LL " as *u8); gv_puts(cr_name_at(names, i)); gv_puts(" x " as *u8); gv_puts(cr_name_at(names, j)); pj_kv("shared_ink_px" as *u8, ov); gv_puts("\n" as *u8) }
66 j = j + 1
67 }
68 j = 0
69 while j < nl {
70 if j != i {
71 let od: i64 = crg_ink_over_disk(masks[i] as *u8, W, H, mx[j], my[j], mr[j])
72 if od > 0 { gv_puts(" LM " as *u8); gv_puts(cr_name_at(names, i)); gv_puts(" over the mark of " as *u8); gv_puts(cr_name_at(names, j)); pj_kv("ink_px_in_disk" as *u8, od); gv_puts("\n" as *u8) }
73 }
74 j = j + 1
75 }
76 let bb: *i64 = crg_bbox_at(r, i)
77 if crg_bbox_off(bb, fr) == 1 { gv_puts(" OFF " as *u8); gv_puts(cr_name_at(names, i)); pj_kv("ink_x0" as *u8, bb[CRG_B_X0]); pj_kv("ink_x1" as *u8, bb[CRG_B_X1]); pj_kv("frame_x1" as *u8, fr[CR_F_X1]); gv_puts("\n" as *u8) }
78 i = i + 1
79 }
80 // the notes (datavis DV5): a note is named by its index; its ink is one mask over all its lines
81 let nn: i64 = r[CRG_R_NN]
82 let nmasks: *i64 = r[CRG_R_NMASKS] as *i64
83 var g: i64 = 0
84 while g < nn {
85 let gm: *u8 = nmasks[g] as *u8
86 var q: i64 = 0
87 while q < nl {
88 let ovn: i64 = crg_overlap(gm, masks[q] as *u8, W * H)
89 if ovn > 0 { gv_puts(" LL note " as *u8); gv_num(g); gv_puts(" x " as *u8); gv_puts(cr_name_at(names, q)); pj_kv("shared_ink_px" as *u8, ovn); gv_puts("\n" as *u8) }
90 let odn: i64 = crg_ink_over_disk(gm, W, H, mx[q], my[q], mr[q])
91 if odn > 0 { gv_puts(" LM note " as *u8); gv_num(g); gv_puts(" over the mark of " as *u8); gv_puts(cr_name_at(names, q)); pj_kv("ink_px_in_disk" as *u8, odn); gv_puts("\n" as *u8) }
92 q = q + 1
93 }
94 var g2: i64 = g + 1
95 while g2 < nn {
96 let ovg: i64 = crg_overlap(gm, nmasks[g2] as *u8, W * H)
97 if ovg > 0 { gv_puts(" LL note " as *u8); gv_num(g); gv_puts(" x note " as *u8); gv_num(g2); pj_kv("shared_ink_px" as *u8, ovg); gv_puts("\n" as *u8) }
98 g2 = g2 + 1
99 }
100 let nbb: *i64 = crg_nbbox_at(r, g)
101 if crg_bbox_off(nbb, fr) == 1 { gv_puts(" OFF note " as *u8); gv_num(g); pj_kv("ink_x0" as *u8, nbb[CRG_B_X0]); pj_kv("ink_x1" as *u8, nbb[CRG_B_X1]); pj_kv("frame_x1" as *u8, fr[CR_F_X1]); gv_puts("\n" as *u8) }
102 g = g + 1
103 }
104 return 0
105}
106
107func main(argc: i64, argv: *i64) -> i64 {
108 if argc < PJ_ARGC {
109 gv_puts("usage: nx_cdmap_pixjudge <index.html> <api.json> <regular.ttf> <bold.ttf> [journal]\n" as *u8)
110 sys_exit(PJ_EXIT_USAGE); return PJ_EXIT_USAGE
111 }
112 let page: *u8 = argv[1] as *u8
113 let api: *u8 = argv[2] as *u8
114 let freg: *u8 = argv[3] as *u8
115 let fbold: *u8 = argv[4] as *u8
116 var journal: *u8 = 0 as *u8
117 if argc >= PJ_ARGC_JOURNAL { journal = argv[5] as *u8 }
118 let lens: *i64 = crg_i64(2)
119 let h: *u8 = sys_read_file(page, lens)
120 gv_puts("NX-CDMAP-PIXJUDGE page=" as *u8); gv_puts(page); pj_kv("page_bytes" as *u8, lens[0]); pj_kv("ink_min_of_255" as *u8, CRG_INK_MIN); gv_puts("\n" as *u8)
121 if (h as i64) == 0 { return pj_unproven("page unreadable" as *u8) }
122 let fhr: *i64 = tf_load(freg)
123 var fhb: *i64 = tf_load(fbold)
124 if (fhb as i64) == 0 { fhb = fhr }
125 if (fhr as i64) != 0 { gv_puts(" font=" as *u8); gv_puts(freg); pj_kv("upem" as *u8, tf_upem(fhr)); pj_kv("glyphs" as *u8, tf_nglyphs(fhr)); gv_puts("\n" as *u8) }
126 let r: *i64 = crg_rec_new()
127 let vec: *i64 = crg_i64(CRG_V_W)
128 let rc: i64 = crg_judge(h, lens[0], fhr, fhb, r, vec)
129 gv_puts(" scan" as *u8); pj_kv("labels" as *u8, r[CRG_R_NL]); pj_kv("marks" as *u8, r[CRG_R_NM]); pj_kv("notes" as *u8, r[CRG_R_NN]); pj_kv("note_lines" as *u8, r[CRG_R_NNL]); pj_kv("canvas_w" as *u8, r[CRG_R_W]); pj_kv("canvas_h" as *u8, r[CRG_R_H])
130 let fr: *i64 = r[CRG_R_FRAME] as *i64
131 pj_kv("frame_x0" as *u8, fr[CR_F_X0]); pj_kv("frame_y0" as *u8, fr[CR_F_Y0]); pj_kv("frame_x1" as *u8, fr[CR_F_X1]); pj_kv("frame_y1" as *u8, fr[CR_F_Y1]); gv_puts("\n" as *u8)
132 if rc != CRG_OK { return pj_unproven(crg_rc_name(rc)) }
133 let names: *u8 = r[CRG_R_NAMES] as *u8
134 let lx: *i64 = r[CRG_R_LX] as *i64
135 let ly: *i64 = r[CRG_R_LY] as *i64
136 let lfont: *i64 = r[CRG_R_LFONT] as *i64
137 let lbold: *i64 = r[CRG_R_LBOLD] as *i64
138 let inkv: *i64 = r[CRG_R_INK] as *i64
139 var i: i64 = 0
140 while i < r[CRG_R_NL] {
141 let bb: *i64 = crg_bbox_at(r, i)
142 gv_puts(" label " as *u8); gv_num(i); gv_puts(" name=" as *u8); gv_puts(cr_name_at(names, i))
143 pj_kv("x" as *u8, lx[i]); pj_kv("baseline" as *u8, ly[i] + CR_LABEL_BASE); pj_kv("font" as *u8, lfont[i]); pj_kv("bold" as *u8, lbold[i])
144 pj_kv("ink_px" as *u8, inkv[i]); pj_kv("ink_x0" as *u8, bb[CRG_B_X0]); pj_kv("ink_y0" as *u8, bb[CRG_B_Y0]); pj_kv("ink_x1" as *u8, bb[CRG_B_X1]); pj_kv("ink_y1" as *u8, bb[CRG_B_Y1])
145 gv_puts("\n" as *u8)
146 i = i + 1
147 }
148 let ninkv: *i64 = r[CRG_R_NINK] as *i64
149 var g: i64 = 0
150 while g < r[CRG_R_NN] {
151 let nbb: *i64 = crg_nbbox_at(r, g)
152 gv_puts(" note " as *u8); gv_num(g); pj_kv("ink_px" as *u8, ninkv[g]); pj_kv("ink_x0" as *u8, nbb[CRG_B_X0]); pj_kv("ink_y0" as *u8, nbb[CRG_B_Y0]); pj_kv("ink_x1" as *u8, nbb[CRG_B_X1]); pj_kv("ink_y1" as *u8, nbb[CRG_B_Y1]); gv_puts("\n" as *u8)
153 g = g + 1
154 }
155 gv_puts(" pixel: " as *u8); pj_kv("LL" as *u8, vec[CRG_V_LL]); pj_kv("LM" as *u8, vec[CRG_V_LM]); pj_kv("OFF" as *u8, vec[CRG_V_OFF]); pj_kv("MM" as *u8, vec[CRG_V_MM]); pj_kv("INKPX" as *u8, vec[CRG_V_INKPX]); pj_kv("DEFECTS" as *u8, vec[CRG_V_DEFECTS]); gv_puts("\n" as *u8)
156 pj_explain(r)
157 let jl: *i64 = crg_i64(2)
158 let j: *u8 = sys_read_file(api, jl)
159 if (j as i64) == 0 { return pj_unproven("api.json unreadable" as *u8) }
160 let pll: i64 = cr_json_int(j, jl[0], PJ_BLOCK, "label_overlaps" as *u8)
161 let plm: i64 = cr_json_int(j, jl[0], PJ_BLOCK, "labels_over_marks" as *u8)
162 let poff: i64 = cr_json_int(j, jl[0], PJ_BLOCK, "off_canvas" as *u8)
163 let pmm: i64 = cr_json_int(j, jl[0], PJ_BLOCK, "mark_overlaps" as *u8)
164 let pdef: i64 = cr_json_int(j, jl[0], PJ_BLOCK, "defects" as *u8)
165 gv_puts(" published:" as *u8); pj_kv("LL" as *u8, pll); pj_kv("LM" as *u8, plm); pj_kv("OFF" as *u8, poff); pj_kv("MM" as *u8, pmm); pj_kv("DEFECTS" as *u8, pdef); gv_puts("\n" as *u8)
166 if pdef == CR_ABSENT { return pj_unproven("api.json carries no readability_cut grade" as *u8) }
167 let agree: i64 = crg_agree(vec, pdef)
168 pj_kv("pixel_defects_equal_published" as *u8, agree); gv_puts("\n" as *u8)
169 var verdict: *u8 = "DISAGREE" as *u8
170 if agree == 1 { verdict = "AGREE" as *u8 }
171 if (journal as i64) != 0 { pj_journal(journal, page, vec, pdef, verdict) }
172 gv_puts("verdict=" as *u8); gv_puts(verdict); gv_puts("\n" as *u8)
173 if agree == 1 { sys_exit(PJ_EXIT_AGREE); return PJ_EXIT_AGREE }
174 sys_exit(PJ_EXIT_DISAGREE)
175 return PJ_EXIT_DISAGREE
176}