' .ApplicationSource GIF-Reader(1.1)'! 'From VisualWorks(R) Release 2.0 of 4 August 1994 on 25 November 1994 at 12:17:08 am'! '- sources of GIF-Reader(1.1) -'! ReadStream subclass: #FilterStream instanceVariableNames: 'stream ' classVariableNames: '' poolDictionaries: '' category: 'Graphics-GIF Reading'! FilterStream comment: 'FilterStream processes data from another stream and presents it to its client with a streaming interface again. This allows FilterStreams and other streams to be composed freely. The current implementation only allows for reading, not for writing. Instance Variables: stream stream from which data is read'! !FilterStream methodsFor: 'initialize-release'! close stream == nil ifFalse: [stream close. stream := nil]! stream: aStream stream := aStream. self initialize! ! !FilterStream methodsFor: 'accessing'! atEnd super atEnd ifFalse: [^false]. self pastEnd == nil ifTrue: [^true]. self skip: -1. ^false! stream ^stream! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! !FilterStream class methodsFor: 'instance creation'! on: aStream ^self basicNew stream: aStream! ! FilterStream subclass: #GIFLZWReader instanceVariableNames: 'bits avail codeSize readMask bitMask clearCode eofCode freeCode oldCode prefix suffix initCodeSize maxCode finChar ' classVariableNames: '' poolDictionaries: '' category: 'Graphics-GIF Reading'! GIFLZWReader comment: 'This class implements the variant of Lempel-Ziv decoding used by the GIF file format. This is somewhat different from Unix compress, but uses mainly the same mechanisms. Instance Variables: bits the low-order bits of this are available for reading avail number of valid bits in ''bits'' codeSize number of bits in a code word readMask (1 raisedTo: codeSize)-1 bitMask mask for data (not code) values clearCode code value that clears the table eofCode code value that signals end-of-file freeCode next available code value oldCode last code value prefix code values that constitute a linked list of previous codes suffix data value corresponding to a code initCodeSize the initial code size; used to reset the codeSize when a clearCode is encountered maxCode maximum possible code value+1 finChar the last data value'! !GIFLZWReader methodsFor: 'initialize-release'! bitMask: mask bitMask := mask! initCodeSize: aNumber self codeSize: aNumber. initCodeSize := aNumber. clearCode := maxCode//2. eofCode := clearCode+1. freeCode := clearCode+2! initialize bits := avail := 0. collection := ByteArray new: 4097. position := readLimit := 0. prefix := WordArray new: 4096. suffix := ByteArray new: 4096! ! !GIFLZWReader methodsFor: 'private'! codeSize: aNumber aNumber <= 12 ifTrue: [codeSize := aNumber. maxCode := 1 bitShift: aNumber. readMask := maxCode - 1]! nextCode | result | [codeSize > avail] whileTrue: [bits := bits + (stream next bitShift: avail). avail := avail + 8]. result := bits bitAnd: readMask. bits := bits bitShift: 0 - codeSize. avail := avail - codeSize. ^result! pastEnd | code curCode inCode | code := self nextCode. code == eofCode ifTrue: [^nil]. code == clearCode ifTrue: [self codeSize: initCodeSize. freeCode := clearCode + 2. code := self nextCode. curCode := oldCode := code. finChar := code bitAnd: bitMask. collection at: 1 put: finChar. position := readLimit := 1. ^finChar]. curCode := inCode := code. position := collection size. readLimit := collection size. code >= freeCode ifTrue: [curCode := oldCode. collection at: position put: finChar. position := position - 1]. [curCode > bitMask] whileTrue: [collection at: position put: (suffix at: curCode). position := position - 1. curCode := prefix at: curCode]. finChar := curCode bitAnd: bitMask. collection at: position put: finChar. prefix at: freeCode put: oldCode. suffix at: freeCode put: finChar. freeCode := freeCode + 1. oldCode := inCode. freeCode >= maxCode ifTrue: [self codeSize: codeSize + 1]. ^finChar! ! ImageReader subclass: #GIFImageReader instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Graphics-GIF Reading'! GIFImageReader comment: 'This class reads GIF images. Currently, many features of the GIF protocol are not handled correctly, such as interleave or multiple images. It''s just enough to read images written out by the XV program...'! !GIFImageReader methodsFor: 'initialize-release'! readHeader "read the header" | flags | ioStream skip: 6. width := self nextLSBUnsignedShort. height := self nextLSBUnsignedShort. flags := ioStream next. ioStream next. "background; not used" ioStream next. "aspect/gif89a; not used" bitsPerPixel := (flags bitAnd: 7) + 1. (flags anyMask: 128) ifTrue: [self readPalette]! readImage self readHeader. self readImageData! readImageData "read next image" | len flags codeSize reader row | [ioStream peek = 33] whileTrue: [ioStream next; next. [(len := ioStream next) = 0] whileFalse: [ioStream skip: len]]. ioStream peek = 59 ifTrue: [^nil]. (ioStream peekFor: 44) ifFalse: [self error: 'unknown GIF tag.']. self nextLSBUnsignedShort; nextLSBUnsignedShort. width := self nextLSBUnsignedShort. height := self nextLSBUnsignedShort. flags := ioStream next. (flags anyMask: 128) ifTrue: [bitsPerPixel := (flags bitAnd: 7) + 1. self readPalette]. codeSize := ioStream next. reader := GIFLZWReader on: (GIFDataBlockReader on: ioStream). reader initCodeSize: codeSize+1; bitMask: palette maxIndex. self initializeImage. row := ByteArray new: width. 0 to: image height - 1 do: [:y | reader next: width into: row startingAt: 1. image rowAt: y putAll: row].! ! !GIFImageReader methodsFor: 'private'! readPalette palette := MappedPalette withColors: ((1 to: (1 bitShift: bitsPerPixel)) collect: [:i | ColorValue red: ioStream next / 255 green: ioStream next / 255 blue: ioStream next / 255])! ! !GIFImageReader methodsFor: 'attributes'! format ^'GIF'! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! !GIFImageReader class methodsFor: 'private'! canRead: aFilenameOrString ('*.gif' match: aFilenameOrString asString) ifTrue: [^true]. ^Object errorSignal handle: [:ex | ex returnWith: false] do: [| inputStream magic | inputStream := aFilenameOrString asFilename readStream. [magic := inputStream next: 6. magic = 'gif87a' or: [magic = 'gif89a']] valueNowOrOnUnwindDo: [inputStream close]]! ! FilterStream subclass: #GIFDataBlockReader instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Graphics-GIF Reading'! GIFDataBlockReader comment: 'This class implements unpacking for GIF data blocks. GIF data is normally written as a sequence of block with length < 256; starting with a length byte. A length byte of 0 signals end-of-data. Example: (GIFDataBlockReader on: #[ 4 16r44 16r61 16r74 16r61 "first block: 4 bytes ''Data''" 0 "end of data" ] readStream) upToEnd asString'! !GIFDataBlockReader methodsFor: 'initialize-release'! initialize collection := ByteArray new: 255. position := readLimit := 0! ! !GIFDataBlockReader methodsFor: 'private'! pastEnd | blockSize | blockSize := stream peek. blockSize = 0 ifTrue: [^nil]. stream next; next: blockSize into: collection startingAt: 1. position := 1. readLimit := blockSize. ^collection at: 1! !