code wiki / (root) / nx_cdmap_pixjudge.nx

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}