GIFReader.st
changeset 618 ab83e72fd105
parent 563 38cbee875bfa
child 619 395cc493a341
--- a/GIFReader.st	Tue Jun 24 13:16:55 1997 +0200
+++ b/GIFReader.st	Tue Jun 24 15:30:20 1997 +0200
@@ -104,6 +104,34 @@
     "Modified: 10.1.1997 / 15:40:34 / cg"
 ! !
 
+!GIFReader methodsFor:'accessing'!
+
+image
+    "return the first image as read"
+
+    ^ imageSequence first
+
+    "Modified: 21.6.1997 / 18:32:38 / cg"
+    "Created: 21.6.1997 / 18:37:05 / cg"
+!
+
+images
+    "return a collection of all images as represented by myself"
+
+    ^ imageSequence
+
+    "Created: 21.6.1997 / 12:01:34 / cg"
+    "Modified: 21.6.1997 / 18:32:38 / cg"
+! !
+
+!GIFReader methodsFor:'queries'!
+
+numberOfImages
+    ^ imageSequence size
+
+    "Created: 21.6.1997 / 18:33:59 / cg"
+! !
+
 !GIFReader methodsFor:'reading from file'!
 
 checkGreyscaleColormap
@@ -134,7 +162,7 @@
      hasColorMap hasLocalColorMap interlaced id
      leftOffs topOffs codeLen
      compressedData compressedSize
-     tmp srcOffset dstOffset isGif89 
+     tmp srcOffset dstOffset isGif89 atEnd
      h "{ Class: SmallInteger }"|
 
     inStream := aStream.
@@ -182,156 +210,170 @@
 
     "get colorMap"
     hasColorMap ifTrue:[
-        self readColorMap:colorMapSize
-    ].
-
-    "skip gif89a extensions "
-    byte := aStream nextByte.
-    [byte == 16r21] whileTrue:[
-        "/ extension
-        self readExtension:aStream.
-        byte := aStream nextByte.
-    ].
-
-    "must now be image separator"
-    (byte ~~ 16r2C) ifTrue:[
-        ('GIFReader [info]: corrupted gif file (no IMAGESEP): ' , (byte printStringRadix:16)) infoPrintCR.
-        ^ nil
-    ].
-
-    "get image data"
-    leftOffs := aStream nextShortMSB:false.
-    topOffs := aStream nextShortMSB:false.
-    width := aStream nextShortMSB:false.
-    height := aStream nextShortMSB:false.
-
-    dimensionCallBack notNil ifTrue:[
-        dimensionCallBack value:self
-    ].
-
-"
-'width ' print. width printNewline.
-'height ' print. height printNewline.
-"
-
-    "another flag byte"
-    flag := aStream nextByte.
-    interlaced :=           (flag bitAnd:2r01000000) ~~ 0.
-    hasLocalColorMap :=     (flag bitAnd:2r10000000) ~~ 0.
-    "localColorMapSorted := (flag bitAnd:2r00100000) ~~ 0.      "
-
-    "if image has a local colormap, this one is used"
-
-    hasLocalColorMap ifTrue:[
-        "local descr. overwrites"
-        bitsPerPixel := (flag bitAnd:2r00000111) + 1.
-        colorMapSize := 1 bitShift:bitsPerPixel.
-" 'local colormap' printNewline. "
-        "overwrite colormap"
-        self readColorMap:colorMapSize
-    ].
-
-    "get codelen for decompression"
-    codeLen := aStream nextByte.
-
-    compressedData := ByteArray uninitializedNew:(aStream size).
-
-    "get compressed data"
-    index := 1.
-    count := aStream nextByte.
-    [count notNil and:[count ~~ 0]] whileTrue:[
-        aStream nextBytes:count into:compressedData startingAt:index blockSize:4096.
-        index := index + count.
-        count := aStream nextByte
-    ].
-    compressedSize := index - 1.
-
-    h := height.
-    data := ByteArray new:((width + 1) * (h + 1)).
-"/    'GIFReader: decompressing ...' infoPrintCR.
-
-    self class decompressGIFFrom:compressedData
-                           count:compressedSize
-                            into:data
-                      startingAt:1
-                         codeLen:(codeLen + 1).
-
-    interlaced ifTrue:[
-"/        'GIFREADER: deinterlacing ...' infoPrintCR.
-        tmp := ByteArray new:(data size).
-
-        "phase 1: 0, 8, 16, 24, ..."
-
-        srcOffset := 1.
-        0 to:(h - 1) by:8 do:[:dstRow |
-            dstOffset := dstRow * width + 1.
-            tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
-                       with:data startingAt:srcOffset.
-            srcOffset := srcOffset + width.
-        ].
-
-        "phase 2: 4, 12, 20, 28, ..."
-
-        4 to:(h - 1) by:8 do:[:dstRow |
-            dstOffset := dstRow * width + 1.
-            tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
-                       with:data startingAt:srcOffset.
-            srcOffset := srcOffset + width.
-        ].
-
-        "phase 3: 2, 6, 10, 14, ..."
-
-        2 to:(h - 1) by:4 do:[:dstRow |
-            dstOffset := dstRow * width + 1.
-            tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
-                       with:data startingAt:srcOffset.
-            srcOffset := srcOffset + width.
-        ].
-
-        "phase 4: 1, 3, 5, 7, ..."
-
-        1 to:(h - 1) by:2 do:[:dstRow |
-            dstOffset := dstRow * width + 1.
-            tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
-                       with:data startingAt:srcOffset.
-            srcOffset := srcOffset + width.
-        ].
-
-        data := tmp.
-        tmp := nil
+        self readColorMap:colorMapSize.
+        colorMap := Colormap 
+                        redVector:redMap 
+                        greenVector:greenMap 
+                        blueVector:blueMap.
     ].
 
     photometric := #palette.
     samplesPerPixel := 1.
     bitsPerSample := #(8).
 
-    "check if only grey values are used,
-     could make it a greyscale image if so (currently not done)"
+    atEnd := false.
+    [atEnd] whileFalse:[
+        "gif89a extensions"
+        byte := aStream nextByte.
+
+        [byte == 16r21] whileTrue:[
+            "/ extension
+            self readExtension:aStream.
+            byte := aStream nextByte.
+        ].
+
+        (byte == 16r3B) ifTrue:[ "trailer"
+            atEnd := true
+        ] ifFalse:[
+            "must be image separator"
+            (byte ~~ 16r2C) ifTrue:[
+                ('GIFReader [info]: corrupted gif file (no IMAGESEP): ' , (byte printStringRadix:16)) infoPrintCR.
+                ^ nil
+            ].
+
+            "get image data"
+            leftOffs := aStream nextShortMSB:false.
+            topOffs := aStream nextShortMSB:false.
+            width := aStream nextShortMSB:false.
+            height := aStream nextShortMSB:false.
+
+            dimensionCallBack notNil ifTrue:[
+                dimensionCallBack value:self
+            ].
+
+"/
+"/          'width ' print. width printNewline.
+"/          'height ' print. height printNewline.
+"/
 
-"/    self checkGreyscaleColormap ifTrue:[
-"/        self makeGreyscale
-"/    ].
+            "another flag byte"
+            flag := aStream nextByte.
+            interlaced :=           (flag bitAnd:2r01000000) ~~ 0.
+            hasLocalColorMap :=     (flag bitAnd:2r10000000) ~~ 0.
+            "localColorMapSorted := (flag bitAnd:2r00100000) ~~ 0.      "
+
+            "if image has a local colormap, this one is used"
+
+            hasLocalColorMap ifTrue:[
+                "local descr. overwrites"
+                bitsPerPixel := (flag bitAnd:2r00000111) + 1.
+                colorMapSize := 1 bitShift:bitsPerPixel.
+                "overwrite colormap"
+                self readColorMap:colorMapSize.
+                colorMap := Colormap 
+                                redVector:redMap 
+                                greenVector:greenMap 
+                                blueVector:blueMap.
+            ].
+
+
+            "get codelen for decompression"
+            codeLen := aStream nextByte.
+
+            compressedData := ByteArray uninitializedNew:(aStream size).
+
+            "get compressed data"
+            index := 1.
+            count := aStream nextByte.
+            [count notNil and:[count ~~ 0]] whileTrue:[
+                aStream nextBytes:count into:compressedData startingAt:index blockSize:4096.
+                index := index + count.
+                count := aStream nextByte
+            ].
+            compressedSize := index - 1.
 
-    colorMap := Colormap 
-                    redVector:redMap 
-                    greenVector:greenMap 
-                    blueVector:blueMap.
+            h := height.
+            data := ByteArray new:((width + 1) * (h + 1)).
+"/            'GIFReader: decompressing ...' infoPrintCR.
+
+            self class decompressGIFFrom:compressedData
+                                   count:compressedSize
+                                    into:data
+                              startingAt:1
+                                 codeLen:(codeLen + 1).
+
+            interlaced ifTrue:[
+"/                'GIFREADER: deinterlacing ...' infoPrintCR.
+                tmp := ByteArray new:(data size).
+
+                "phase 1: 0, 8, 16, 24, ..."
+
+                srcOffset := 1.
+                0 to:(h - 1) by:8 do:[:dstRow |
+                    dstOffset := dstRow * width + 1.
+                    tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
+                               with:data startingAt:srcOffset.
+                    srcOffset := srcOffset + width.
+                ].
+
+                "phase 2: 4, 12, 20, 28, ..."
+
+                4 to:(h - 1) by:8 do:[:dstRow |
+                    dstOffset := dstRow * width + 1.
+                    tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
+                               with:data startingAt:srcOffset.
+                    srcOffset := srcOffset + width.
+                ].
+
+                "phase 3: 2, 6, 10, 14, ..."
 
-    maskPixelValue notNil ifTrue:[
-        "/
-        "/ ok, there is a maskValue
-        "/ build a Depth1Image for it.
-        "/
-        self buildMaskFromColor:maskPixelValue
+                2 to:(h - 1) by:4 do:[:dstRow |
+                    dstOffset := dstRow * width + 1.
+                    tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
+                               with:data startingAt:srcOffset.
+                    srcOffset := srcOffset + width.
+                ].
+
+                "phase 4: 1, 3, 5, 7, ..."
+
+                1 to:(h - 1) by:2 do:[:dstRow |
+                    dstOffset := dstRow * width + 1.
+                    tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
+                               with:data startingAt:srcOffset.
+                    srcOffset := srcOffset + width.
+                ].
+
+                data := tmp.
+                tmp := nil.
+
+                imageSequence isNil ifTrue:[
+                    imageSequence := OrderedCollection new.
+                ].
+                maskPixelValue notNil ifTrue:[
+                    "/
+                    "/ ok, there is a maskValue
+                    "/ build a Depth1Image for it.
+                    "/
+                    self buildMaskFromColor:maskPixelValue
+                ].
+
+                imageSequence add:(self image).
+
+                aStream atEnd ifTrue:[
+                    atEnd := true.
+                ]
+            ]
+        ].
     ].
 
     "
      GIFReader fromFile:'../fileIn/bitmaps/claus.gif
      GIFReader fromFile:'../fileIn/bitmaps/garfield.gif'
+     GIFReader new fromStream:('/home2/cg/.misc/circum.gif' asFilename readStream)
     "
 
     "Modified: 5.7.1996 / 17:32:01 / stefan"
-    "Modified: 24.4.1997 / 21:13:06 / cg"
+    "Modified: 21.6.1997 / 18:36:49 / cg"
 !
 
 makeGreyscale
@@ -362,7 +404,9 @@
 
     |type blockSize subBlockSize
      aspNum aspDen left top width height cWidth cHeight fg bg
-     animationType animationTime animationMask|
+     animationType animationTime animationMask
+     appID appAUTH
+     iterationCount b|
 
     type := aStream nextByte.
     type == $R asciiValue ifTrue:[
@@ -420,10 +464,11 @@
         animationTime := aStream nextShortMSB:false.
         animationMask := aStream nextByte.
 
-        animationType == 1 ifTrue:[
+        (animationType bitTest: 1) ifTrue:[
             maskPixelValue := animationMask.
 "/            'GIFREADER [info]: mask: ' infoPrint. (maskPixelValue printStringRadix:16) infoPrintCR.
         ].
+  'GIFREADER [info]: animationTime: ' infoPrint. (animationTime * (1/100)) infoPrintCR.
 
         [(subBlockSize := aStream nextByte) > 0] whileTrue:[
             aStream skip:subBlockSize
@@ -446,7 +491,35 @@
         "/
         "/  application extension
         "/
-        'GIFREADER [info]: application extension ignored' infoPrintCR.
+        subBlockSize := aStream nextByte.
+        appID := (aStream nextBytes:8 ) asString.
+        appAUTH := aStream nextBytes:3.
+
+        subBlockSize := aStream nextByte.
+
+        appID = 'NETSCAPE' ifTrue:[
+            appAUTH asString = '2.0' ifTrue:[
+                subBlockSize == 3 ifTrue:[
+                    b := aStream nextByte.
+                    iterationCount := aStream nextShortMSB:false.
+                    subBlockSize := aStream nextByte.
+                ]
+            ]
+        ].
+
+        ('GIFREADER [info]: application extension (' , appID , ') ignored') infoPrintCR.
+        [subBlockSize > 0] whileTrue:[
+            aStream skip:subBlockSize.
+            subBlockSize := aStream nextByte.
+        ].
+        ^ self
+    ].
+
+    type == 16r2C ifTrue:[
+        "/
+        "/  image descriptor extension
+        "/
+        'GIFREADER [info]: image descriptor extension ignored' infoPrintCR.
         [(subBlockSize := aStream nextByte) > 0] whileTrue:[
             aStream skip:subBlockSize
         ].
@@ -461,12 +534,12 @@
         aStream skip:subBlockSize
     ]
 
-    "Modified: 11.4.1997 / 00:55:15 / cg"
+    "Modified: 21.6.1997 / 11:59:05 / cg"
 ! !
 
 !GIFReader class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview2/GIFReader.st,v 1.48 1997-04-24 19:20:58 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libview2/GIFReader.st,v 1.49 1997-06-24 13:30:20 cg Exp $'
 ! !
 GIFReader initialize!