code wiki / (root) / nx_color_meter.nx

nx_color_meter.nx source

↩ module page · 74 lines · 3337 B

1const NX_MAGIC_1000000: i64 = 1000000 2const NX_MAGIC_50000: i64 = 50000 3const NX_MAGIC_10000: i64 = 10000 4// nx_color_meter.nx -- per-color (CMYK) toner coverage measurement = the COLOR analog of the black-toner 5// real-coverage exceed. The operator's ask: "color toner monitoring, not just black." We own the bitmap, so 6// we measure REAL per-channel toner consumption with GCR under-color removal (black pulled into the K channel, 7// exactly as a color laser separates), giving honest C/M/Y/K consumption per page -- the per-color truth the 8// printer's lying per-color gauge can't be trusted for (HP "fake empty" = $5M settlement; per the sovereign 9// researcher's Ink/Toner-cartridge sources). PURE integer, NO float, NO syscalls -> never-brick #26. 10// Grounded: ISO/IEC 19798 (color toner page yield) + ISO/IEC 19752 (mono), 5%-coverage standard page. 11// genealogy_id: project-printer-management-ipp-sclass-2026-06-20 ; license_tier: ORIGINAL 12 13const NX_CMY_C: i64 = 0 14const NX_CMY_M: i64 = 1 15const NX_CMY_Y: i64 = 2 16const NX_CMY_K: i64 = 3 17 18// Per-channel coverage in ppm (1e6 = 100% of that colorant over the page) from an RGB bitmap (3 bytes/pixel). 19// out4 receives [C, M, Y, K]. CMY demand = 255 - channel; GCR: K = min(C,M,Y) -> black toner, C/M/Y reduced 20// by K (so pure gray/black consumes K toner, not a muddy CMY mix -- how a real color laser prints). 21func nx_color_coverage(rgb: *u8, npix: i64, out4: *i64) -> i64 { 22 if npix <= 0 { out4[0] = 0; out4[1] = 0; out4[2] = 0; out4[3] = 0; return 0 } 23 var sc: i64 = 0 24 var sm: i64 = 0 25 var sy: i64 = 0 26 var sk: i64 = 0 27 var i: i64 = 0 28 while i < npix { 29 let base: i64 = i * 3 30 let r: i64 = rgb[base] as i64 31 let g: i64 = rgb[base + 1] as i64 32 let bb: i64 = rgb[base + 2] as i64 33 let c: i64 = 255 - r 34 let m: i64 = 255 - g 35 let y: i64 = 255 - bb 36 var k: i64 = c 37 if m < k { k = m } 38 if y < k { k = y } 39 sc = sc + (c - k) 40 sm = sm + (m - k) 41 sy = sy + (y - k) 42 sk = sk + k 43 i = i + 1 44 } 45 let denom: i64 = 255 * npix 46 out4[0] = (sc * NX_MAGIC_1000000) / denom 47 out4[1] = (sm * NX_MAGIC_1000000) / denom 48 out4[2] = (sy * NX_MAGIC_1000000) / denom 49 out4[3] = (sk * NX_MAGIC_1000000) / denom 50 return 0 51} 52 53// Per-color remaining toner in basis points (10000 = 100%) given that color's ISO-19798 page yield and the 54// cumulative coverage consumed (ppm summed over pages). capacity = yield_pages * 50000 ppm (the 5% ISO page). 55// -1 if yield unknown. Mirrors the mono nx_toner_ledger, per channel. 56func nx_color_remaining_bp(yield_pages: i64, consumed_ppm: i64) -> i64 { 57 if yield_pages <= 0 { return 0 - 1 } 58 let cap: i64 = yield_pages * NX_MAGIC_50000 59 if cap <= 0 { return 0 - 1 } 60 if consumed_ppm >= cap { return 0 } 61 return ((cap - consumed_ppm) * NX_MAGIC_10000) / cap 62} 63 64// sealed per-color status from a remaining-bp value: OK / LOW (<10%) / EMPTY (0) / UNKNOWN (-1). 65const NX_CSUP_OK: i64 = 1 66const NX_CSUP_LOW: i64 = 2 67const NX_CSUP_EMPTY: i64 = 3 68const NX_CSUP_UNKNOWN: i64 = 4 69func nx_color_status(remaining_bp: i64) -> i64 { 70 if remaining_bp < 0 { return NX_CSUP_UNKNOWN } 71 if remaining_bp == 0 { return NX_CSUP_EMPTY } 72 if remaining_bp < 1000 { return NX_CSUP_LOW } 73 return NX_CSUP_OK 74}