225 "GIF-files are always lsb (intel-world)" |
223 "GIF-files are always lsb (intel-world)" |
226 byteOrder := #lsb. |
224 byteOrder := #lsb. |
227 |
225 |
228 id := ByteArray new:6. |
226 id := ByteArray new:6. |
229 (aStream nextBytes:6 into:id startingAt:1) ~~ 6 ifTrue:[ |
227 (aStream nextBytes:6 into:id startingAt:1) ~~ 6 ifTrue:[ |
230 ^ self fileFormatError:'not a gif file (short read)'. |
228 ^ self fileFormatError:'not a gif file (short read)'. |
231 ]. |
229 ]. |
232 id := id asString. |
230 id := id asString. |
233 |
231 |
234 "all I had for testing where GIF87a files; |
232 "all I had for testing where GIF87a files; |
235 I hope later versions work too ..." |
233 I hope later versions work too ..." |
236 |
234 |
237 isGif89 := false. |
235 isGif89 := false. |
238 (id ~= 'GIF87a') ifTrue:[ |
236 (id ~= 'GIF87a') ifTrue:[ |
239 (id startsWith:'GIF') ifFalse:[ |
237 (id startsWith:'GIF') ifFalse:[ |
240 ^ self fileFormatError:('not a gif file (id=''' , id , ''')'). |
238 ^ self fileFormatError:('not a gif file (id=''' , id , ''')'). |
241 ]. |
239 ]. |
242 id ~= 'GIF89a' ifTrue:[ |
240 id ~= 'GIF89a' ifTrue:[ |
243 'GIFReader [info]: not a GIF87a/GIF89a file - hope that works' infoPrintCR. |
241 'GIFReader [info]: not a GIF87a/GIF89a file - hope that works' infoPrintCR. |
244 ] |
242 ] |
245 ]. |
243 ]. |
246 |
244 |
247 "get screen dimensions (not used)" |
245 "get screen dimensions (not used)" |
248 scrWidth := aStream nextShortMSB:false. |
246 scrWidth := aStream nextInt16MSB:false. |
249 scrHeight := aStream nextShortMSB:false. |
247 scrHeight := aStream nextInt16MSB:false. |
250 |
248 |
251 "get flag byte" |
249 "get flag byte" |
252 flag := aStream nextByte. |
250 flag := aStream nextByte. |
253 hasColorMap := (flag bitAnd:2r10000000) ~~ 0. |
251 hasColorMap := (flag bitAnd:2r10000000) ~~ 0. |
254 "bitsPerRGB := ((flag bitAnd:2r01110000) bitShift:-4) + 1. " |
252 "bitsPerRGB := ((flag bitAnd:2r01110000) bitShift:-4) + 1. " |
262 "aspect ratio (not used)" |
260 "aspect ratio (not used)" |
263 aStream nextByte. |
261 aStream nextByte. |
264 |
262 |
265 "get colorMap" |
263 "get colorMap" |
266 hasColorMap ifTrue:[ |
264 hasColorMap ifTrue:[ |
267 fileColorMap := self readColorMap:colorMapSize. |
265 fileColorMap := self readColorMap:colorMapSize. |
268 ]. |
266 ]. |
269 colorMap := fileColorMap. |
267 colorMap := fileColorMap. |
270 |
268 |
271 photometric := #palette. |
269 photometric := #palette. |
272 samplesPerPixel := 1. |
270 samplesPerPixel := 1. |
273 bitsPerSample := #(8). |
271 bitsPerSample := #(8). |
274 |
272 |
275 imageCount := 0. |
273 imageCount := 0. |
276 atEnd := false. |
274 atEnd := false. |
277 [atEnd] whileFalse:[ |
275 [atEnd] whileFalse:[ |
278 "gif89a extensions" |
276 "gif89a extensions" |
279 |
277 |
280 byte := aStream nextByte. |
278 byte := aStream nextByte. |
281 byte isNil ifTrue:[ |
279 byte isNil ifTrue:[ |
282 "/ atEnd-Terminator missing |
280 "/ atEnd-Terminator missing |
283 atEnd := true |
281 atEnd := true |
284 ] ifFalse:[ |
282 ] ifFalse:[ |
285 byte == Extension ifTrue:[ |
283 byte == Extension ifTrue:[ |
286 "/ 'Ext' infoPrintCR. |
284 "/ 'Ext' infoPrintCR. |
287 self readExtension:aStream. |
285 self readExtension:aStream. |
288 ] ifFalse:[ |
286 ] ifFalse:[ |
289 (byte == Terminator) ifTrue:[ |
287 (byte == Terminator) ifTrue:[ |
290 atEnd := true |
288 atEnd := true |
291 ] ifFalse:[ |
289 ] ifFalse:[ |
292 "must be image separator" |
290 "must be image separator" |
293 (byte ~~ ImageSeparator) ifTrue:[ |
291 (byte ~~ ImageSeparator) ifTrue:[ |
294 ^ self fileFormatError:('corrupted gif file (no IMAGESEP): ' , (byte printStringRadix:16)). |
292 ^ self fileFormatError:('corrupted gif file (no IMAGESEP): ' , (byte printStringRadix:16)). |
295 ]. |
293 ]. |
296 "/ 'Img' infoPrintCR. |
294 "/ 'Img' infoPrintCR. |
297 |
295 |
298 fileColorMap notNil ifTrue:[ |
296 fileColorMap notNil ifTrue:[ |
299 colorMap := fileColorMap. |
297 colorMap := fileColorMap. |
300 ]. |
298 ]. |
301 Object primitiveFailureSignal handle:[:ex | |
299 Object primitiveFailureSignal handle:[:ex | |
302 ^ self fileFormatError:('corrupted gif file'). |
300 ^ self fileFormatError:('corrupted gif file'). |
303 ] do:[ |
301 ] do:[ |
304 self readImage:aStream. |
302 self readImage:aStream. |
305 ]. |
303 ]. |
306 |
304 |
307 maskPixel notNil ifTrue:[ |
305 maskPixel notNil ifTrue:[ |
308 "/ |
306 "/ |
309 "/ ok, there is a maskValue |
307 "/ ok, there is a maskValue |
310 "/ build a Depth1Image for it. |
308 "/ build a Depth1Image for it. |
311 "/ |
309 "/ |
312 self buildMaskFromColor:maskPixel |
310 self buildMaskFromColor:maskPixel |
313 ]. |
311 ]. |
314 |
312 |
315 imageCount == 0 ifTrue:[ |
313 imageCount == 0 ifTrue:[ |
316 img := self makeImage. |
314 img := self makeImage. |
317 "/ remember first image in case more come later. |
315 "/ remember first image in case more come later. |
318 firstImage := img. |
316 firstImage := img. |
319 firstFrameDelay := frameDelay. |
317 firstFrameDelay := frameDelay. |
320 firstOffset := (leftOffs @ topOffs). |
318 firstOffset := (leftOffs @ topOffs). |
321 ] ifFalse:[ |
319 ] ifFalse:[ |
322 imageCount == 1 ifTrue:[ |
320 imageCount == 1 ifTrue:[ |
323 imageSequence := ImageSequence new. |
321 imageSequence := ImageSequence new. |
324 img imageSequence:imageSequence. |
322 img imageSequence:imageSequence. |
325 |
323 |
326 "/ add frame for first image. |
324 "/ add frame for first image. |
327 frame := ImageFrame new image:firstImage. |
325 frame := ImageFrame new image:firstImage. |
328 frame delay:firstFrameDelay. |
326 frame delay:firstFrameDelay. |
329 frame offset:firstOffset. |
327 frame offset:firstOffset. |
330 imageSequence add:frame. |
328 imageSequence add:frame. |
331 ]. |
329 ]. |
332 img := self makeImage. |
330 img := self makeImage. |
333 img imageSequence:imageSequence. |
331 img imageSequence:imageSequence. |
334 |
332 |
335 "/ add frame for this image. |
333 "/ add frame for this image. |
336 frame := ImageFrame new image:img. |
334 frame := ImageFrame new image:img. |
337 frame delay:frameDelay. |
335 frame delay:frameDelay. |
338 frame offset:(leftOffs @ topOffs). |
336 frame offset:(leftOffs @ topOffs). |
339 imageSequence add:frame. |
337 imageSequence add:frame. |
340 ]. |
338 ]. |
341 |
339 |
342 imageCount := imageCount + 1. |
340 imageCount := imageCount + 1. |
343 |
341 |
344 frameDelay := nil. |
342 frameDelay := nil. |
345 |
343 |
346 aStream atEnd ifTrue:[ |
344 aStream atEnd ifTrue:[ |
347 atEnd := true. |
345 atEnd := true. |
348 ] |
346 ] |
349 ] |
347 ] |
350 ]. |
348 ]. |
351 ]. |
349 ]. |
352 ]. |
350 ]. |
353 |
351 |
354 imageSequence notNil ifTrue:[ |
352 imageSequence notNil ifTrue:[ |
355 iterationCount notNil ifTrue:[ |
353 iterationCount notNil ifTrue:[ |
356 iterationCount == 0 ifTrue:[ |
354 iterationCount == 0 ifTrue:[ |
357 imageSequence loop:true. |
355 imageSequence loop:true. |
358 ] ifFalse:[ |
356 ] ifFalse:[ |
359 imageSequence loop:false. |
357 imageSequence loop:false. |
360 imageSequence iterationCount:iterationCount. |
358 imageSequence iterationCount:iterationCount. |
361 ] |
359 ] |
362 ] |
360 ] |
363 ]. |
361 ]. |
364 |
362 |
365 " |
363 " |
366 Image fromFile:'/home/cg/work/stx/goodies/bitmaps/gifImages/animated/vrml.gif' |
364 Image fromFile:'/home/cg/work/stx/goodies/bitmaps/gifImages/animated/vrml.gif' |
367 Image fromFile:'/home/cg/work/stx/goodies/bitmaps/gifImages/animated/arrow.gif' |
365 Image fromFile:'/home/cg/work/stx/goodies/bitmaps/gifImages/animated/arrow.gif' |
395 appID appAUTH |
393 appID appAUTH |
396 b ok| |
394 b ok| |
397 |
395 |
398 type := aStream nextByte. |
396 type := aStream nextByte. |
399 type == $R codePoint ifTrue:[ |
397 type == $R codePoint ifTrue:[ |
400 "/ |
398 "/ |
401 "/ Ratio extension |
399 "/ Ratio extension |
402 "/ |
400 "/ |
403 "/ 'GIFREADER [info]: ratio extension ignored' infoPrintCR. |
401 "/ 'GIFREADER [info]: ratio extension ignored' infoPrintCR. |
404 blockSize := aStream nextByte. |
402 blockSize := aStream nextByte. |
405 (blockSize == 2) ifTrue:[ |
403 (blockSize == 2) ifTrue:[ |
406 aspNum := aStream nextByte. |
404 aspNum := aStream nextByte. |
407 aspDen := aStream nextByte |
405 aspDen := aStream nextByte |
408 ] ifFalse:[ |
406 ] ifFalse:[ |
409 aStream skip:blockSize |
407 aStream skip:blockSize |
410 ]. |
408 ]. |
411 |
409 |
412 "/ eat subblocks |
410 "/ eat subblocks |
413 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
411 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
414 aStream skip:subBlockSize |
412 aStream skip:subBlockSize |
415 ]. |
413 ]. |
416 ^ self |
414 ^ self |
417 ]. |
415 ]. |
418 |
416 |
419 type == 16r01 ifTrue:[ |
417 type == 16r01 ifTrue:[ |
420 "/ |
418 "/ |
421 "/ plaintext extension |
419 "/ plaintext extension |
422 "/ |
420 "/ |
423 "/ 'GIFREADER [info]: plaintext extension ignored' infoPrintCR. |
421 "/ 'GIFREADER [info]: plaintext extension ignored' infoPrintCR. |
424 subBlockSize := aStream nextByte. |
422 subBlockSize := aStream nextByte. |
425 left := aStream nextShortMSB:false. |
423 left := aStream nextInt16MSB:false. |
426 top := aStream nextShortMSB:false. |
424 top := aStream nextInt16MSB:false. |
427 width := aStream nextShortMSB:false. |
425 width := aStream nextInt16MSB:false. |
428 height := aStream nextShortMSB:false. |
426 height := aStream nextInt16MSB:false. |
429 cWidth := aStream nextByte. |
427 cWidth := aStream nextByte. |
430 cHeight := aStream nextByte. |
428 cHeight := aStream nextByte. |
431 fg := aStream nextByte. |
429 fg := aStream nextByte. |
432 bg := aStream nextByte. |
430 bg := aStream nextByte. |
433 aStream skip:12. |
431 aStream skip:12. |
434 "/ eat subblocks |
432 "/ eat subblocks |
435 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
433 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
436 aStream skip:subBlockSize |
434 aStream skip:subBlockSize |
437 ]. |
435 ]. |
438 ^ self |
436 ^ self |
439 ]. |
437 ]. |
440 |
438 |
441 type == 16rF9 ifTrue:[ |
439 type == 16rF9 ifTrue:[ |
442 "/ |
440 "/ |
443 "/ graphic control extension |
441 "/ graphic control extension |
444 "/ |
442 "/ |
445 "/ 'GIFREADER [info]: graphic control extension' infoPrintCR. |
443 "/ 'GIFREADER [info]: graphic control extension' infoPrintCR. |
446 |
444 |
447 [(subBlockSize := aStream nextByte) ~~ 0 and:[subBlockSize notNil]] whileTrue:[ |
445 [(subBlockSize := aStream nextByte) ~~ 0 and:[subBlockSize notNil]] whileTrue:[ |
448 "/ type bitAnd:1 means: animationMask is transparent pixel |
446 "/ type bitAnd:1 means: animationMask is transparent pixel |
449 "/ to be implemented in Image ... |
447 "/ to be implemented in Image ... |
450 |
448 |
451 animationType := aStream nextByte. |
449 animationType := aStream nextByte. |
452 animationTime := aStream nextShortMSB:false. |
450 animationTime := aStream nextInt16MSB:false. |
453 animationMask := aStream nextByte. |
451 animationMask := aStream nextByte. |
454 |
452 |
455 subBlockSize := subBlockSize - 4. |
453 subBlockSize := subBlockSize - 4. |
456 |
454 |
457 (animationType bitTest: 1) ifTrue:[ |
455 (animationType bitTest: 1) ifTrue:[ |
458 maskPixel := animationMask. |
456 maskPixel := animationMask. |
459 "/ 'GIFREADER [info]: mask: ' infoPrint. (maskPixel printStringRadix:16) infoPrintCR. |
457 "/ 'GIFREADER [info]: mask: ' infoPrint. (maskPixel printStringRadix:16) infoPrintCR. |
460 ]. |
458 ]. |
461 "/ 'GIFREADER [info]: animationTime: ' infoPrint. (animationTime * (1/100)) infoPrintCR. |
459 "/ 'GIFREADER [info]: animationTime: ' infoPrint. (animationTime * (1/100)) infoPrintCR. |
462 "/ 'GIFREADER [info]: animationType: ' infoPrint. (animationType) infoPrintCR. |
460 "/ 'GIFREADER [info]: animationType: ' infoPrint. (animationType) infoPrintCR. |
463 "/ 'GIFREADER [info]: animationMask: ' infoPrint. (animationMask) infoPrintCR. |
461 "/ 'GIFREADER [info]: animationMask: ' infoPrint. (animationMask) infoPrintCR. |
464 |
462 |
465 frameDelay := (animationTime * (1/100)) * 1000. |
463 frameDelay := (animationTime * (1/100)) * 1000. |
466 |
464 |
467 subBlockSize ~~ 0 ifTrue:[ |
465 subBlockSize ~~ 0 ifTrue:[ |
468 aStream skip:subBlockSize |
466 aStream skip:subBlockSize |
469 ]. |
467 ]. |
470 ]. |
468 ]. |
471 ^ self |
469 ^ self |
472 ]. |
470 ]. |
473 |
471 |
474 type == 16rFE ifTrue:[ |
472 type == 16rFE ifTrue:[ |
475 "/ |
473 "/ |
476 "/ comment extension |
474 "/ comment extension |
477 "/ |
475 "/ |
478 "/ 'GIFREADER [info]: comment extension' infoPrintCR. |
476 "/ 'GIFREADER [info]: comment extension' infoPrintCR. |
479 [(blockSize := aStream nextByte) ~~ 0] whileTrue:[ |
477 [(blockSize := aStream nextByte) ~~ 0] whileTrue:[ |
480 aStream skip:blockSize |
478 aStream skip:blockSize |
481 ]. |
479 ]. |
482 ^ self |
480 ^ self |
483 ]. |
481 ]. |
484 |
482 |
485 type == 16rFF ifTrue:[ |
483 type == 16rFF ifTrue:[ |
486 "/ |
484 "/ |
487 "/ application extension |
485 "/ application extension |
488 "/ |
486 "/ |
489 "/ 'GIFREADER [info]: application extension' infoPrintCR. |
487 "/ 'GIFREADER [info]: application extension' infoPrintCR. |
490 subBlockSize := aStream nextByte. |
488 subBlockSize := aStream nextByte. |
491 appID := (aStream nextBytes:8 ) asString. |
489 appID := (aStream nextBytes:8 ) asString. |
492 appAUTH := aStream nextBytes:3. |
490 appAUTH := aStream nextBytes:3. |
493 |
491 |
494 subBlockSize := aStream nextByte. |
492 subBlockSize := aStream nextByte. |
495 |
493 |
496 ok := false. |
494 ok := false. |
497 appID = 'NETSCAPE' ifTrue:[ |
495 appID = 'NETSCAPE' ifTrue:[ |
498 appAUTH asString = '2.0' ifTrue:[ |
496 appAUTH asString = '2.0' ifTrue:[ |
499 subBlockSize == 3 ifTrue:[ |
497 subBlockSize == 3 ifTrue:[ |
500 b := aStream nextByte. |
498 b := aStream nextByte. |
501 iterationCount := aStream nextShortMSB:false. |
499 iterationCount := aStream nextInt16MSB:false. |
502 subBlockSize := aStream nextByte. |
500 subBlockSize := aStream nextByte. |
503 ok := true. |
501 ok := true. |
504 "/ ('GIFREADER [info]: NETSCAPE application extension - iterationCount = ') infoPrint. |
502 "/ ('GIFREADER [info]: NETSCAPE application extension - iterationCount = ') infoPrint. |
505 "/ iterationCount infoPrintCR. |
503 "/ iterationCount infoPrintCR. |
506 ] |
504 ] |
507 ] |
505 ] |
508 ]. |
506 ]. |
509 |
507 |
510 ok ifFalse:[ |
508 ok ifFalse:[ |
511 ('GIFREADER [info]: application extension (' , appID , ') ignored') infoPrintCR. |
509 ('GIFREADER [info]: application extension (' , appID , ') ignored') infoPrintCR. |
512 ]. |
510 ]. |
513 |
511 |
514 [subBlockSize > 0] whileTrue:[ |
512 [subBlockSize > 0] whileTrue:[ |
515 aStream skip:subBlockSize. |
513 aStream skip:subBlockSize. |
516 subBlockSize := aStream nextByte. |
514 subBlockSize := aStream nextByte. |
517 ]. |
515 ]. |
518 ^ self |
516 ^ self |
519 ]. |
517 ]. |
520 |
518 |
521 type == 16r2C ifTrue:[ |
519 type == 16r2C ifTrue:[ |
522 "/ |
520 "/ |
523 "/ image descriptor extension |
521 "/ image descriptor extension |
524 "/ |
522 "/ |
525 "/ 'GIFREADER [info]: image descriptor extension ignored' infoPrintCR. |
523 "/ 'GIFREADER [info]: image descriptor extension ignored' infoPrintCR. |
526 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
524 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
527 aStream skip:subBlockSize |
525 aStream skip:subBlockSize |
528 ]. |
526 ]. |
529 ^ self |
527 ^ self |
530 ]. |
528 ]. |
531 |
529 |
532 "/ |
530 "/ |
533 "/ unknown extension |
531 "/ unknown extension |
534 "/ |
532 "/ |
535 'GIFREADER [info]: unknown extension ignored' infoPrintCR. |
533 'GIFREADER [info]: unknown extension ignored' infoPrintCR. |
536 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
534 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
537 aStream skip:subBlockSize |
535 aStream skip:subBlockSize |
538 ] |
536 ] |
539 |
537 |
540 "Modified: / 02-06-2010 / 12:21:53 / cg" |
538 "Modified: / 02-06-2010 / 12:21:53 / cg" |
541 ! |
539 ! |
542 |
540 |
569 "localColorMapSorted := (flag bitAnd:2r00100000) ~~ 0. " |
567 "localColorMapSorted := (flag bitAnd:2r00100000) ~~ 0. " |
570 |
568 |
571 "if image has a local colormap, this one is used" |
569 "if image has a local colormap, this one is used" |
572 |
570 |
573 hasLocalColorMap ifTrue:[ |
571 hasLocalColorMap ifTrue:[ |
574 "local descr. overwrites" |
572 "local descr. overwrites" |
575 bitsPerPixel := (flag bitAnd:2r00000111) + 1. |
573 bitsPerPixel := (flag bitAnd:2r00000111) + 1. |
576 colorMapSize := 1 bitShift:bitsPerPixel. |
574 colorMapSize := 1 bitShift:bitsPerPixel. |
577 "overwrite colormap" |
575 "overwrite colormap" |
578 colorMap := self readColorMap:colorMapSize. |
576 colorMap := self readColorMap:colorMapSize. |
579 ]. |
577 ]. |
580 |
578 |
581 |
579 |
582 "get codelen for decompression" |
580 "get codelen for decompression" |
583 codeLen := aStream nextByte. |
581 codeLen := aStream nextByte. |
584 (aStream respondsTo:#fileSize) ifTrue:[ |
582 (aStream respondsTo:#fileSize) ifTrue:[ |
585 initialBuffSize := aStream fileSize. |
583 initialBuffSize := aStream fileSize. |
586 ] ifFalse:[ |
584 ] ifFalse:[ |
587 initialBuffSize := 512. |
585 initialBuffSize := 512. |
588 ]. |
586 ]. |
589 compressedData := ByteArray uninitializedNew:initialBuffSize. |
587 compressedData := ByteArray uninitializedNew:initialBuffSize. |
590 |
588 |
591 "get compressed data" |
589 "get compressed data" |
592 index := 1. |
590 index := 1. |
593 count := aStream nextByte. |
591 count := aStream nextByte. |
594 [count notNil and:[count ~~ 0]] whileTrue:[ |
592 [count notNil and:[count ~~ 0]] whileTrue:[ |
595 (compressedData size < (index+count)) ifTrue:[ |
593 (compressedData size < (index+count)) ifTrue:[ |
596 |t| |
594 |t| |
597 |
595 |
598 t := ByteArray uninitializedNew:(index+count*3//2). |
596 t := ByteArray uninitializedNew:(index+count*3//2). |
599 t replaceBytesFrom:1 to:index-1 with:compressedData startingAt:1. |
597 t replaceBytesFrom:1 to:index-1 with:compressedData startingAt:1. |
600 compressedData := t. |
598 compressedData := t. |
601 ]. |
599 ]. |
602 |
600 |
603 aStream nextBytes:count into:compressedData startingAt:index blockSize:4096. |
601 aStream nextBytes:count into:compressedData startingAt:index blockSize:4096. |
604 index := index + count. |
602 index := index + count. |
605 count := aStream nextByte |
603 count := aStream nextByte |
606 ]. |
604 ]. |
607 compressedSize := index - 1. |
605 compressedSize := index - 1. |
608 |
606 |
609 h := height. |
607 h := height. |
610 data := ByteArray new:((width + 1) * (h + 1)). |
608 data := ByteArray new:((width + 1) * (h + 1)). |
611 "/ 'GIFReader: decompressing ...' infoPrintCR. |
609 "/ 'GIFReader: decompressing ...' infoPrintCR. |
612 |
610 |
613 self class decompressGIFFrom:compressedData |
611 self class decompressGIFFrom:compressedData |
614 count:compressedSize |
612 count:compressedSize |
615 into:data |
613 into:data |
616 startingAt:1 |
614 startingAt:1 |
617 codeLen:(codeLen + 1). |
615 codeLen:(codeLen + 1). |
618 |
616 |
619 interlaced ifTrue:[ |
617 interlaced ifTrue:[ |
620 "/ 'GIFREADER: deinterlacing ...' infoPrintCR. |
618 "/ 'GIFREADER: deinterlacing ...' infoPrintCR. |
621 tmp := ByteArray new:(data size). |
619 tmp := ByteArray new:(data size). |
622 |
620 |
623 "phase 1: 0, 8, 16, 24, ..." |
621 "phase 1: 0, 8, 16, 24, ..." |
624 |
622 |
625 srcOffset := 1. |
623 srcOffset := 1. |
626 0 to:(h - 1) by:8 do:[:dstRow | |
624 0 to:(h - 1) by:8 do:[:dstRow | |
627 dstOffset := dstRow * width + 1. |
625 dstOffset := dstRow * width + 1. |
628 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
626 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
629 with:data startingAt:srcOffset. |
627 with:data startingAt:srcOffset. |
630 srcOffset := srcOffset + width. |
628 srcOffset := srcOffset + width. |
631 ]. |
629 ]. |
632 |
630 |
633 "phase 2: 4, 12, 20, 28, ..." |
631 "phase 2: 4, 12, 20, 28, ..." |
634 |
632 |
635 4 to:(h - 1) by:8 do:[:dstRow | |
633 4 to:(h - 1) by:8 do:[:dstRow | |
636 dstOffset := dstRow * width + 1. |
634 dstOffset := dstRow * width + 1. |
637 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
635 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
638 with:data startingAt:srcOffset. |
636 with:data startingAt:srcOffset. |
639 srcOffset := srcOffset + width. |
637 srcOffset := srcOffset + width. |
640 ]. |
638 ]. |
641 |
639 |
642 "phase 3: 2, 6, 10, 14, ..." |
640 "phase 3: 2, 6, 10, 14, ..." |
643 |
641 |
644 2 to:(h - 1) by:4 do:[:dstRow | |
642 2 to:(h - 1) by:4 do:[:dstRow | |
645 dstOffset := dstRow * width + 1. |
643 dstOffset := dstRow * width + 1. |
646 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
644 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
647 with:data startingAt:srcOffset. |
645 with:data startingAt:srcOffset. |
648 srcOffset := srcOffset + width. |
646 srcOffset := srcOffset + width. |
649 ]. |
647 ]. |
650 |
648 |
651 "phase 4: 1, 3, 5, 7, ..." |
649 "phase 4: 1, 3, 5, 7, ..." |
652 |
650 |
653 1 to:(h - 1) by:2 do:[:dstRow | |
651 1 to:(h - 1) by:2 do:[:dstRow | |
654 dstOffset := dstRow * width + 1. |
652 dstOffset := dstRow * width + 1. |
655 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
653 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
656 with:data startingAt:srcOffset. |
654 with:data startingAt:srcOffset. |
657 srcOffset := srcOffset + width. |
655 srcOffset := srcOffset + width. |
658 ]. |
656 ]. |
659 |
657 |
660 data := tmp. |
658 data := tmp. |
661 tmp := nil. |
659 tmp := nil. |
662 ]. |
660 ]. |
663 |
661 |
664 "Created: / 13.1.1998 / 10:44:05 / cg" |
662 "Created: / 13.1.1998 / 10:44:05 / cg" |
665 "Modified: / 12.8.1998 / 13:55:32 / cg" |
663 "Modified: / 12.8.1998 / 13:55:32 / cg" |
666 ! ! |
664 ! ! |
1048 colorMap := image colorMap. |
1046 colorMap := image colorMap. |
1049 data := image bits. |
1047 data := image bits. |
1050 |
1048 |
1051 self writeHeaderFor:image. |
1049 self writeHeaderFor:image. |
1052 maskPixel notNil ifTrue:[ |
1050 maskPixel notNil ifTrue:[ |
1053 self writeMaskExtensionHeaderFor:image. |
1051 self writeMaskExtensionHeaderFor:image. |
1054 ]. |
1052 ]. |
1055 |
1053 |
1056 self writeBitDataFor:image. |
1054 self writeBitDataFor:image. |
1057 |
1055 |
1058 image imageSequence notEmptyOrNil ifTrue:[ |
1056 image imageSequence notEmptyOrNil ifTrue:[ |
1059 image imageSequence do:[:eachFrame | |
1057 image imageSequence do:[:eachFrame | |
1060 outStream nextPut:Extension. |
1058 outStream nextPut:Extension. |
1061 outStream nextPut:16rF9. "/ graphic control extension |
1059 outStream nextPut:16rF9. "/ graphic control extension |
1062 outStream nextPut:4. "/ sub block size |
1060 outStream nextPut:4. "/ sub block size |
1063 outStream nextPut:0. "/ animation type 0 |
1061 outStream nextPut:0. "/ animation type 0 |
1064 outStream nextPutShort:(eachFrame delay / 10) rounded asInteger MSB:false. |
1062 outStream nextPutInt16:(eachFrame delay / 10) rounded asInteger MSB:false. |
1065 outStream nextPut:0. "/ animation mask |
1063 outStream nextPut:0. "/ animation mask |
1066 outStream nextPut:0. "/ subblock size |
1064 outStream nextPut:0. "/ subblock size |
1067 |
1065 |
1068 self writeBitDataFor:eachFrame image. |
1066 self writeBitDataFor:eachFrame image. |
1069 |
1067 |
1070 ]. |
1068 ]. |
1071 ]. |
1069 ]. |
1072 |
1070 |
1073 outStream nextPut: Terminator. |
1071 outStream nextPut: Terminator. |
1074 |
1072 |
1075 " |
1073 " |