GIFReader.st
changeset 3553 2e3f003c3848
parent 3468 d0a6fa0e6b5f
child 3573 7df429deaf89
equal deleted inserted replaced
3552:ef88cdf452d1 3553:2e3f003c3848
     1 "{ Encoding: utf8 }"
       
     2 
       
     3 "
     1 "
     4  COPYRIGHT (c) 1991 by Claus Gittinger
     2  COPYRIGHT (c) 1991 by Claus Gittinger
     5 	      All Rights Reserved
     3 	      All Rights Reserved
     6 
     4 
     7  This software is furnished under a license and may be used
     5  This software is furnished under a license and may be used
   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 
   546     | flag interlaced hasLocalColorMap bitsPerPixel colorMapSize
   544     | flag interlaced hasLocalColorMap bitsPerPixel colorMapSize
   547      codeLen compressedData compressedSize index count h tmp srcOffset dstOffset
   545      codeLen compressedData compressedSize index count h tmp srcOffset dstOffset
   548      initialBuffSize|
   546      initialBuffSize|
   549 
   547 
   550     "get image data"
   548     "get image data"
   551     leftOffs := aStream nextShortMSB:false.
   549     leftOffs := aStream nextInt16MSB:false.
   552     topOffs := aStream nextShortMSB:false.
   550     topOffs := aStream nextInt16MSB:false.
   553 "/    'GIFReader: leftOffs ' infoPrint. leftOffs infoPrintCR.
   551 "/    'GIFReader: leftOffs ' infoPrint. leftOffs infoPrintCR.
   554 "/    'GIFReader: topOffs ' infoPrint. topOffs infoPrintCR.
   552 "/    'GIFReader: topOffs ' infoPrint. topOffs infoPrintCR.
   555     width := aStream nextShortMSB:false.
   553     width := aStream nextInt16MSB:false.
   556     height := aStream nextShortMSB:false.
   554     height := aStream nextInt16MSB:false.
   557 
   555 
   558     self reportDimension.
   556     self reportDimension.
   559 
   557 
   560 "/
   558 "/
   561 "/    'width ' print. width printNewline.
   559 "/    'width ' print. width printNewline.
   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 ! !
   975     outStream nextPut:Extension.
   973     outStream nextPut:Extension.
   976     outStream nextPut:16rF9.       "/ graphic control extension
   974     outStream nextPut:16rF9.       "/ graphic control extension
   977     outStream nextPut:4.           "/ subBlockSize
   975     outStream nextPut:4.           "/ subBlockSize
   978 
   976 
   979     outStream nextPut:1.                "/ animationType
   977     outStream nextPut:1.                "/ animationType
   980     outStream nextPutShort:1 MSB:false. "/ animationTime
   978     outStream nextPutInt16:1 MSB:false. "/ animationTime
   981     outStream nextPut:maskPixel.        "/ animationMask
   979     outStream nextPut:maskPixel.        "/ animationMask
   982 
   980 
   983     outStream nextPut:0.
   981     outStream nextPut:0.
   984 ! !
   982 ! !
   985 
   983 
  1024 
  1022 
  1025 save:image onStream:aStream
  1023 save:image onStream:aStream
  1026     "save image in GIF-file-format onto aStream"
  1024     "save image in GIF-file-format onto aStream"
  1027 
  1025 
  1028     image depth ~~ 8 ifTrue:[
  1026     image depth ~~ 8 ifTrue:[
  1029 	^ Image cannotRepresentImageSignal
  1027         ^ Image cannotRepresentImageSignal
  1030 	    raiseWith:image
  1028             raiseWith:image
  1031 	    errorString:('GIF (currently) only supports depth8 images').
  1029             errorString:('GIF (currently) only supports depth8 images').
  1032     ].
  1030     ].
  1033 
  1031 
  1034     outStream := aStream.
  1032     outStream := aStream.
  1035     outStream binary.
  1033     outStream binary.
  1036 
  1034 
  1037     mask := image mask.
  1035     mask := image mask.
  1038     mask notNil ifTrue:[
  1036     mask notNil ifTrue:[
  1039 	self assignTransparentPixelIn:image
  1037         self assignTransparentPixelIn:image
  1040     ].
  1038     ].
  1041 
  1039 
  1042     byteOrder := #lsb.
  1040     byteOrder := #lsb.
  1043     width := image width.
  1041     width := image width.
  1044     height := image height.
  1042     height := image height.
  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     "
  1085 ! !
  1083 ! !
  1086 
  1084 
  1087 !GIFReader class methodsFor:'documentation'!
  1085 !GIFReader class methodsFor:'documentation'!
  1088 
  1086 
  1089 version
  1087 version
  1090     ^ '$Header: /cvs/stx/stx/libview2/GIFReader.st,v 1.108 2015-05-07 20:42:35 cg Exp $'
  1088     ^ '$Header$'
  1091 !
  1089 !
  1092 
  1090 
  1093 version_CVS
  1091 version_CVS
  1094     ^ '$Header: /cvs/stx/stx/libview2/GIFReader.st,v 1.108 2015-05-07 20:42:35 cg Exp $'
  1092     ^ '$Header$'
  1095 ! !
  1093 ! !
  1096 
  1094 
  1097 
  1095 
  1098 GIFReader initialize!
  1096 GIFReader initialize!