code wiki / (root) / nx_tiff_decode.nx

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}