90 ]. |
84 ]. |
91 ^ true |
85 ^ true |
92 ! ! |
86 ! ! |
93 |
87 |
94 !GIFReader methodsFor:'reading from file'! |
88 !GIFReader methodsFor:'reading from file'! |
|
89 |
|
90 checkGreyscaleColormap |
|
91 "return true, if colormap is really a greymap" |
|
92 |
|
93 |sz "{ Class: SmallInteger }" |
|
94 redVal| |
|
95 |
|
96 sz := redMap size. |
|
97 |
|
98 1 to:sz do:[:i | |
|
99 redVal := redMap at:i. |
|
100 redVal ~~ (greenMap at:i) ifTrue:[^ false]. |
|
101 redVal ~~ (blueMap at:i) ifTrue:[^ false]. |
|
102 ]. |
|
103 ^ true |
|
104 ! |
|
105 |
|
106 fromStream:aStream |
|
107 "read a GIF file" |
|
108 |
|
109 |byte index flag count |
|
110 colorMapSize bitsPerPixel scrWidth scrHeight |
|
111 hasColorMap hasLocalColorMap interlaced id |
|
112 leftOffs topOffs codeLen |
|
113 compressedData compressedSize |
|
114 tmp srcOffset dstOffset |
|
115 h "{ Class: SmallInteger }"| |
|
116 |
|
117 inStream := aStream. |
|
118 aStream binary. |
|
119 |
|
120 "GIF-files are always lsb (intel-world)" |
|
121 byteOrder := #lsb. |
|
122 |
|
123 id := String new:6. |
|
124 aStream nextBytes:6 into:id. |
|
125 |
|
126 "all I had for testing where GIF87a files; |
|
127 I hope later versions work too ..." |
|
128 |
|
129 (id ~= 'GIF87a') ifTrue:[ |
|
130 (id startsWith:'GIF') ifFalse:[ |
|
131 'GIFReader: not a gif file' errorPrintNL. |
|
132 ^ nil |
|
133 ]. |
|
134 'GIFReader: not a GIF87a file - hope that works' errorPrintNL. |
|
135 ]. |
|
136 |
|
137 "get screen dimensions (not used)" |
|
138 |
|
139 scrWidth := aStream nextShortMSB:false. |
|
140 scrHeight := aStream nextShortMSB:false. |
|
141 |
|
142 "get flag byte" |
|
143 flag := aStream nextByte. |
|
144 hasColorMap := (flag bitAnd:2r10000000) ~~ 0. |
|
145 "bitsPerRGB := ((flag bitAnd:2r01110000) bitShift:-4) + 1. " |
|
146 "colorMapSorted := ((flag bitAnd:2r00001000) ~~ 0. " |
|
147 bitsPerPixel := (flag bitAnd:2r00000111) + 1. |
|
148 colorMapSize := 1 bitShift:bitsPerPixel. |
|
149 |
|
150 "get background (not used)" |
|
151 aStream nextByte. |
|
152 |
|
153 "aspect ratio (not used)" |
|
154 aStream nextByte. |
|
155 |
|
156 "get colorMap" |
|
157 hasColorMap ifTrue:[ |
|
158 self readColorMap:colorMapSize |
|
159 ]. |
|
160 |
|
161 "image separator" |
|
162 byte := aStream nextByte. |
|
163 (byte ~~ 16r2C) ifTrue:[ |
|
164 'GIFReader: corrupted gif file (no imgSep)' errorPrintNL. |
|
165 ^ nil |
|
166 ]. |
|
167 |
|
168 "get image data" |
|
169 leftOffs := aStream nextShortMSB:false. |
|
170 topOffs := aStream nextShortMSB:false. |
|
171 width := aStream nextShortMSB:false. |
|
172 height := aStream nextShortMSB:false. |
|
173 |
|
174 " |
|
175 'width ' print. width printNewline. |
|
176 'height ' print. height printNewline. |
|
177 " |
|
178 |
|
179 "another flag byte" |
|
180 flag := aStream nextByte. |
|
181 interlaced := (flag bitAnd:2r01000000) ~~ 0. |
|
182 hasLocalColorMap := (flag bitAnd:2r10000000) ~~ 0. |
|
183 "localColorMapSorted := (flag bitAnd:2r00100000) ~~ 0. " |
|
184 |
|
185 "if image has a local colormap, this one is used" |
|
186 |
|
187 hasLocalColorMap ifTrue:[ |
|
188 "local descr. overwrites" |
|
189 bitsPerPixel := (flag bitAnd:2r00000111) + 1. |
|
190 colorMapSize := 1 bitShift:bitsPerPixel. |
|
191 " 'local colormap' printNewline. " |
|
192 "overwrite colormap" |
|
193 self readColorMap:colorMapSize |
|
194 ]. |
|
195 |
|
196 "get codelen for decompression" |
|
197 codeLen := aStream nextByte. |
|
198 |
|
199 compressedData := ByteArray uninitializedNew:(aStream size). |
|
200 |
|
201 "get compressed data" |
|
202 index := 1. |
|
203 count := aStream nextByte. |
|
204 [count notNil and:[count ~~ 0]] whileTrue:[ |
|
205 aStream nextBytes:count into:compressedData startingAt:index. |
|
206 index := index + count. |
|
207 count := aStream nextByte |
|
208 ]. |
|
209 compressedSize := index - 1. |
|
210 |
|
211 h := height. |
|
212 data := ByteArray new:((width + 1) * (h + 1)). |
|
213 'GIFReader: decompressing ...' infoPrintNL. |
|
214 |
|
215 self class decompressGIFFrom:compressedData |
|
216 count:compressedSize |
|
217 into:data |
|
218 startingAt:1 |
|
219 codeLen:(codeLen + 1). |
|
220 |
|
221 interlaced ifTrue:[ |
|
222 Transcript showCr:'deinterlacing'. |
|
223 tmp := ByteArray new:(data size). |
|
224 |
|
225 "phase 1: 0, 8, 16, 24, ..." |
|
226 |
|
227 srcOffset := 1. |
|
228 0 to:(h - 1) by:8 do:[:dstRow | |
|
229 dstOffset := dstRow * width + 1. |
|
230 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
|
231 with:data startingAt:srcOffset. |
|
232 srcOffset := srcOffset + width. |
|
233 ]. |
|
234 |
|
235 "phase 2: 4, 12, 20, 28, ..." |
|
236 |
|
237 4 to:(h - 1) by:8 do:[:dstRow | |
|
238 dstOffset := dstRow * width + 1. |
|
239 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
|
240 with:data startingAt:srcOffset. |
|
241 srcOffset := srcOffset + width. |
|
242 ]. |
|
243 |
|
244 "phase 3: 2, 6, 10, 14, ..." |
|
245 |
|
246 2 to:(h - 1) by:4 do:[:dstRow | |
|
247 dstOffset := dstRow * width + 1. |
|
248 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
|
249 with:data startingAt:srcOffset. |
|
250 srcOffset := srcOffset + width. |
|
251 ]. |
|
252 |
|
253 "phase 4: 1, 3, 5, 7, ..." |
|
254 |
|
255 1 to:(h - 1) by:2 do:[:dstRow | |
|
256 dstOffset := dstRow * width + 1. |
|
257 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
|
258 with:data startingAt:srcOffset. |
|
259 srcOffset := srcOffset + width. |
|
260 ]. |
|
261 |
|
262 data := tmp. |
|
263 tmp := nil |
|
264 ]. |
|
265 |
|
266 photometric := #palette. |
|
267 samplesPerPixel := 1. |
|
268 bitsPerSample := #(8). |
|
269 |
|
270 "check if only grey values are used, |
|
271 could make it a greyscale image if so (currently not done)" |
|
272 |
|
273 "/ self checkGreyscaleColormap ifTrue:[ |
|
274 "/ self makeGreyscale |
|
275 "/ ]. |
|
276 |
|
277 colorMap := Colormap redVector:redMap greenVector:greenMap blueVector:blueMap. |
|
278 |
|
279 " |
|
280 GIFReader fromFile:'../fileIn/bitmaps/claus.gif |
|
281 GIFReader fromFile:'../fileIn/bitmaps/garfield.gif' |
|
282 " |
|
283 ! |
|
284 |
|
285 makeGreyscale |
|
286 "not yet implemented/needed" |
|
287 ! |
95 |
288 |
96 readColorMap:colorMapSize |
289 readColorMap:colorMapSize |
97 "get gif colormap consisting of colorMapSize entries" |
290 "get gif colormap consisting of colorMapSize entries" |
98 |
291 |
99 |sz "{ Class: SmallInteger }"| |
292 |sz "{ Class: SmallInteger }"| |
108 1 to:sz do:[:i | |
301 1 to:sz do:[:i | |
109 redMap at:i put:(inStream nextByte). |
302 redMap at:i put:(inStream nextByte). |
110 greenMap at:i put:(inStream nextByte). |
303 greenMap at:i put:(inStream nextByte). |
111 blueMap at:i put:(inStream nextByte) |
304 blueMap at:i put:(inStream nextByte) |
112 ] |
305 ] |
113 ! |
306 ! ! |
114 |
307 |
115 checkGreyscaleColormap |
308 !GIFReader class methodsFor:'documentation'! |
116 "return true, if colormap is really a greymap" |
309 |
117 |
310 version |
118 |sz "{ Class: SmallInteger }" |
311 ^ '$Header: /cvs/stx/stx/libview2/GIFReader.st,v 1.20 1995-12-07 11:38:12 cg Exp $' |
119 redVal| |
312 ! ! |
120 |
|
121 sz := redMap size. |
|
122 |
|
123 1 to:sz do:[:i | |
|
124 redVal := redMap at:i. |
|
125 redVal ~~ (greenMap at:i) ifTrue:[^ false]. |
|
126 redVal ~~ (blueMap at:i) ifTrue:[^ false]. |
|
127 ]. |
|
128 ^ true |
|
129 ! |
|
130 |
|
131 makeGreyscale |
|
132 "not yet implemented/needed" |
|
133 ! |
|
134 |
|
135 fromStream:aStream |
|
136 "read a GIF file" |
|
137 |
|
138 |byte index flag count |
|
139 colorMapSize bitsPerPixel scrWidth scrHeight |
|
140 hasColorMap hasLocalColorMap interlaced id |
|
141 leftOffs topOffs codeLen |
|
142 compressedData compressedSize |
|
143 tmp srcOffset dstOffset |
|
144 h "{ Class: SmallInteger }"| |
|
145 |
|
146 inStream := aStream. |
|
147 aStream binary. |
|
148 |
|
149 "GIF-files are always lsb (intel-world)" |
|
150 byteOrder := #lsb. |
|
151 |
|
152 id := String new:6. |
|
153 aStream nextBytes:6 into:id. |
|
154 |
|
155 "all I had for testing where GIF87a files; |
|
156 I hope later versions work too ..." |
|
157 |
|
158 (id ~= 'GIF87a') ifTrue:[ |
|
159 (id startsWith:'GIF') ifFalse:[ |
|
160 'GIFReader: not a gif file' errorPrintNL. |
|
161 ^ nil |
|
162 ]. |
|
163 'GIFReader: not a GIF87a file - hope that works' errorPrintNL. |
|
164 ]. |
|
165 |
|
166 "get screen dimensions (not used)" |
|
167 |
|
168 scrWidth := aStream nextShortMSB:false. |
|
169 scrHeight := aStream nextShortMSB:false. |
|
170 |
|
171 "get flag byte" |
|
172 flag := aStream nextByte. |
|
173 hasColorMap := (flag bitAnd:2r10000000) ~~ 0. |
|
174 "bitsPerRGB := ((flag bitAnd:2r01110000) bitShift:-4) + 1. " |
|
175 "colorMapSorted := ((flag bitAnd:2r00001000) ~~ 0. " |
|
176 bitsPerPixel := (flag bitAnd:2r00000111) + 1. |
|
177 colorMapSize := 1 bitShift:bitsPerPixel. |
|
178 |
|
179 "get background (not used)" |
|
180 aStream nextByte. |
|
181 |
|
182 "aspect ratio (not used)" |
|
183 aStream nextByte. |
|
184 |
|
185 "get colorMap" |
|
186 hasColorMap ifTrue:[ |
|
187 self readColorMap:colorMapSize |
|
188 ]. |
|
189 |
|
190 "image separator" |
|
191 byte := aStream nextByte. |
|
192 (byte ~~ 16r2C) ifTrue:[ |
|
193 'GIFReader: corrupted gif file (no imgSep)' errorPrintNL. |
|
194 ^ nil |
|
195 ]. |
|
196 |
|
197 "get image data" |
|
198 leftOffs := aStream nextShortMSB:false. |
|
199 topOffs := aStream nextShortMSB:false. |
|
200 width := aStream nextShortMSB:false. |
|
201 height := aStream nextShortMSB:false. |
|
202 |
|
203 " |
|
204 'width ' print. width printNewline. |
|
205 'height ' print. height printNewline. |
|
206 " |
|
207 |
|
208 "another flag byte" |
|
209 flag := aStream nextByte. |
|
210 interlaced := (flag bitAnd:2r01000000) ~~ 0. |
|
211 hasLocalColorMap := (flag bitAnd:2r10000000) ~~ 0. |
|
212 "localColorMapSorted := (flag bitAnd:2r00100000) ~~ 0. " |
|
213 |
|
214 "if image has a local colormap, this one is used" |
|
215 |
|
216 hasLocalColorMap ifTrue:[ |
|
217 "local descr. overwrites" |
|
218 bitsPerPixel := (flag bitAnd:2r00000111) + 1. |
|
219 colorMapSize := 1 bitShift:bitsPerPixel. |
|
220 " 'local colormap' printNewline. " |
|
221 "overwrite colormap" |
|
222 self readColorMap:colorMapSize |
|
223 ]. |
|
224 |
|
225 "get codelen for decompression" |
|
226 codeLen := aStream nextByte. |
|
227 |
|
228 compressedData := ByteArray uninitializedNew:(aStream size). |
|
229 |
|
230 "get compressed data" |
|
231 index := 1. |
|
232 count := aStream nextByte. |
|
233 [count notNil and:[count ~~ 0]] whileTrue:[ |
|
234 aStream nextBytes:count into:compressedData startingAt:index. |
|
235 index := index + count. |
|
236 count := aStream nextByte |
|
237 ]. |
|
238 compressedSize := index - 1. |
|
239 |
|
240 h := height. |
|
241 data := ByteArray new:((width + 1) * (h + 1)). |
|
242 'GIFReader: decompressing ...' infoPrintNL. |
|
243 |
|
244 self class decompressGIFFrom:compressedData |
|
245 count:compressedSize |
|
246 into:data |
|
247 startingAt:1 |
|
248 codeLen:(codeLen + 1). |
|
249 |
|
250 interlaced ifTrue:[ |
|
251 Transcript showCr:'deinterlacing'. |
|
252 tmp := ByteArray new:(data size). |
|
253 |
|
254 "phase 1: 0, 8, 16, 24, ..." |
|
255 |
|
256 srcOffset := 1. |
|
257 0 to:(h - 1) by:8 do:[:dstRow | |
|
258 dstOffset := dstRow * width + 1. |
|
259 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
|
260 with:data startingAt:srcOffset. |
|
261 srcOffset := srcOffset + width. |
|
262 ]. |
|
263 |
|
264 "phase 2: 4, 12, 20, 28, ..." |
|
265 |
|
266 4 to:(h - 1) by:8 do:[:dstRow | |
|
267 dstOffset := dstRow * width + 1. |
|
268 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
|
269 with:data startingAt:srcOffset. |
|
270 srcOffset := srcOffset + width. |
|
271 ]. |
|
272 |
|
273 "phase 3: 2, 6, 10, 14, ..." |
|
274 |
|
275 2 to:(h - 1) by:4 do:[:dstRow | |
|
276 dstOffset := dstRow * width + 1. |
|
277 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
|
278 with:data startingAt:srcOffset. |
|
279 srcOffset := srcOffset + width. |
|
280 ]. |
|
281 |
|
282 "phase 4: 1, 3, 5, 7, ..." |
|
283 |
|
284 1 to:(h - 1) by:2 do:[:dstRow | |
|
285 dstOffset := dstRow * width + 1. |
|
286 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
|
287 with:data startingAt:srcOffset. |
|
288 srcOffset := srcOffset + width. |
|
289 ]. |
|
290 |
|
291 data := tmp. |
|
292 tmp := nil |
|
293 ]. |
|
294 |
|
295 photometric := #palette. |
|
296 samplesPerPixel := 1. |
|
297 bitsPerSample := #(8). |
|
298 |
|
299 "check if only grey values are used, |
|
300 could make it a greyscale image if so (currently not done)" |
|
301 |
|
302 "/ self checkGreyscaleColormap ifTrue:[ |
|
303 "/ self makeGreyscale |
|
304 "/ ]. |
|
305 |
|
306 colorMap := Colormap redVector:redMap greenVector:greenMap blueVector:blueMap. |
|
307 |
|
308 " |
|
309 GIFReader fromFile:'../fileIn/bitmaps/claus.gif |
|
310 GIFReader fromFile:'../fileIn/bitmaps/garfield.gif' |
|
311 " |
|
312 ! ! |
|
313 |
|
314 GIFReader initialize! |
313 GIFReader initialize! |