1 ! Copyright (C) 2009 Marc Fauconneau.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays assocs byte-arrays
4 byte-vectors combinators fry grouping hashtables
5 compression.huffman images io.binary kernel locals
6 math math.bitwise math.order math.ranges multiline sequences
8 IN: compression.inflate
10 QUALIFIED-WITH: bitstreams bs
14 : enum>seq ( assoc -- seq )
15 dup keys [ ] [ max ] map-reduce 1 + f <array>
16 [ '[ swap _ set-nth ] assoc-each ] keep ;
18 ERROR: zlib-unimplemented ;
19 ERROR: bad-zlib-data ;
20 ERROR: bad-zlib-header ;
22 :: check-zlib-header ( data -- )
23 16 data bs:peek 2 >le be> 31 mod ! checksum
25 4 data bs:read 8 assert= ! compression method: deflate
26 4 data bs:read ! log2(max length)-8, 32K max
27 7 <= [ bad-zlib-header ] unless
28 5 data bs:seek ! drop check bits
29 1 data bs:read 0 assert= ! dictionnary - not allowed in png
30 2 data bs:seek ! compression level; ignore
33 :: default-table ( -- table )
34 0 <hashtable> :> table
35 0 143 [a,b] 280 287 [a,b] append 8 table set-at
36 144 255 [a,b] >array 9 table set-at
37 256 279 [a,b] >array 7 table set-at
38 table enum>seq 1 tail ;
40 CONSTANT: clen-shuffle { 16 17 18 0 8 7 9 6 10 5 11 4 12 3 13 2 14 1 15 }
42 : get-table ( values size -- table )
43 16 f <array> clone <enum>
44 [ '[ _ push-at ] 2each ] keep seq>> 1 tail [ natural-sort ] map ;
46 :: decode-huffman-tables ( bitstream -- tables )
47 5 bitstream bs:read 257 +
48 5 bitstream bs:read 1 +
49 4 bitstream bs:read 4 +
50 clen-shuffle swap head
51 dup [ drop 3 bitstream bs:read ] map
53 bitstream swap <huffman-decoder>
54 [ 2dup + ] dip swap :> k!
58 { [ dup 16 = ] [ 2 bitstream bs:read 3 + 2array ] }
59 { [ dup 17 = ] [ 3 bitstream bs:read 3 + 2array ] }
60 { [ dup 18 = ] [ 7 bitstream bs:read 11 + 2array ] }
63 dup array? [ dup second ] [ 1 ] if
66 [ ] produce swap suffix
67 { } [ dup array? [ dup first 16 = ] [ f ] if [ [ unclip-last ] [ second 1 + swap <repetition> append ] bi* ] [ suffix ] if ] reduce
68 [ dup array? [ second 0 <repetition> ] [ 1array ] if ] map concat
69 nip swap cut 2array [ [ length>> [0,b) ] [ ] bi get-table ] map ;
71 CONSTANT: length-table
93 : nth* ( n seq -- elt )
94 [ length 1 - swap - ] [ nth ] bi ;
96 :: inflate-lz77 ( seq -- bytes )
97 1000 <byte-vector> :> bytes
101 [ first2 '[ _ 1 - bytes nth* bytes push ] times ]
106 :: inflate-dynamic ( bitstream -- bytes )
107 bitstream decode-huffman-tables
108 bitstream '[ _ swap <huffman-decoder> ] map :> tables
110 tables first read1-huff2
118 dup 261 - 4 /i dup 5 >
119 [ bad-zlib-data ] when
120 bitstream bs:read 2array
124 ! 5 bitstream read-bits ! distance
125 tables second read1-huff2
128 dup 2 - 2 /i dup 13 >
129 [ bad-zlib-data ] when
130 bitstream bs:read 2array
143 dup array? [ first2 ] [ 0 ] if
144 [ 257 - length-table nth ] [ + ] bi*
147 dup array? [ first2 ] [ 0 ] if
148 [ dist-table nth ] [ + ] bi*
154 :: inflate-raw ( bitstream -- bytes )
156 16 bitstream bs:read :> len
157 16 bitstream bs:read :> nlen
158 len nlen + 16 >signed -1 assert= ! len + ~len = -1
160 bitstream byte-pos>> len +
161 bitstream bytes>> <slice>
162 len 8 * bitstream bs:seek ;
164 : inflate-static ( bitstream -- bytes ) zlib-unimplemented ;
166 :: inflate-loop ( bitstream -- bytes )
167 [ 1 bitstream bs:read 0 = ]
172 { 0 [ inflate-raw ] }
173 { 1 [ inflate-static ] }
174 { 2 [ inflate-dynamic ] }
175 { 3 [ bad-zlib-data f ] }
179 [ produce ] keep call suffix concat ;
181 ! [ produce ] keep dip swap suffix
183 :: paeth ( a b c -- p )
184 a b + c - { a b c } [ [ - abs ] keep 2array ] with map
185 sort-keys first second ;
187 :: png-unfilter-line ( prev curr filter -- curr' )
189 prev 3 tail-slice :> b
191 curr 3 tail-slice :> x
196 { 1 [ [| n | n x nth n a nth + 256 wrap n x set-nth ] each ] }
197 { 2 [ [| n | n x nth n b nth + 256 wrap n x set-nth ] each ] }
198 { 3 [ [| n | n x nth n a nth n b nth + 2/ + 256 wrap n x set-nth ] each ] }
199 { 4 [ [| n | n x nth n a nth n b nth n c nth paeth + 256 wrap n x set-nth ] each ] }
206 : reverse-png-filter' ( lines -- byte-array )
207 [ first ] [ 1 tail ] [ map ] bi-curry@ bi nip
208 concat [ 128 + ] B{ } map-as ;
210 : reverse-png-filter ( lines -- byte-array )
211 dup first [ 0 ] replicate prefix
212 [ { 0 0 } prepend ] map
214 first2 dup [ third ] [ 0 2 rot set-nth ] bi png-unfilter-line
215 ] map B{ } concat-as ;
217 : zlib-inflate ( bytes -- bytes )
219 [ check-zlib-header ] [ inflate-loop ] bi