GIFReader.st
changeset 882 2913420cab5a
parent 809 0d39cb7c21a9
child 888 69628f75a4b8
equal deleted inserted replaced
881:981e0791ca36 882:2913420cab5a
   306 
   306 
   307     "Modified: 2.5.1996 / 17:54:40 / cg"
   307     "Modified: 2.5.1996 / 17:54:40 / cg"
   308 !
   308 !
   309 
   309 
   310 fromStream:aStream
   310 fromStream:aStream
   311     "read a stream containing a GIF image.
   311     "read a stream containing a GIF image (or an image sequence).
   312      Leave image description in instance variables."
   312      Leave image description in instance variables."
   313 
   313 
   314     |byte index flag count fileColorMap
   314     |byte index flag count fileColorMap
   315      colorMapSize bitsPerPixel scrWidth scrHeight
   315      colorMapSize bitsPerPixel scrWidth scrHeight
   316      hasColorMap hasLocalColorMap interlaced id
   316      hasColorMap hasLocalColorMap interlaced id
   406                     "/ build a Depth1Image for it.
   406                     "/ build a Depth1Image for it.
   407                     "/
   407                     "/
   408                     self buildMaskFromColor:maskPixel
   408                     self buildMaskFromColor:maskPixel
   409                 ].
   409                 ].
   410 
   410 
   411                 imageSequence add:(self image).
   411                 imageSequence add:(self makeImage).
   412 
   412 
   413                 aStream atEnd ifTrue:[
   413                 aStream atEnd ifTrue:[
   414                     atEnd := true.
   414                     atEnd := true.
   415                 ]
   415                 ]
   416             ]
   416             ]
   417         ].
   417         ].
   418     ].
   418     ].
   419 
   419 
   420     "Modified: / 5.7.1996 / 17:32:01 / stefan"
   420     "Modified: / 5.7.1996 / 17:32:01 / stefan"
   421     "Modified: / 3.2.1998 / 17:53:37 / cg"
   421     "Modified: / 1.4.1998 / 14:17:26 / cg"
   422 !
   422 !
   423 
   423 
   424 makeGreyscale
   424 makeGreyscale
   425     "not yet implemented/needed"
   425     "not yet implemented/needed"
   426 !
   426 !
   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"
   599     topOffs := aStream nextShortMSB:false.
   601     topOffs := aStream nextShortMSB:false.
   600     width := aStream nextShortMSB:false.
   602     width := aStream nextShortMSB:false.
   601     height := aStream nextShortMSB:false.
   603     height := aStream nextShortMSB:false.
   602 
   604 
   603     dimensionCallBack notNil ifTrue:[
   605     dimensionCallBack notNil ifTrue:[
   604 	dimensionCallBack value:self
   606         dimensionCallBack value:self
   605     ].
   607     ].
   606 
   608 
   607 "/
   609 "/
   608 "/    'width ' print. width printNewline.
   610 "/    'width ' print. width printNewline.
   609 "/    'height ' print. height printNewline.
   611 "/    'height ' print. height printNewline.
   616     "localColorMapSorted := (flag bitAnd:2r00100000) ~~ 0.      "
   618     "localColorMapSorted := (flag bitAnd:2r00100000) ~~ 0.      "
   617 
   619 
   618     "if image has a local colormap, this one is used"
   620     "if image has a local colormap, this one is used"
   619 
   621 
   620     hasLocalColorMap ifTrue:[
   622     hasLocalColorMap ifTrue:[
   621 	"local descr. overwrites"
   623         "local descr. overwrites"
   622 	bitsPerPixel := (flag bitAnd:2r00000111) + 1.
   624         bitsPerPixel := (flag bitAnd:2r00000111) + 1.
   623 	colorMapSize := 1 bitShift:bitsPerPixel.
   625         colorMapSize := 1 bitShift:bitsPerPixel.
   624 	"overwrite colormap"
   626         "overwrite colormap"
   625 	self readColorMap:colorMapSize.
   627         self readColorMap:colorMapSize.
   626 	colorMap := Colormap 
   628         colorMap := Colormap 
   627 			redVector:redMap 
   629                         redVector:redMap 
   628 			greenVector:greenMap 
   630                         greenVector:greenMap 
   629 			blueVector:blueMap.
   631                         blueVector:blueMap.
   630     ].
   632     ].
   631 
   633 
   632 
   634 
   633     "get codelen for decompression"
   635     "get codelen for decompression"
   634     codeLen := aStream nextByte.
   636     codeLen := aStream nextByte.
   635     (aStream respondsTo:#fileSize) ifTrue:[
   637     (aStream respondsTo:#fileSize) ifTrue:[
   636 	initialBuffSize := aStream fileSize.
   638         initialBuffSize := aStream fileSize.
   637     ] ifFalse:[
   639     ] ifFalse:[
   638 	initialBuffSize := 512.
   640         initialBuffSize := 512.
   639     ].
   641     ].
   640     compressedData := ByteArray uninitializedNew:initialBuffSize.
   642     compressedData := ByteArray uninitializedNew:initialBuffSize.
   641 
   643 
   642     "get compressed data"
   644     "get compressed data"
   643     index := 1.
   645     index := 1.
   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
   937 ! !
   939 ! !
   938 
   940 
   939 !GIFReader class methodsFor:'documentation'!
   941 !GIFReader class methodsFor:'documentation'!
   940 
   942 
   941 version
   943 version
   942     ^ '$Header: /cvs/stx/stx/libview2/GIFReader.st,v 1.67 1998-02-03 16:54:19 cg Exp $'
   944     ^ '$Header: /cvs/stx/stx/libview2/GIFReader.st,v 1.68 1998-04-01 12:17:37 cg Exp $'
   943 ! !
   945 ! !
   944 GIFReader initialize!
   946 GIFReader initialize!