nx_urf.nx source
↩ module page · 79 lines · 3661 B
1// nx_urf.nx -- sovereign URF (Apple Raster / UNIRAST) document encoder. Wraps the shared PWG RLE in the
2// URF container the Brother (and every AirPrint printer) accepts (document-format image/urf).
3//
4// URF layout (reverse-engineered + cross-checked; the Brother advertises urf-supported=W8 = 8-bit gray):
5// FILE HEADER (12 bytes): "UNIRAST\0" (8) + uint32 BE page-count.
6// PER-PAGE HEADER (32 bytes):
7// [0] bitsPerPixel (8 for sgray_8) [1] colorspace (sGray=0,sRGB=1) [2] duplex (0/1/2)
8// [3] quality (0 def,3 draft,4 normal,5 high) [4] mediaType (0 auto) [5] mediaPosition (0 auto)
9// [6..11] reserved(0) [12..15] width BE [16..19] height BE [20..23] dpi BE [24..31] reserved(0)
10// PAGE DATA: PWG/URF PackBits RLE (nx_pwg_rle), pixels top-to-bottom, left-to-right.
11//
12// HONEST NOTE: the RLE is spec-PROVEN (CUPS spec worked example); the URF header is spec-GROUNDED
13// (reverse-engineered) -- the real printer is the final oracle (live submit = the next rung).
14// NEVER-BRICK (#26): pure builder; no syscalls. Sovereign (imports only nx_pwg_rle.nx).
15// genealogy_id: project-printer-management-ipp-sclass-2026-06-20 ; license_tier: ORIGINAL
16
17import "nx_pwg_rle.nx"
18
19const NX_URF_CS_SGRAY: i64 = 0
20const NX_URF_CS_SRGB: i64 = 1
21const NX_URF_DUP_NONE: i64 = 0
22const NX_URF_DUP_SHORT: i64 = 1
23const NX_URF_DUP_LONG: i64 = 2 // long-edge duplex -- the paper-waste fix
24const NX_URF_Q_DEFAULT: i64 = 0
25const NX_URF_Q_DRAFT: i64 = 3 // draft = the toner-saving mode
26const NX_URF_Q_NORMAL: i64 = 4
27const NX_URF_Q_HIGH: i64 = 5
28
29func nx_urf_be32(out: *u8, off: i64, v: i64) -> i64 {
30 out[off] = ((v >> 24) & 0xff) as u8
31 out[off + 1] = ((v >> 16) & 0xff) as u8
32 out[off + 2] = ((v >> 8) & 0xff) as u8
33 out[off + 3] = (v & 0xff) as u8
34 return off + 4
35}
36
37// 12-byte URF file header. Returns 12.
38func nx_urf_file_header(out: *u8, pages: i64) -> i64 {
39 out[0] = 0x55 as u8 // U
40 out[1] = 0x4E as u8 // N
41 out[2] = 0x49 as u8 // I
42 out[3] = 0x52 as u8 // R
43 out[4] = 0x41 as u8 // A
44 out[5] = 0x53 as u8 // S
45 out[6] = 0x54 as u8 // T
46 out[7] = 0x00 as u8 // \0
47 nx_urf_be32(out, 8, pages)
48 return 12
49}
50
51// 32-byte page header at out[off..]. Returns off+32.
52func nx_urf_page_header(out: *u8, off: i64, bpp: i64, colorspace: i64, duplex: i64,
53 quality: i64, width: i64, height: i64, dpi: i64) -> i64 {
54 var o: i64 = off
55 out[o] = bpp as u8; o = o + 1
56 out[o] = colorspace as u8; o = o + 1
57 out[o] = duplex as u8; o = o + 1
58 out[o] = quality as u8; o = o + 1
59 out[o] = 0 as u8; o = o + 1 // media type = auto
60 out[o] = 0 as u8; o = o + 1 // media position = auto
61 var r: i64 = 0
62 while r < 6 { out[o] = 0 as u8; o = o + 1; r = r + 1 }
63 o = nx_urf_be32(out, o, width)
64 o = nx_urf_be32(out, o, height)
65 o = nx_urf_be32(out, o, dpi)
66 var r2: i64 = 0
67 while r2 < 8 { out[o] = 0 as u8; o = o + 1; r2 = r2 + 1 }
68 return o
69}
70
71// Encode a complete single-page 8-bit GRAYSCALE URF document (bitmap = width*height bytes) into out.
72// Returns total byte length. duplex/quality let the caller fix the paper/toner waste at the document level.
73func nx_urf_encode_gray_page(out: *u8, bitmap: *u8, width: i64, height: i64,
74 dpi: i64, duplex: i64, quality: i64) -> i64 {
75 var off: i64 = nx_urf_file_header(out, 1)
76 off = nx_urf_page_header(out, off, 8, NX_URF_CS_SGRAY, duplex, quality, width, height, dpi)
77 let rlen: i64 = nx_rle_encode_page(bitmap, width, height, 1, ((out as i64) + off) as *u8)
78 return off + rlen
79}