443 |
443 |
444 "Modified: 21.6.1996 / 12:32:43 / cg" |
444 "Modified: 21.6.1996 / 12:32:43 / cg" |
445 ! |
445 ! |
446 |
446 |
447 readExtension:aStream |
447 readExtension:aStream |
448 "get gif89 extension - this is currently ignored" |
448 "get gif89 extension" |
449 |
449 |
450 |type blockSize subBlockSize |
450 |type blockSize subBlockSize |
451 aspNum aspDen left top width height cWidth cHeight fg bg |
451 aspNum aspDen left top width height cWidth cHeight fg bg |
452 animationType animationTime animationMask |
452 animationType animationTime animationMask |
453 appID appAUTH |
453 appID appAUTH |
454 iterationCount b ok| |
454 iterationCount b ok| |
455 |
455 |
456 type := aStream nextByte. |
456 type := aStream nextByte. |
457 type == $R asciiValue ifTrue:[ |
457 type == $R asciiValue ifTrue:[ |
458 "/ |
458 "/ |
459 "/ Ratio extension |
459 "/ Ratio extension |
460 "/ |
460 "/ |
461 'GIFREADER [info]: ratio extension ignored' infoPrintCR. |
461 'GIFREADER [info]: ratio extension ignored' infoPrintCR. |
462 blockSize := aStream nextByte. |
462 blockSize := aStream nextByte. |
463 (blockSize == 2) ifTrue:[ |
463 (blockSize == 2) ifTrue:[ |
464 aspNum := aStream nextByte. |
464 aspNum := aStream nextByte. |
465 aspDen := aStream nextByte |
465 aspDen := aStream nextByte |
466 ] ifFalse:[ |
466 ] ifFalse:[ |
467 aStream skip:blockSize |
467 aStream skip:blockSize |
468 ]. |
468 ]. |
469 "/ eat subblocks |
469 "/ eat subblocks |
470 |
470 |
471 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
471 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
472 aStream skip:subBlockSize |
472 aStream skip:subBlockSize |
473 ]. |
473 ]. |
474 ^ self |
474 ^ self |
475 ]. |
475 ]. |
476 |
476 |
477 type == 16r01 ifTrue:[ |
477 type == 16r01 ifTrue:[ |
478 "/ |
478 "/ |
479 "/ plaintext extension |
479 "/ plaintext extension |
480 "/ |
480 "/ |
481 "/ 'GIFREADER [info]: plaintext extension ignored' infoPrintCR. |
481 "/ 'GIFREADER [info]: plaintext extension ignored' infoPrintCR. |
482 subBlockSize := aStream nextByte. |
482 subBlockSize := aStream nextByte. |
483 left := aStream nextShortMSB:false. |
483 left := aStream nextShortMSB:false. |
484 top := aStream nextShortMSB:false. |
484 top := aStream nextShortMSB:false. |
485 width := aStream nextShortMSB:false. |
485 width := aStream nextShortMSB:false. |
486 height := aStream nextShortMSB:false. |
486 height := aStream nextShortMSB:false. |
487 cWidth := aStream nextByte. |
487 cWidth := aStream nextByte. |
488 cHeight := aStream nextByte. |
488 cHeight := aStream nextByte. |
489 fg := aStream nextByte. |
489 fg := aStream nextByte. |
490 bg := aStream nextByte. |
490 bg := aStream nextByte. |
491 aStream skip:12. |
491 aStream skip:12. |
492 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
492 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
493 aStream skip:subBlockSize |
493 aStream skip:subBlockSize |
494 ]. |
494 ]. |
495 ^ self |
495 ^ self |
496 ]. |
496 ]. |
497 |
497 |
498 type == 16rF9 ifTrue:[ |
498 type == 16rF9 ifTrue:[ |
499 "/ |
499 "/ |
500 "/ graphic control extension |
500 "/ graphic control extension |
501 "/ |
501 "/ |
502 "/ 'GIFREADER [info]: graphic control extension ignored' infoPrintCR. |
502 "/ 'GIFREADER [info]: graphic control extension ignored' infoPrintCR. |
503 |
503 |
504 [(subBlockSize := aStream nextByte) ~~ 0] whileTrue:[ |
504 [(subBlockSize := aStream nextByte) ~~ 0] whileTrue:[ |
505 "/ type bitAnd:1 means: animationMask is transparent pixel |
505 "/ type bitAnd:1 means: animationMask is transparent pixel |
506 "/ to be implemented in Image ... |
506 "/ to be implemented in Image ... |
507 |
507 |
508 animationType := aStream nextByte. |
508 animationType := aStream nextByte. |
509 animationTime := aStream nextShortMSB:false. |
509 animationTime := aStream nextShortMSB:false. |
510 animationMask := aStream nextByte. |
510 animationMask := aStream nextByte. |
511 subBlockSize := subBlockSize - 4. |
511 subBlockSize := subBlockSize - 4. |
512 |
512 |
513 (animationType bitTest: 1) ifTrue:[ |
513 (animationType bitTest: 1) ifTrue:[ |
514 maskPixel := animationMask. |
514 maskPixel := animationMask. |
515 "/ 'GIFREADER [info]: mask: ' infoPrint. (maskPixel printStringRadix:16) infoPrintCR. |
515 "/ 'GIFREADER [info]: mask: ' infoPrint. (maskPixel printStringRadix:16) infoPrintCR. |
516 ]. |
516 ]. |
517 "/ 'GIFREADER [info]: animationTime: ' infoPrint. (animationTime * (1/100)) infoPrintCR. |
517 "/ 'GIFREADER [info]: animationTime: ' infoPrint. (animationTime * (1/100)) infoPrintCR. |
518 |
518 |
519 subBlockSize ~~ 0 ifTrue:[ |
519 subBlockSize ~~ 0 ifTrue:[ |
520 aStream skip:subBlockSize |
520 aStream skip:subBlockSize |
521 ]. |
521 ]. |
522 ]. |
522 ]. |
523 ^ self |
523 ^ self |
524 ]. |
524 ]. |
525 |
525 |
526 type == 16rFE ifTrue:[ |
526 type == 16rFE ifTrue:[ |
527 "/ |
527 "/ |
528 "/ comment extension |
528 "/ comment extension |
529 "/ |
529 "/ |
530 "/ 'GIFREADER [info]: comment extension ignored' infoPrintCR. |
530 "/ 'GIFREADER [info]: comment extension ignored' infoPrintCR. |
531 [(blockSize := aStream nextByte) ~~ 0] whileTrue:[ |
531 [(blockSize := aStream nextByte) ~~ 0] whileTrue:[ |
532 aStream skip:blockSize |
532 aStream skip:blockSize |
533 ]. |
533 ]. |
534 ^ self |
534 ^ self |
535 ]. |
535 ]. |
536 |
536 |
537 type == 16rFF ifTrue:[ |
537 type == 16rFF ifTrue:[ |
538 "/ |
538 "/ |
539 "/ application extension |
539 "/ application extension |
540 "/ |
540 "/ |
541 subBlockSize := aStream nextByte. |
541 subBlockSize := aStream nextByte. |
542 appID := (aStream nextBytes:8 ) asString. |
542 appID := (aStream nextBytes:8 ) asString. |
543 appAUTH := aStream nextBytes:3. |
543 appAUTH := aStream nextBytes:3. |
544 |
544 |
545 subBlockSize := aStream nextByte. |
545 subBlockSize := aStream nextByte. |
546 |
546 |
547 ok := false. |
547 ok := false. |
548 appID = 'NETSCAPE' ifTrue:[ |
548 appID = 'NETSCAPE' ifTrue:[ |
549 appAUTH asString = '2.0' ifTrue:[ |
549 appAUTH asString = '2.0' ifTrue:[ |
550 subBlockSize == 3 ifTrue:[ |
550 subBlockSize == 3 ifTrue:[ |
551 b := aStream nextByte. |
551 b := aStream nextByte. |
552 iterationCount := aStream nextShortMSB:false. |
552 iterationCount := aStream nextShortMSB:false. |
553 subBlockSize := aStream nextByte. |
553 subBlockSize := aStream nextByte. |
554 ok := true. |
554 ok := true. |
555 ] |
555 ] |
556 ] |
556 ] |
557 ]. |
557 ]. |
558 |
558 |
559 ok ifFalse:[ |
559 ok ifFalse:[ |
560 ('GIFREADER [info]: application extension (' , appID , ') ignored') infoPrintCR. |
560 ('GIFREADER [info]: application extension (' , appID , ') ignored') infoPrintCR. |
561 ]. |
561 ]. |
562 |
562 |
563 [subBlockSize > 0] whileTrue:[ |
563 [subBlockSize > 0] whileTrue:[ |
564 aStream skip:subBlockSize. |
564 aStream skip:subBlockSize. |
565 subBlockSize := aStream nextByte. |
565 subBlockSize := aStream nextByte. |
566 ]. |
566 ]. |
567 ^ self |
567 ^ self |
568 ]. |
568 ]. |
569 |
569 |
570 type == 16r2C ifTrue:[ |
570 type == 16r2C ifTrue:[ |
571 "/ |
571 "/ |
572 "/ image descriptor extension |
572 "/ image descriptor extension |
573 "/ |
573 "/ |
574 'GIFREADER [info]: image descriptor extension ignored' infoPrintCR. |
574 'GIFREADER [info]: image descriptor extension ignored' infoPrintCR. |
575 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
575 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
576 aStream skip:subBlockSize |
576 aStream skip:subBlockSize |
577 ]. |
577 ]. |
578 ^ self |
578 ^ self |
579 ]. |
579 ]. |
580 |
580 |
581 "/ |
581 "/ |
582 "/ unknown extension |
582 "/ unknown extension |
583 "/ |
583 "/ |
584 'GIFREADER [info]: unknown extension ignored' infoPrintCR. |
584 'GIFREADER [info]: unknown extension ignored' infoPrintCR. |
585 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
585 [(subBlockSize := aStream nextByte) > 0] whileTrue:[ |
586 aStream skip:subBlockSize |
586 aStream skip:subBlockSize |
587 ] |
587 ] |
588 |
588 |
589 "Modified: 24.7.1997 / 18:02:49 / cg" |
589 "Modified: / 1.4.1998 / 14:00:37 / cg" |
590 ! |
590 ! |
591 |
591 |
592 readImage:aStream |
592 readImage:aStream |
|
593 "read a single image from aStream." |
|
594 |
593 |leftOffs topOffs flag interlaced hasLocalColorMap bitsPerPixel colorMapSize |
595 |leftOffs topOffs flag interlaced hasLocalColorMap bitsPerPixel colorMapSize |
594 codeLen compressedData compressedSize index count h tmp srcOffset dstOffset |
596 codeLen compressedData compressedSize index count h tmp srcOffset dstOffset |
595 initialBuffSize| |
597 initialBuffSize| |
596 |
598 |
597 "get image data" |
599 "get image data" |
649 t := ByteArray uninitializedNew:(index+count*3//2). |
651 t := ByteArray uninitializedNew:(index+count*3//2). |
650 t replaceBytesFrom:1 to:index-1 with:compressedData startingAt:1. |
652 t replaceBytesFrom:1 to:index-1 with:compressedData startingAt:1. |
651 compressedData := t. |
653 compressedData := t. |
652 ]. |
654 ]. |
653 |
655 |
654 aStream nextBytes:count into:compressedData startingAt:index blockSize:4096. |
656 aStream nextBytes:count into:compressedData startingAt:index blockSize:4096. |
655 index := index + count. |
657 index := index + count. |
656 count := aStream nextByte |
658 count := aStream nextByte |
657 ]. |
659 ]. |
658 compressedSize := index - 1. |
660 compressedSize := index - 1. |
659 |
661 |
660 h := height. |
662 h := height. |
661 data := ByteArray uninitializedNew:((width + 1) * (h + 1)). |
663 data := ByteArray uninitializedNew:((width + 1) * (h + 1)). |
662 "/ 'GIFReader: decompressing ...' infoPrintCR. |
664 "/ 'GIFReader: decompressing ...' infoPrintCR. |
663 |
665 |
664 self class decompressGIFFrom:compressedData |
666 self class decompressGIFFrom:compressedData |
665 count:compressedSize |
667 count:compressedSize |
666 into:data |
668 into:data |
667 startingAt:1 |
669 startingAt:1 |
668 codeLen:(codeLen + 1). |
670 codeLen:(codeLen + 1). |
669 |
671 |
670 interlaced ifTrue:[ |
672 interlaced ifTrue:[ |
671 "/ 'GIFREADER: deinterlacing ...' infoPrintCR. |
673 "/ 'GIFREADER: deinterlacing ...' infoPrintCR. |
672 tmp := ByteArray uninitializedNew:(data size). |
674 tmp := ByteArray uninitializedNew:(data size). |
673 |
675 |
674 "phase 1: 0, 8, 16, 24, ..." |
676 "phase 1: 0, 8, 16, 24, ..." |
675 |
677 |
676 srcOffset := 1. |
678 srcOffset := 1. |
677 0 to:(h - 1) by:8 do:[:dstRow | |
679 0 to:(h - 1) by:8 do:[:dstRow | |
678 dstOffset := dstRow * width + 1. |
680 dstOffset := dstRow * width + 1. |
679 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
681 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
680 with:data startingAt:srcOffset. |
682 with:data startingAt:srcOffset. |
681 srcOffset := srcOffset + width. |
683 srcOffset := srcOffset + width. |
682 ]. |
684 ]. |
683 |
685 |
684 "phase 2: 4, 12, 20, 28, ..." |
686 "phase 2: 4, 12, 20, 28, ..." |
685 |
687 |
686 4 to:(h - 1) by:8 do:[:dstRow | |
688 4 to:(h - 1) by:8 do:[:dstRow | |
687 dstOffset := dstRow * width + 1. |
689 dstOffset := dstRow * width + 1. |
688 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
690 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
689 with:data startingAt:srcOffset. |
691 with:data startingAt:srcOffset. |
690 srcOffset := srcOffset + width. |
692 srcOffset := srcOffset + width. |
691 ]. |
693 ]. |
692 |
694 |
693 "phase 3: 2, 6, 10, 14, ..." |
695 "phase 3: 2, 6, 10, 14, ..." |
694 |
696 |
695 2 to:(h - 1) by:4 do:[:dstRow | |
697 2 to:(h - 1) by:4 do:[:dstRow | |
696 dstOffset := dstRow * width + 1. |
698 dstOffset := dstRow * width + 1. |
697 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
699 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
698 with:data startingAt:srcOffset. |
700 with:data startingAt:srcOffset. |
699 srcOffset := srcOffset + width. |
701 srcOffset := srcOffset + width. |
700 ]. |
702 ]. |
701 |
703 |
702 "phase 4: 1, 3, 5, 7, ..." |
704 "phase 4: 1, 3, 5, 7, ..." |
703 |
705 |
704 1 to:(h - 1) by:2 do:[:dstRow | |
706 1 to:(h - 1) by:2 do:[:dstRow | |
705 dstOffset := dstRow * width + 1. |
707 dstOffset := dstRow * width + 1. |
706 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
708 tmp replaceFrom:dstOffset to:(dstOffset + width - 1) |
707 with:data startingAt:srcOffset. |
709 with:data startingAt:srcOffset. |
708 srcOffset := srcOffset + width. |
710 srcOffset := srcOffset + width. |
709 ]. |
711 ]. |
710 |
712 |
711 data := tmp. |
713 data := tmp. |
712 tmp := nil. |
714 tmp := nil. |
713 ]. |
715 ]. |
714 |
716 |
715 "Modified: / 13.1.1998 / 10:41:05 / cg" |
|
716 "Created: / 13.1.1998 / 10:44:05 / cg" |
717 "Created: / 13.1.1998 / 10:44:05 / cg" |
|
718 "Modified: / 1.4.1998 / 14:00:27 / cg" |
717 ! ! |
719 ! ! |
718 |
720 |
719 !GIFReader methodsFor:'writing to file'! |
721 !GIFReader methodsFor:'writing to file'! |
720 |
722 |
721 save:image onFile:aFileName |
723 save:image onFile:aFileName |