--- a/GIFReader.st Wed Oct 15 12:55:40 1997 +0200
+++ b/GIFReader.st Wed Oct 15 13:24:53 1997 +0200
@@ -10,9 +10,13 @@
hereby transferred.
"
+'From Smalltalk/X, Version:3.2.1 on 14-oct-1997 at 11:13:24 pm' !
+
ImageReader subclass:#GIFReader
- instanceVariableNames:'redMap greenMap blueMap'
- classVariableNames:''
+ instanceVariableNames:'redMap greenMap blueMap pass xpos ypos rowByteSize remainBitCount
+ bufByte bufStream prefixTable suffixTable clearCode eoiCode
+ freeCode codeSize maxCode interlace'
+ classVariableNames:'ImageSeparator Extension Terminator'
poolDictionaries:''
category:'Graphics-Images-Support'
!
@@ -71,9 +75,13 @@
"install myself in the Image classes fileFormat table
for the `.gif' extensions."
+ ImageSeparator := $, asciiValue.
+ Extension := $!! asciiValue.
+ Terminator := $; asciiValue.
+
MIMETypes defineImageType:'image/gif' suffix:'gif' reader:self.
- "Modified: 1.2.1997 / 14:59:37 / cg"
+ "Modified: 14.10.1997 / 18:47:27 / cg"
! !
!GIFReader class methodsFor:'testing'!
@@ -104,6 +112,145 @@
"Modified: 10.1.1997 / 15:40:34 / cg"
! !
+!GIFReader methodsFor:'private - writing'!
+
+checkCodeSize
+ (freeCode > maxCode and: [codeSize < 12])
+ ifTrue:
+ [codeSize := codeSize + 1.
+ maxCode := (1 bitShift: codeSize) - 1]
+
+ "Created: 14.10.1997 / 18:42:01 / cg"
+!
+
+flushBits
+ remainBitCount = 0
+ ifFalse:
+ [self nextBytePut: bufByte.
+ remainBitCount := 0].
+ self flushBuffer
+
+ "Modified: 14.10.1997 / 18:58:06 / cg"
+!
+
+flushBuffer
+ bufStream isEmpty ifTrue: [^ self].
+ outStream nextPut: bufStream size.
+ outStream nextPutAll: bufStream contents.
+ bufStream := WriteStream on: (ByteArray new: 256)
+
+ "Modified: 14.10.1997 / 20:46:04 / cg"
+!
+
+flushCode
+ self flushBits
+
+ "Created: 14.10.1997 / 18:57:33 / cg"
+!
+
+nextBitsPut: t1
+ | t2 t3 t4 |
+ t4 := 0.
+ remainBitCount = 0
+ ifTrue:
+ [t3 := 8.
+ t2 := t1]
+ ifFalse:
+ [t3 := remainBitCount.
+ t2 := bufByte + (t1 bitShift: 8 - remainBitCount)].
+ [t3 < codeSize]
+ whileTrue:
+ [self nextBytePut: ((t2 bitShift: t4) bitAnd: 255).
+ t4 := t4 - 8.
+ t3 := t3 + 8].
+ (remainBitCount := t3 - codeSize) = 0
+ ifTrue: [self nextBytePut: (t2 bitShift: t4)]
+ ifFalse: [bufByte := t2 bitShift: t4].
+ ^ t1
+
+ "Modified: 14.10.1997 / 19:20:24 / cg"
+!
+
+nextBytePut: t1
+ bufStream nextPut: t1.
+ bufStream size >= 254 ifTrue: [self flushBuffer]
+
+ "Created: 14.10.1997 / 18:40:01 / cg"
+ "Modified: 14.10.1997 / 18:40:36 / cg"
+!
+
+readPixelFrom: t1
+ | t2 |
+ ypos >= height ifTrue: [^ nil].
+ t2 := t1 at: ypos * rowByteSize + xpos + 1.
+ self updatePixelPosition.
+ ^ t2
+
+ "Created: 14.10.1997 / 18:43:50 / cg"
+!
+
+setParameters:bitsPerPixel
+ clearCode := 1 bitShift:bitsPerPixel.
+ eoiCode := clearCode + 1.
+ freeCode := clearCode + 2.
+ codeSize := bitsPerPixel + 1.
+ maxCode := (1 bitShift: codeSize) - 1
+
+ "Modified: 14.10.1997 / 20:09:48 / cg"
+!
+
+updatePixelPosition
+ (xpos _ xpos + 1) >= width ifFalse: [^ self].
+ xpos _ 0.
+ interlace == true
+ ifFalse:
+ [ypos _ ypos + 1.
+ ^ self].
+ pass = 0
+ ifTrue:
+ [(ypos _ ypos + 8) >= height
+ ifTrue:
+ [pass _ pass + 1.
+ ypos _ 4].
+ ^ self].
+ pass = 1
+ ifTrue:
+ [(ypos _ ypos + 8) >= height
+ ifTrue:
+ [pass _ pass + 1.
+ ypos _ 2].
+ ^ self].
+ pass = 2
+ ifTrue:
+ [(ypos _ ypos + 4) >= height
+ ifTrue:
+ [pass _ pass + 1.
+ ypos _ 1].
+ ^ self].
+ pass = 3
+ ifTrue:
+ [ypos _ ypos + 2.
+ ^ self].
+ ^ self error: 'can''t happen'
+
+ "Modified: 14.10.1997 / 18:44:27 / cg"
+!
+
+writeCode: t1
+ self nextBitsPut: t1
+
+ "Created: 14.10.1997 / 18:38:35 / cg"
+ "Modified: 14.10.1997 / 18:40:50 / cg"
+!
+
+writeCodeAndCheckCodeSize: t1
+ self writeCode: t1.
+ self checkCodeSize
+
+ "Created: 14.10.1997 / 18:38:24 / cg"
+ "Modified: 14.10.1997 / 18:40:56 / cg"
+! !
+
!GIFReader methodsFor:'reading from file'!
checkGreyscaleColormap
@@ -129,7 +276,7 @@
"read a stream containing a GIF image.
Leave image description in instance variables."
- |byte index flag count
+ |byte index flag count fileColorMap
colorMapSize bitsPerPixel scrWidth scrHeight
hasColorMap hasLocalColorMap interlaced id
leftOffs topOffs codeLen
@@ -162,7 +309,6 @@
].
"get screen dimensions (not used)"
-
scrWidth := aStream nextShortMSB:false.
scrHeight := aStream nextShortMSB:false.
@@ -183,11 +329,12 @@
"get colorMap"
hasColorMap ifTrue:[
self readColorMap:colorMapSize.
- colorMap := Colormap
+ fileColorMap := Colormap
redVector:redMap
greenVector:greenMap
blueVector:blueMap.
].
+ colorMap := fileColorMap.
photometric := #palette.
samplesPerPixel := 1.
@@ -198,15 +345,14 @@
"gif89a extensions"
byte := aStream nextByte.
- byte == 16r21 ifTrue:[
- "/ extension
+ byte == Extension ifTrue:[
self readExtension:aStream.
] ifFalse:[
- (byte == 16r3B) ifTrue:[ "trailer"
+ (byte == Terminator) ifTrue:[
atEnd := true
] ifFalse:[
"must be image separator"
- (byte ~~ 16r2C) ifTrue:[
+ (byte ~~ ImageSeparator) ifTrue:[
('GIFReader [info]: corrupted gif file (no IMAGESEP): ' , (byte printStringRadix:16)) infoPrintCR.
^ nil
].
@@ -244,6 +390,8 @@
redVector:redMap
greenVector:greenMap
blueVector:blueMap.
+ ] ifFalse:[
+ colorMap := fileColorMap
].
@@ -344,7 +492,7 @@
"
"Modified: 5.7.1996 / 17:32:01 / stefan"
- "Modified: 24.7.1997 / 18:02:44 / cg"
+ "Modified: 14.10.1997 / 20:45:57 / cg"
!
makeGreyscale
@@ -515,9 +663,178 @@
"Modified: 24.7.1997 / 18:02:49 / cg"
! !
+!GIFReader methodsFor:'writing to file'!
+
+save:image onFile:aFileName
+ "save image as GIF file on aFileName"
+
+ outStream := FileStream newFileNamed:aFileName.
+ outStream isNil ifTrue:[
+ ^ Image fileCreationErrorSignal
+ raiseWith:image
+ errorString:('file creation error: ' , aFileName asString).
+ ].
+ outStream binary.
+
+ image mask notNil ifTrue:[
+ Image informationLostQuerySignal
+ raiseWith:image
+ errorString:('GFF writer does not (yet) support an imageMask').
+ ].
+
+ byteOrder := #lsb.
+ width := image width.
+ height := image height.
+ photometric := image photometric.
+ samplesPerPixel := image samplesPerPixel.
+ bitsPerSample := image bitsPerSample.
+ colorMap := image colorMap.
+ data := image bits.
+
+ self writeHeaderFor:image.
+ self writeBitDataFor:image.
+ outStream close.
+
+ "
+ |i|
+
+ i := Image fromFile:'bitmaps/gifImages/garfield.gif'.
+ GIFReader save:i onFile:'foo.gif'.
+ (Image fromFile:'./foo.gif') inspect
+ "
+
+ "Created: 14.10.1997 / 17:40:12 / cg"
+ "Modified: 14.10.1997 / 18:59:22 / cg"
+!
+
+writeBitDataFor:image
+ | t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 |
+
+ t1 := image bits.
+ pass := 0.
+ xpos := 0.
+ ypos := 0.
+ rowByteSize := width * 8 + 31 // 32 * 4.
+ remainBitCount := 0.
+ bufByte := 0.
+ bufStream := WriteStream on: (ByteArray new: 256).
+ t2 := 12.
+ t3 := 1 bitShift: t2.
+ t4 := 5003.
+ prefixTable := Array new: t4.
+ suffixTable := Array new: t4.
+ t5 := image bitsPerPixel <= 1
+ ifTrue: [2]
+ ifFalse: [image bitsPerPixel].
+ outStream nextPut: t5. "/ codeLen
+ self setParameters: t5.
+ t7 := 0.
+ t8 := t4.
+ [t8 < 65536] whileTrue:[
+ t7 := t7 + 1.
+ t8 := t8 * 2
+ ].
+ t7 := 8 - t7.
+ 1 to: t4 do: [:t13 | suffixTable at: t13 put: -1].
+
+ self writeCodeAndCheckCodeSize: clearCode.
+ t6 := self readPixelFrom: t1.
+ [(t9 := self readPixelFrom: t1) == nil] whileFalse:[
+ t8 := (t9 bitShift: t2) + t6.
+ t10 := ((t9 bitShift: t7) bitXor: t6) + 1.
+ (suffixTable at: t10) = t8 ifTrue: [
+ t6 := prefixTable at: t10
+ ] ifFalse:[
+ t12 := true.
+ (suffixTable at: t10) >= 0 ifTrue:[
+ t11 := t4 - t10 + 1.
+ t10 = 1 ifTrue: [t11 := 1].
+
+ [
+ (t10 := t10 - t11) < 1 ifTrue: [t10 := t10 + t4].
+ (suffixTable at: t10) = t8 ifTrue:[
+ t6 := prefixTable at: t10.
+ t12 := false
+ ].
+ t12 and: [(suffixTable at: t10) > 0]
+ ] whileTrue
+ ].
+ t12 ifTrue:[
+ self writeCodeAndCheckCodeSize: t6.
+ t6 := t9.
+ freeCode < t3 ifTrue:[
+ prefixTable at: t10 put: freeCode.
+ suffixTable at: t10 put: t8.
+ freeCode := freeCode + 1
+ ] ifFalse:[
+ self writeCodeAndCheckCodeSize: clearCode.
+ 1 to: t4 do: [:t13 | suffixTable at: t13 put: -1].
+ self setParameters: t5
+ ]
+ ]
+ ]
+ ].
+ prefixTable := suffixTable := nil.
+ self writeCodeAndCheckCodeSize: t6.
+ self writeCodeAndCheckCodeSize: eoiCode.
+ self flushCode.
+ outStream nextPut: 0.
+ outStream nextPut: Terminator
+
+ "Created: 14.10.1997 / 18:33:54 / cg"
+ "Modified: 14.10.1997 / 20:31:11 / cg"
+!
+
+writeHeaderFor:image
+ "save image as GIF file on aFileName"
+
+ |bitsPerPixel t1 n|
+
+ bitsPerPixel := image bitsPerPixel.
+
+ outStream nextPutAll: 'GIF87a' asByteArray.
+ self writeShort: width. "/ screen size
+ self writeShort: height.
+ t1 := 128.
+ t1 := t1 bitOr: (bitsPerPixel - 1 bitShift: 5).
+ t1 := t1 bitOr: bitsPerPixel - 1.
+ outStream nextPut: t1. "/ flag
+ outStream nextPut: 0. "/ background (not used)
+ outStream nextPut: 0. "/ aspect ratio
+
+ n := 0.
+ image colorMap notNil ifTrue:[
+ image colorMap do:[:clr |
+ outStream
+ nextPut: (clr redByte);
+ nextPut: (clr greenByte);
+ nextPut: (clr blueByte).
+ n := n + 1.
+ ]
+ ].
+ n+1 to:(1 bitShift:bitsPerPixel) do:[:i |
+ outStream nextPut:0; nextPut:0; nextPut:0
+ ].
+ outStream nextPut:ImageSeparator.
+ self writeShort:0. "/
+ self writeShort:0. "/
+ self writeShort:width. "/ image size
+ self writeShort:height.
+
+ interlace == true ifTrue:[
+ t1 := 64
+ ] ifFalse:[
+ t1 := 0
+ ].
+ outStream nextPut:t1 "/ another flag
+
+ "Created: 14.10.1997 / 17:41:28 / cg"
+ "Modified: 14.10.1997 / 20:28:12 / cg"
+! !
+
!GIFReader class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libview2/GIFReader.st,v 1.56 1997-09-08 18:26:48 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libview2/GIFReader.st,v 1.57 1997-10-15 11:24:53 cg Exp $'
! !
GIFReader initialize!