]> gitweb.factorcode.org Git - factor.git/blob - extra/images/gif/gif.factor
use radix literals
[factor.git] / extra / images / gif / gif.factor
1 ! Copyrigt (C) 2009 Doug Coleman, Keith Lazuka
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays combinators compression.lzw
4 constructors destructors grouping images images.loader io
5 io.binary io.buffers io.encodings.string io.encodings.utf8
6 kernel make math math.bitwise namespaces sequences ;
7 IN: images.gif
8
9 SINGLETON: gif-image
10 "gif" gif-image register-image-class
11
12 TUPLE: loading-gif
13 loading?
14 magic
15 width height
16 flags
17 background-color
18 default-aspect-ratio
19 global-color-table
20 graphic-control-extensions
21 application-extensions
22 plain-text-extensions
23 comment-extensions
24
25 image-descriptor
26 local-color-table
27 compressed-bytes ;
28
29 TUPLE: gif-frame
30 image-descriptor
31 local-color-table ;
32
33 ERROR: unsupported-gif-format magic ;
34 ERROR: unknown-extension n ;
35 ERROR: gif-unexpected-eof ;
36
37 TUPLE: graphics-control-extension
38 flags delay-time transparent-color-index ;
39
40 TUPLE: image-descriptor
41 left top width height flags first-code-size ;
42
43 TUPLE: plain-text-extension
44 introducer label block-size text-grid-left text-grid-top text-grid-width
45 text-grid-height cell-width cell-height
46 text-fg-color-index text-bg-color-index plain-text-data ;
47
48 TUPLE: application-extension
49 introducer label block-size identifier authentication-code
50 application-data ;
51
52 TUPLE: comment-extension
53 introducer label comment-data ;
54
55 TUPLE: trailer byte ;
56 CONSTRUCTOR: trailer ( byte -- obj ) ;
57
58 CONSTANT: image-descriptor 0x2c
59 ! Extensions
60 CONSTANT: extension-identifier 0x21
61 CONSTANT: plain-text-extension 0x01
62 CONSTANT: graphic-control-extension 0xf9
63 CONSTANT: comment-extension 0xfe
64 CONSTANT: application-extension 0xff
65 CONSTANT: trailer 0x3b
66 CONSTANT: graphic-control-extension-block-size 0x04
67 CONSTANT: block-terminator 0x00
68
69 : <loading-gif> ( -- loading-gif )
70     \ loading-gif new
71         V{ } clone >>graphic-control-extensions
72         V{ } clone >>application-extensions
73         V{ } clone >>plain-text-extensions
74         V{ } clone >>comment-extensions
75         t >>loading? ;
76
77 : (read-sub-blocks) ( -- )
78     read1 [ read , (read-sub-blocks) ] unless-zero ;
79
80 : read-sub-blocks ( -- bytes )
81     [ (read-sub-blocks) ] { } make B{ } concat-as ;
82
83 : read-image-descriptor ( -- image-descriptor )
84     \ image-descriptor new
85         2 read le> >>left
86         2 read le> >>top
87         2 read le> >>width
88         2 read le> >>height
89         1 read le> >>flags
90         1 read le> 1 + >>first-code-size ;
91
92 : read-graphic-control-extension ( -- graphic-control-extension )
93     \ graphics-control-extension new
94         1 read le> graphic-control-extension-block-size assert=
95         1 read le> >>flags
96         2 read le> >>delay-time
97         1 read le> >>transparent-color-index
98         1 read le> block-terminator assert= ;
99
100 : read-plain-text-extension ( -- plain-text-extension )
101     \ plain-text-extension new
102         1 read le> >>block-size
103         2 read le> >>text-grid-left
104         2 read le> >>text-grid-top
105         2 read le> >>text-grid-width
106         2 read le> >>text-grid-height
107         1 read le> >>cell-width
108         1 read le> >>cell-height
109         1 read le> >>text-fg-color-index
110         1 read le> >>text-bg-color-index
111         read-sub-blocks >>plain-text-data ;
112
113 : read-comment-extension ( -- comment-extension )
114     \ comment-extension new
115         read-sub-blocks >>comment-data ;
116     
117 : read-application-extension ( -- read-application-extension )
118    \ application-extension new
119        1 read le> >>block-size
120        8 read utf8 decode >>identifier
121        3 read >>authentication-code
122        read-sub-blocks >>application-data ;
123
124 : read-gif-header ( loading-gif -- loading-gif )
125     6 read utf8 decode >>magic ;
126
127 ERROR: unimplemented message ;
128 : read-GIF87a ( loading-gif -- loading-gif )
129     "GIF87a" unimplemented ;
130
131 : read-logical-screen-descriptor ( loading-gif -- loading-gif )
132     2 read le> >>width
133     2 read le> >>height
134     1 read le> >>flags
135     1 read le> >>background-color
136     1 read le> >>default-aspect-ratio ;
137
138 : color-table? ( image -- ? ) flags>> 7 bit? ; inline
139 : interlaced? ( image -- ? ) flags>> 6 bit? ; inline
140 : sort? ( image -- ? ) flags>> 5 bit? ; inline
141 : color-table-size ( image -- ? ) flags>> 3 bits 1 + 2^ 3 * ; inline
142 : transparency? ( image -- ? )
143     graphic-control-extensions>>
144     [ f ] [ first flags>> 0 bit? ] if-empty ; inline
145
146 : color-resolution ( image -- ? ) flags>> -4 shift 3 bits ; inline
147
148 : read-global-color-table ( loading-gif -- loading-gif )
149     dup color-table? [
150         dup color-table-size read 3 group >>global-color-table
151     ] when ;
152
153 : maybe-read-local-color-table ( loading-gif -- loading-gif )
154     dup image-descriptor>> color-table? [
155         dup color-table-size read >>local-color-table
156     ] when ;
157
158 : read-image-data ( loading-gif -- loading-gif )
159     read-sub-blocks >>compressed-bytes ;
160
161 : read-table-based-image ( loading-gif -- loading-gif )
162     read-image-descriptor >>image-descriptor
163     maybe-read-local-color-table
164     read-image-data ;
165
166 : read-graphic-rendering-block ( loading-gif -- loading-gif )
167     read-table-based-image ;
168
169 : read-extension ( loading-gif -- loading-gif )
170     read1 {
171         { plain-text-extension [
172             read-plain-text-extension over plain-text-extensions>> push
173         ] }
174
175         { graphic-control-extension [
176             read-graphic-control-extension
177             over graphic-control-extensions>> push
178         ] }
179         { comment-extension [
180             read-comment-extension over comment-extensions>> push
181         ] }
182         { application-extension [
183             read-application-extension over application-extensions>> push
184         ] }
185         { f [ gif-unexpected-eof ] }
186         [ unknown-extension ]
187     } case ;
188
189 ERROR: unhandled-data byte ;
190
191 : read-data ( loading-gif -- loading-gif )
192     read1 {
193         { extension-identifier [ read-extension ] }
194         { graphic-control-extension [
195             read-graphic-control-extension
196             over graphic-control-extensions>> push
197         ] }
198         { image-descriptor [ read-table-based-image ] }
199         { trailer [ f >>loading? ] }
200         [ unhandled-data ]
201     } case ;
202
203 : read-GIF89a ( loading-gif -- loading-gif )
204     read-logical-screen-descriptor
205     read-global-color-table
206     [ read-data dup loading?>> ] loop ;
207
208 : load-gif ( stream -- loading-gif )
209     [
210         <loading-gif>
211         read-gif-header dup magic>> {
212             { "GIF87a" [ read-GIF87a ] }
213             { "GIF89a" [ read-GIF89a ] }
214             [ unsupported-gif-format ]
215         } case
216     ] with-input-stream ;
217
218 : decompress ( loading-gif -- indexes )
219     [ compressed-bytes>> ]
220     [ image-descriptor>> first-code-size>> ] bi
221     gif-lzw-uncompress ;
222
223 : colorize ( index palette transparent-index/f -- seq )
224     pick = [ 2drop B{ 0 0 0 0 } ] [ nth 255 suffix ] if ;
225
226 : apply-palette ( indexes palette transparent-index/f -- bitmap )
227     [ colorize ] 2curry V{ } map-as concat ;
228
229 : dimensions ( loading-gif -- dim )
230     [ image-descriptor>> width>> ] [ image-descriptor>> height>> ] bi 2array ;
231
232 : ?transparent-color-index ( loading-gif -- index/f )
233     dup transparency?
234     [ graphic-control-extensions>> first transparent-color-index>> ]
235     [ drop f ] if ;
236
237 : gif>image ( loading-gif -- image )
238     [ <image> ] dip
239     [ dimensions >>dim ]
240     [ drop RGBA >>component-order ubyte-components >>component-type ]
241     [
242         [ decompress ] [ global-color-table>> ] [ ?transparent-color-index ] tri
243         apply-palette >>bitmap
244     ] tri ;
245
246 ERROR: loading-gif-error gif-image ;
247
248 : ensure-loaded ( gif-image -- gif-image )
249     dup loading?>> [ loading-gif-error ] when ;
250
251 M: gif-image stream>image ( path gif-image -- image )
252     drop load-gif ensure-loaded gif>image ;