1 ! Copyright (C) 2009 Marc Fauconneau.
\r
2 ! See http://factorcode.org/license.txt for BSD license.
\r
3 USING: accessors arrays assocs byte-arrays
\r
4 byte-vectors combinators constructors fry grouping hashtables
\r
5 compression.huffman images io.binary kernel locals
\r
6 math math.bitwise math.order math.ranges multiline sequences
\r
8 IN: compression.inflate
\r
10 QUALIFIED-WITH: bitstreams bs
\r
14 : enum>seq ( assoc -- seq )
\r
15 dup keys [ ] [ max ] map-reduce 1 + f <array>
\r
16 [ '[ swap _ set-nth ] assoc-each ] keep ;
\r
18 ERROR: zlib-unimplemented ;
\r
19 ERROR: bad-zlib-data ;
\r
20 ERROR: bad-zlib-header ;
\r
22 :: check-zlib-header ( data -- )
\r
23 16 data bs:peek 2 >le be> 31 mod ! checksum
\r
25 4 data bs:read 8 assert= ! compression method: deflate
\r
26 4 data bs:read ! log2(max length)-8, 32K max
\r
27 7 <= [ bad-zlib-header ] unless
\r
28 5 data bs:seek ! drop check bits
\r
29 1 data bs:read 0 assert= ! dictionnary - not allowed in png
\r
30 2 data bs:seek ! compression level; ignore
\r
33 :: default-table ( -- table )
\r
34 0 <hashtable> :> table
\r
35 0 143 [a,b] 280 287 [a,b] append 8 table set-at
\r
36 144 255 [a,b] >array 9 table set-at
\r
37 256 279 [a,b] >array 7 table set-at
\r
38 table enum>seq 1 tail ;
\r
40 CONSTANT: clen-shuffle { 16 17 18 0 8 7 9 6 10 5 11 4 12 3 13 2 14 1 15 }
\r
42 : get-table ( values size -- table )
\r
43 16 f <array> clone <enum>
\r
44 [ '[ _ push-at ] 2each ] keep seq>> 1 tail [ natural-sort ] map ;
\r
46 :: decode-huffman-tables ( bitstream -- tables )
\r
47 5 bitstream bs:read 257 +
\r
48 5 bitstream bs:read 1 +
\r
49 4 bitstream bs:read 4 +
\r
50 clen-shuffle swap head
\r
51 dup [ drop 3 bitstream bs:read ] map
\r
53 bitstream swap <huffman-decoder>
\r
54 [ 2dup + ] dip swap :> k!
\r
58 { [ dup 16 = ] [ 2 bitstream bs:read 3 + 2array ] }
\r
59 { [ dup 17 = ] [ 3 bitstream bs:read 3 + 2array ] }
\r
60 { [ dup 18 = ] [ 7 bitstream bs:read 11 + 2array ] }
\r
63 dup array? [ dup second ] [ 1 ] if
\r
66 [ ] produce swap suffix
\r
67 { } [ dup array? [ dup first 16 = ] [ f ] if [ [ unclip-last ] [ second 1+ swap <repetition> append ] bi* ] [ suffix ] if ] reduce
\r
68 [ dup array? [ second 0 <repetition> ] [ 1array ] if ] map concat
\r
69 nip swap cut 2array [ [ length>> [0,b) ] [ ] bi get-table ] map ;
\r
71 CONSTANT: length-table
\r
81 CONSTANT: dist-table
\r
88 4097 6145 8193 12289
\r
91 : nth* ( n seq -- elt )
\r
92 [ length 1- swap - ] [ nth ] bi ;
\r
94 :: inflate-lz77 ( seq -- bytes )
\r
95 1000 <byte-vector> :> bytes
\r
99 [ first2 '[ _ 1- bytes nth* bytes push ] times ]
\r
104 :: inflate-dynamic ( bitstream -- bytes )
\r
105 bitstream decode-huffman-tables
\r
106 bitstream '[ _ swap <huffman-decoder> ] map :> tables
\r
108 tables first read1-huff2
\r
116 dup 261 - 4 /i dup 5 >
\r
117 [ bad-zlib-data ] when
\r
118 bitstream bs:read 2array
\r
122 ! 5 bitstream read-bits ! distance
\r
123 tables second read1-huff2
\r
126 dup 2 - 2 /i dup 13 >
\r
127 [ bad-zlib-data ] when
\r
128 bitstream bs:read 2array
\r
141 dup array? [ first2 ] [ 0 ] if
\r
142 [ 257 - length-table nth ] [ + ] bi*
\r
145 dup array? [ first2 ] [ 0 ] if
\r
146 [ dist-table nth ] [ + ] bi*
\r
152 : inflate-raw ( bitstream -- bytes ) zlib-unimplemented ;
\r
153 : inflate-static ( bitstream -- bytes ) zlib-unimplemented ;
\r
155 :: inflate-loop ( bitstream -- bytes )
\r
156 [ 1 bitstream bs:read 0 = ]
\r
159 2 bitstream bs:read ! B
\r
161 { 0 [ inflate-raw ] }
\r
162 { 1 [ inflate-static ] }
\r
163 { 2 [ inflate-dynamic ] }
\r
164 { 3 [ bad-zlib-data f ] }
\r
168 [ produce ] keep call suffix concat ;
\r
170 ! [ produce ] keep dip swap suffix
\r
172 :: paeth ( a b c -- p )
\r
173 a b + c - { a b c } [ [ - abs ] keep 2array ] with map
\r
174 sort-keys first second ;
\r
176 :: png-unfilter-line ( prev curr filter -- curr' )
\r
178 prev 3 tail-slice :> b
\r
180 curr 3 tail-slice :> x
\r
185 { 1 [ [| n | n x nth n a nth + 256 wrap n x set-nth ] each ] }
\r
186 { 2 [ [| n | n x nth n b nth + 256 wrap n x set-nth ] each ] }
\r
187 { 3 [ [| n | n x nth n a nth n b nth + 2/ + 256 wrap n x set-nth ] each ] }
\r
188 { 4 [ [| n | n x nth n a nth n b nth n c nth paeth + 256 wrap n x set-nth ] each ] }
\r
195 ! for debug -- shows residual values
\r
196 : reverse-png-filter' ( lines -- filtered )
\r
197 [ first ] [ 1 tail ] [ map ] bi-curry@ bi nip
\r
198 concat [ 128 + 256 wrap ] map ;
\r
200 : reverse-png-filter ( lines -- filtered )
\r
201 dup first [ 0 ] replicate prefix
\r
202 [ { 0 0 } prepend ] map
\r
204 first2 dup [ third ] [ 0 2 rot set-nth ] bi png-unfilter-line
\r
207 : zlib-inflate ( bytes -- bytes )
\r
208 bs:<lsb0-bit-reader>
\r
209 [ check-zlib-header ]
\r
210 [ inflate-loop ] bi
\r