nx_tiff_decode.nx source
↩ module page · 195 lines · 7661 B
1// nx_tiff_decode.nx -- sovereign baseline TIFF READER (the 1990s scan/fax/print interchange format;
2// the tree had a sniffer claim and NO decoder). tiff_decode_rgb(raw,n,out_wh) -> w*h*3 packed RGB,
3// top-down. Covers: both byte orders (II little / MM big endian), first IFD, strip organisation
4// (StripOffsets/StripByteCounts/RowsPerStrip), Compression 1 (none) + 32773 (PackBits), Photometric
5// 0 (white-is-zero gray, inverted here), 1 (black-is-zero gray), 2 (RGB 8-bit), 3 (palette via
6// ColorMap's 16-bit channels >>8), BitsPerSample 8 (gray/RGB/palette) + 1 (bilevel gray).
7// REFUSED (0 return, never a wrong image): LZW(5)/CCITT(2-4)/JPEG-in-TIFF(6,7)/Deflate(8), tiles,
8// planar config 2, 16-bit samples. license_tier: ORIGINAL
9import "nx_syscalls.nx"
10const K_MAGIC_32767: i64 = 32767
11const K_MAGIC_32773: i64 = 32773
12
13// endian-aware readers: le==1 little, else big
14func tf_u16(b: *u8, o: i64, le: i64) -> i64 {
15 if le==1 { return (b[o] as i64) | ((b[o+1] as i64)<<8) }
16 return ((b[o] as i64)<<8) | (b[o+1] as i64)
17}
18func tf_u32(b: *u8, o: i64, le: i64) -> i64 {
19 if le==1 { return (b[o] as i64) | ((b[o+1] as i64)<<8) | ((b[o+2] as i64)<<16) | ((b[o+3] as i64)<<24) }
20 return ((b[o] as i64)<<24) | ((b[o+1] as i64)<<16) | ((b[o+2] as i64)<<8) | (b[o+3] as i64)
21}
22
23// TIFF type byte widths: 1 BYTE, 2 ASCII, 3 SHORT, 4 LONG (others unsupported here)
24func tf_type_w(t: i64) -> i64 {
25 if t==1 { return 1 }
26 if t==2 { return 1 }
27 if t==3 { return 2 }
28 if t==4 { return 4 }
29 return 0
30}
31
32// find tag in the IFD; returns entry offset or -1
33func tf_find(raw: *u8, n: i64, ifd: i64, le: i64, tag: i64) -> i64 {
34 if ifd+2>n { return 0-1 }
35 let cnt: i64 = tf_u16(raw, ifd, le)
36 var i: i64=0
37 while i<cnt {
38 let eo: i64 = ifd+2+i*12
39 if eo+12>n { return 0-1 }
40 if tf_u16(raw, eo, le)==tag { return eo }
41 i=i+1
42 }
43 return 0-1
44}
45
46// value #k of a tag entry (SHORT/LONG/BYTE); inline when it fits 4 bytes, else via offset
47func tf_val(raw: *u8, n: i64, eo: i64, le: i64, k: i64) -> i64 {
48 let ty: i64 = tf_u16(raw, eo+2, le)
49 let cnt: i64 = tf_u32(raw, eo+4, le)
50 let tw: i64 = tf_type_w(ty)
51 if tw==0 { return 0-1 }
52 if k>=cnt { return 0-1 }
53 var base: i64 = eo+8
54 if cnt*tw > 4 { base = tf_u32(raw, eo+8, le) }
55 let vo: i64 = base + k*tw
56 if vo+tw>n { return 0-1 }
57 if tw==1 { return raw[vo] as i64 }
58 if tw==2 { return tf_u16(raw, vo, le) }
59 return tf_u32(raw, vo, le)
60}
61
62// first value convenience; def when the tag is absent
63func tf_val1(raw: *u8, n: i64, ifd: i64, le: i64, tag: i64, def: i64) -> i64 {
64 let eo: i64 = tf_find(raw, n, ifd, le, tag)
65 if eo<0 { return def }
66 let v: i64 = tf_val(raw, n, eo, le, 0)
67 if v<0 { return def }
68 return v
69}
70
71// PackBits (Apple/TIFF 32773): n in 0..127 -> copy n+1 literal; n in -127..-1 (129..255
72// unsigned) -> repeat next byte 1-n times; 128 (-128) is a no-op.
73func tf_packbits(src: *u8, slen: i64, dst: *u8, dcap: i64) -> i64 {
74 var sp: i64=0
75 var dp: i64=0
76 while sp<slen {
77 let c: i64 = src[sp] as i64
78 sp=sp+1
79 if c<128 {
80 var k: i64=0
81 while k<=c { if sp<slen { if dp<dcap { dst[dp]=src[sp]; dp=dp+1 } sp=sp+1 } k=k+1 }
82 } else { if c>128 {
83 let rep: i64 = 257-c
84 if sp<slen {
85 let v: u8 = src[sp]
86 sp=sp+1
87 var k2: i64=0
88 while k2<rep { if dp<dcap { dst[dp]=v; dp=dp+1 } k2=k2+1 }
89 }
90 } }
91 }
92 return dp
93}
94
95func tiff_decode_rgb(raw: *u8, n: i64, out_wh: *i64) -> *u8 {
96 if n<8 { return 0 as *u8 }
97 var le: i64 = 0-1
98 if (raw[0] as i64)==0x49 { if (raw[1] as i64)==0x49 { if (raw[2] as i64)==0x2A { if (raw[3] as i64)==0x00 { le=1 } } } }
99 if (raw[0] as i64)==0x4D { if (raw[1] as i64)==0x4D { if (raw[2] as i64)==0x00 { if (raw[3] as i64)==0x2A { le=0 } } } }
100 if le<0 { return 0 as *u8 }
101 let ifd: i64 = tf_u32(raw, 4, le)
102 if ifd+2>n { return 0 as *u8 }
103 let w: i64 = tf_val1(raw, n, ifd, le, 256, 0)
104 let h: i64 = tf_val1(raw, n, ifd, le, 257, 0)
105 if w<=0 { return 0 as *u8 }
106 if h<=0 { return 0 as *u8 }
107 if w>K_MAGIC_32767 { return 0 as *u8 }
108 if h>K_MAGIC_32767 { return 0 as *u8 }
109 let comp: i64 = tf_val1(raw, n, ifd, le, 259, 1)
110 if comp!=1 { if comp!=K_MAGIC_32773 { return 0 as *u8 } }
111 let photo: i64 = tf_val1(raw, n, ifd, le, 262, 1)
112 let spp: i64 = tf_val1(raw, n, ifd, le, 277, 1)
113 let bps: i64 = tf_val1(raw, n, ifd, le, 258, 1)
114 let planar: i64 = tf_val1(raw, n, ifd, le, 284, 1)
115 if planar!=1 { return 0 as *u8 }
116 var mode: i64 = 0-1 // 0 gray8, 1 rgb8, 2 pal8, 3 gray1
117 if photo==2 { if spp==3 { if bps==8 { mode=1 } } }
118 if photo==0 { if spp==1 { if bps==8 { mode=0 } if bps==1 { mode=3 } } }
119 if photo==1 { if spp==1 { if bps==8 { mode=0 } if bps==1 { mode=3 } } }
120 if photo==3 { if spp==1 { if bps==8 { mode=2 } } }
121 if mode<0 { return 0 as *u8 }
122 let so_e: i64 = tf_find(raw, n, ifd, le, 273)
123 let sc_e: i64 = tf_find(raw, n, ifd, le, 279)
124 if so_e<0 { return 0 as *u8 }
125 if sc_e<0 { return 0 as *u8 }
126 var rps: i64 = tf_val1(raw, n, ifd, le, 278, h)
127 if rps<=0 { rps=h }
128 let nstrips: i64 = (h+rps-1)/rps
129 // decompressed image data: spp samples per pixel (bilevel unpacked below)
130 var rowbytes: i64 = w*spp
131 if mode==3 { rowbytes=(w+7)/8 }
132 let dcap: i64 = rowbytes*h+16
133 let data: *u8 = sys_mmap(dcap)
134 var written: i64 = 0
135 var s: i64=0
136 while s<nstrips {
137 let soff: i64 = tf_val(raw, n, so_e, le, s)
138 let slen: i64 = tf_val(raw, n, sc_e, le, s)
139 if soff<0 { return 0 as *u8 }
140 if slen<0 { return 0 as *u8 }
141 if soff+slen>n { return 0 as *u8 }
142 if comp==1 {
143 var k: i64=0
144 while k<slen { if written<dcap { data[written]=raw[soff+k]; written=written+1 } k=k+1 }
145 } else {
146 written = written + tf_packbits((raw as i64 + soff) as *u8, slen, (data as i64 + written) as *u8, dcap-written)
147 }
148 s=s+1
149 }
150 if written < rowbytes*h { return 0 as *u8 }
151 // ColorMap for palette mode: 3 planes of 2^bps 16-bit values (R plane, G plane, B plane)
152 var cm_e: i64 = 0-1
153 if mode==2 {
154 cm_e = tf_find(raw, n, ifd, le, 320)
155 if cm_e<0 { return 0 as *u8 }
156 }
157 let rgb: *u8 = sys_mmap(w*h*3+16)
158 var y: i64=0
159 while y<h {
160 var x: i64=0
161 while x<w {
162 var rv: i64=0
163 var gv: i64=0
164 var bv: i64=0
165 if mode==1 {
166 let po: i64=(y*w+x)*3
167 rv=data[po] as i64; gv=data[po+1] as i64; bv=data[po+2] as i64
168 } else { if mode==0 {
169 var g8: i64=data[y*w+x] as i64
170 if photo==0 { g8=255-g8 }
171 rv=g8; gv=g8; bv=g8
172 } else { if mode==3 {
173 let bb: i64=data[y*rowbytes+x/8] as i64
174 var bit: i64=(bb>>(7-(x%8)))&1
175 if photo==0 { bit=1-bit }
176 rv=bit*255; gv=bit*255; bv=bit*255
177 } else {
178 let ci: i64=data[y*w+x] as i64
179 rv=tf_val(raw, n, cm_e, le, ci)>>8
180 gv=tf_val(raw, n, cm_e, le, 256+ci)>>8
181 bv=tf_val(raw, n, cm_e, le, 512+ci)>>8
182 if rv<0 { rv=0 }
183 if gv<0 { gv=0 }
184 if bv<0 { bv=0 }
185 } } }
186 rgb[(y*w+x)*3] =rv as u8
187 rgb[(y*w+x)*3+1]=gv as u8
188 rgb[(y*w+x)*3+2]=bv as u8
189 x=x+1
190 }
191 y=y+1
192 }
193 out_wh[0]=w; out_wh[1]=h
194 return rgb
195}