]> gitweb.factorcode.org Git - factor.git/blob - extra/images/gif/gif.factor
Merge branch 'irc-fix' of git://tiodante.com/git/factor
[factor.git] / extra / images / gif / gif.factor
1 ! Copyrigt (C) 2009 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays combinators constructors destructors
4 images images.loader io io.binary io.buffers
5 io.encodings.binary io.encodings.string io.encodings.utf8
6 io.files io.files.info io.ports io.streams.limited kernel make
7 math math.bitwise math.functions multiline namespaces
8 prettyprint sequences ;
9 IN: images.gif
10
11 SINGLETON: gif-image
12 "gif" gif-image register-image-class
13
14 TUPLE: loading-gif
15 loading?
16 magic
17 width height
18 flags
19 background-color
20 default-aspect-ratio
21 global-color-table
22 graphic-control-extensions
23 application-extensions
24 plain-text-extensions
25 comment-extensions
26
27 image-descriptor
28 local-color-table
29 compressed-bytes ;
30
31 TUPLE: gif-frame
32 image-descriptor
33 local-color-table ;
34
35 ERROR: unsupported-gif-format magic ;
36 ERROR: unknown-extension n ;
37 ERROR: gif-unexpected-eof ;
38
39 TUPLE: graphics-control-extension
40 label block-size raw-data
41 packed delay-time color-index
42 block-terminator ;
43
44 TUPLE: image-descriptor
45 separator left top width height flags ;
46
47 TUPLE: plain-text-extension
48 introducer label block-size text-grid-left text-grid-top text-grid-width
49 text-grid-height cell-width cell-height
50 text-fg-color-index text-bg-color-index plain-text-data ;
51
52 TUPLE: application-extension
53 introducer label block-size identifier authentication-code
54 application-data ;
55
56 TUPLE: comment-extension
57 introducer label comment-data ;
58
59 TUPLE: trailer byte ;
60 CONSTRUCTOR: trailer ( byte -- obj ) ;
61
62 CONSTANT: image-descriptor HEX: 2c
63 ! Extensions
64 CONSTANT: extension-identifier HEX: 21
65 CONSTANT: plain-text-extension HEX: 01
66 CONSTANT: graphic-control-extension HEX: f9
67 CONSTANT: comment-extension HEX: fe
68 CONSTANT: application-extension HEX: ff
69 CONSTANT: trailer HEX: 3b
70
71 : <loading-gif> ( -- loading-gif )
72     \ loading-gif new
73         V{ } clone >>graphic-control-extensions
74         V{ } clone >>application-extensions
75         V{ } clone >>plain-text-extensions
76         V{ } clone >>comment-extensions
77         t >>loading? ;
78
79 GENERIC: stream-peek1 ( stream -- byte )
80
81 M: input-port stream-peek1
82     dup check-disposed dup wait-to-read
83     [ drop f ] [ buffer>> buffer-peek ] if ; inline
84
85 : peek1 ( -- byte ) input-stream get stream-peek1 ;
86
87 : (read-sub-blocks) ( -- )
88     read1 [ read , (read-sub-blocks) ] unless-zero ;
89
90 : read-sub-blocks ( -- bytes )
91     [ (read-sub-blocks) ] { } make B{ } concat-as ;
92
93 : read-image-descriptor ( -- image-descriptor )
94     \ image-descriptor new
95         1 read le> >>separator
96         2 read le> >>left
97         2 read le> >>top
98         2 read le> >>width
99         2 read le> >>height
100         1 read le> >>flags ;
101
102 : read-graphic-control-extension ( -- graphic-control-extension )
103     \ graphics-control-extension new
104         1 read le> [ >>block-size ] [ read ] bi
105         >>raw-data
106         1 read le> >>block-terminator ;
107
108 : read-plain-text-extension ( -- plain-text-extension )
109     \ plain-text-extension new
110         1 read le> >>block-size
111         2 read le> >>text-grid-left
112         2 read le> >>text-grid-top
113         2 read le> >>text-grid-width
114         2 read le> >>text-grid-height
115         1 read le> >>cell-width
116         1 read le> >>cell-height
117         1 read le> >>text-fg-color-index
118         1 read le> >>text-bg-color-index
119         read-sub-blocks >>plain-text-data ;
120
121 : read-comment-extension ( -- comment-extension )
122     \ comment-extension new
123         read-sub-blocks >>comment-data ;
124     
125 : read-application-extension ( -- read-application-extension )
126    \ application-extension new
127        1 read le> >>block-size
128        8 read utf8 decode >>identifier
129        3 read >>authentication-code
130        read-sub-blocks >>application-data ;
131
132 : read-gif-header ( loading-gif -- loading-gif )
133     6 read utf8 decode >>magic ;
134
135 ERROR: unimplemented message ;
136 : read-GIF87a ( loading-gif -- loading-gif )
137     "GIF87a" unimplemented ;
138
139 : read-logical-screen-descriptor ( loading-gif -- loading-gif )
140     2 read le> >>width
141     2 read le> >>height
142     1 read le> >>flags
143     1 read le> >>background-color
144     1 read le> >>default-aspect-ratio ;
145
146 : color-table? ( image -- ? ) flags>> 7 bit? ; inline
147 : interlaced? ( image -- ? ) flags>> 6 bit? ; inline
148 : sort? ( image -- ? ) flags>> 5 bit? ; inline
149 : color-table-size ( image -- ? ) flags>> 3 bits 1 + 2^ 3 * ; inline
150
151 : color-resolution ( image -- ? ) flags>> -4 shift 3 bits ; inline
152
153 : read-global-color-table ( loading-gif -- loading-gif )
154     dup color-table? [
155         dup color-table-size read >>global-color-table
156     ] when ;
157
158 : maybe-read-local-color-table ( loading-gif -- loading-gif )
159     dup image-descriptor>> color-table? [
160         dup color-table-size read >>local-color-table
161     ] when ;
162
163 : read-image-data ( loading-gif -- loading-gif )
164     read-sub-blocks >>compressed-bytes ;
165
166 : read-table-based-image ( loading-gif -- loading-gif )
167     read-image-descriptor >>image-descriptor
168     maybe-read-local-color-table
169     read-image-data ;
170
171 : read-graphic-rendering-block ( loading-gif -- loading-gif )
172     read-table-based-image ;
173
174 : read-extension ( loading-gif -- loading-gif )
175     read1 {
176         { plain-text-extension [
177             read-plain-text-extension over plain-text-extensions>> push
178         ] }
179
180         { graphic-control-extension [
181             read-graphic-control-extension
182             over graphic-control-extensions>> push
183         ] }
184         { comment-extension [
185             read-comment-extension over comment-extensions>> push
186         ] }
187         { application-extension [
188             read-application-extension over application-extensions>> push
189         ] }
190         { f [ gif-unexpected-eof ] }
191         [ unknown-extension ]
192     } case ;
193
194 ERROR: unhandled-data byte ;
195
196 : read-data ( loading-gif -- loading-gif )
197     read1 {
198         { extension-identifier [ read-extension ] }
199         { graphic-control-extension [
200             read-graphic-control-extension
201             over graphic-control-extensions>> push
202         ] }
203         { image-descriptor [ read-table-based-image ] }
204         { trailer [ f >>loading? ] }
205         [ unhandled-data ]
206     } case ;
207
208 : read-GIF89a ( loading-gif -- loading-gif )
209     read-logical-screen-descriptor
210     read-global-color-table
211     [ read-data dup loading?>> ] loop ;
212
213 : load-gif ( stream -- loading-gif )
214     [
215         <loading-gif>
216         read-gif-header dup magic>> {
217             { "GIF87a" [ read-GIF87a ] }
218             { "GIF89a" [ read-GIF89a ] }
219             [ unsupported-gif-format ]
220         } case
221     ] with-input-stream ;
222
223 : loading-gif>image ( loading-gif -- image )
224     ;
225
226 ERROR: loading-gif-error gif-image ;
227
228 : ensure-loaded ( gif-image -- gif-image )
229     dup loading?>> [ loading-gif-error ] when ;
230
231 M: gif-image stream>image ( path gif-image -- image )
232     drop load-gif ensure-loaded loading-gif>image ;