GIFReader.st
changeset 135 ff507d9a242b
parent 114 e577a2f332d0
child 136 69c9d2368352
equal deleted inserted replaced
134:f83c245371c2 135:ff507d9a242b
     8  be provided or otherwise made available to, or used by, any
     8  be provided or otherwise made available to, or used by, any
     9  other person.  No title to or ownership of the software is
     9  other person.  No title to or ownership of the software is
    10  hereby transferred.
    10  hereby transferred.
    11 "
    11 "
    12 
    12 
    13 'From Smalltalk/X, Version:2.10.4 on 18-feb-1995 at 2:18:24 am'!
       
    14 
       
    15 ImageReader subclass:#GIFReader
    13 ImageReader subclass:#GIFReader
    16 	 instanceVariableNames:'redMap greenMap blueMap'
    14 	 instanceVariableNames:'redMap greenMap blueMap'
    17 	 classVariableNames:''
    15 	 classVariableNames:''
    18 	 poolDictionaries:''
    16 	 poolDictionaries:''
    19 	 category:'Graphics-Images support'
    17 	 category:'Graphics-Images support'
    33  other person.  No title to or ownership of the software is
    31  other person.  No title to or ownership of the software is
    34  hereby transferred.
    32  hereby transferred.
    35 "
    33 "
    36 !
    34 !
    37 
    35 
    38 version
       
    39     ^ '$Header: /cvs/stx/stx/libview2/GIFReader.st,v 1.19 1995-11-11 16:04:30 cg Exp $'
       
    40 !
       
    41 
       
    42 documentation
    36 documentation
    43 "
    37 "
    44     this class provides methods for loading and saving GIF pictures.
    38     this class provides methods for loading and saving GIF pictures.
    45     It has been tested with some different GIF87a pictures, I dont
    39     It has been tested with some different GIF87a pictures, I dont
    46     know, if it works with other GIF versions.
    40     know, if it works with other GIF versions.
    90     ].
    84     ].
    91     ^ true
    85     ^ true
    92 ! !
    86 ! !
    93 
    87 
    94 !GIFReader methodsFor:'reading from file'!
    88 !GIFReader methodsFor:'reading from file'!
       
    89 
       
    90 checkGreyscaleColormap
       
    91     "return true, if colormap is really a greymap"
       
    92 
       
    93     |sz "{ Class: SmallInteger }"
       
    94      redVal|
       
    95 
       
    96     sz := redMap size.
       
    97 
       
    98     1 to:sz do:[:i |
       
    99 	redVal := redMap at:i.
       
   100 	redVal ~~ (greenMap at:i) ifTrue:[^ false].
       
   101 	redVal ~~ (blueMap at:i) ifTrue:[^ false].
       
   102     ].
       
   103     ^ true
       
   104 !
       
   105 
       
   106 fromStream:aStream
       
   107     "read a GIF file"
       
   108 
       
   109     |byte index flag count
       
   110      colorMapSize bitsPerPixel scrWidth scrHeight
       
   111      hasColorMap hasLocalColorMap interlaced id
       
   112      leftOffs topOffs codeLen
       
   113      compressedData compressedSize
       
   114      tmp srcOffset dstOffset
       
   115      h "{ Class: SmallInteger }"|
       
   116 
       
   117     inStream := aStream.
       
   118     aStream binary.
       
   119 
       
   120     "GIF-files are always lsb (intel-world)"
       
   121     byteOrder := #lsb.
       
   122 
       
   123     id := String new:6.
       
   124     aStream nextBytes:6 into:id.
       
   125 
       
   126     "all I had for testing where GIF87a files;
       
   127      I hope later versions work too ..."
       
   128 
       
   129     (id ~= 'GIF87a') ifTrue:[
       
   130 	(id startsWith:'GIF') ifFalse:[
       
   131 	    'GIFReader: not a gif file' errorPrintNL.
       
   132 	    ^ nil
       
   133 	].
       
   134 	'GIFReader: not a GIF87a file - hope that works' errorPrintNL.
       
   135     ].
       
   136 
       
   137     "get screen dimensions (not used)"
       
   138 
       
   139     scrWidth := aStream nextShortMSB:false.
       
   140     scrHeight := aStream nextShortMSB:false.
       
   141 
       
   142     "get flag byte"
       
   143     flag := aStream nextByte.
       
   144     hasColorMap :=      (flag bitAnd:2r10000000) ~~ 0.
       
   145     "bitsPerRGB :=     ((flag bitAnd:2r01110000) bitShift:-4) + 1. "
       
   146     "colorMapSorted := ((flag bitAnd:2r00001000) ~~ 0.             "
       
   147     bitsPerPixel :=     (flag bitAnd:2r00000111) + 1.
       
   148     colorMapSize := 1 bitShift:bitsPerPixel.
       
   149 
       
   150     "get background (not used)"
       
   151     aStream nextByte.
       
   152 
       
   153     "aspect ratio (not used)"
       
   154     aStream nextByte.
       
   155 
       
   156     "get colorMap"
       
   157     hasColorMap ifTrue:[
       
   158 	self readColorMap:colorMapSize
       
   159     ].
       
   160 
       
   161     "image separator"
       
   162     byte := aStream nextByte.
       
   163     (byte ~~ 16r2C) ifTrue:[
       
   164 	'GIFReader: corrupted gif file (no imgSep)' errorPrintNL.
       
   165 	^ nil
       
   166     ].
       
   167 
       
   168     "get image data"
       
   169     leftOffs := aStream nextShortMSB:false.
       
   170     topOffs := aStream nextShortMSB:false.
       
   171     width := aStream nextShortMSB:false.
       
   172     height := aStream nextShortMSB:false.
       
   173 
       
   174 "
       
   175 'width ' print. width printNewline.
       
   176 'height ' print. height printNewline.
       
   177 "
       
   178 
       
   179     "another flag byte"
       
   180     flag := aStream nextByte.
       
   181     interlaced :=           (flag bitAnd:2r01000000) ~~ 0.
       
   182     hasLocalColorMap :=     (flag bitAnd:2r10000000) ~~ 0.
       
   183     "localColorMapSorted := (flag bitAnd:2r00100000) ~~ 0.      "
       
   184 
       
   185     "if image has a local colormap, this one is used"
       
   186 
       
   187     hasLocalColorMap ifTrue:[
       
   188 	"local descr. overwrites"
       
   189 	bitsPerPixel := (flag bitAnd:2r00000111) + 1.
       
   190 	colorMapSize := 1 bitShift:bitsPerPixel.
       
   191 " 'local colormap' printNewline. "
       
   192 	"overwrite colormap"
       
   193 	self readColorMap:colorMapSize
       
   194     ].
       
   195 
       
   196     "get codelen for decompression"
       
   197     codeLen := aStream nextByte.
       
   198 
       
   199     compressedData := ByteArray uninitializedNew:(aStream size).
       
   200 
       
   201     "get compressed data"
       
   202     index := 1.
       
   203     count := aStream nextByte.
       
   204     [count notNil and:[count ~~ 0]] whileTrue:[
       
   205 	aStream nextBytes:count into:compressedData startingAt:index.
       
   206 	index := index + count.
       
   207 	count := aStream nextByte
       
   208     ].
       
   209     compressedSize := index - 1.
       
   210 
       
   211     h := height.
       
   212     data := ByteArray new:((width + 1) * (h + 1)).
       
   213     'GIFReader: decompressing ...' infoPrintNL.
       
   214 
       
   215     self class decompressGIFFrom:compressedData
       
   216 			   count:compressedSize
       
   217 			    into:data
       
   218 		      startingAt:1
       
   219 			 codeLen:(codeLen + 1).
       
   220 
       
   221     interlaced ifTrue:[
       
   222 	Transcript showCr:'deinterlacing'.
       
   223 	tmp := ByteArray new:(data size).
       
   224 
       
   225 	"phase 1: 0, 8, 16, 24, ..."
       
   226 
       
   227 	srcOffset := 1.
       
   228 	0 to:(h - 1) by:8 do:[:dstRow |
       
   229 	    dstOffset := dstRow * width + 1.
       
   230 	    tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
       
   231 		       with:data startingAt:srcOffset.
       
   232 	    srcOffset := srcOffset + width.
       
   233 	].
       
   234 
       
   235 	"phase 2: 4, 12, 20, 28, ..."
       
   236 
       
   237 	4 to:(h - 1) by:8 do:[:dstRow |
       
   238 	    dstOffset := dstRow * width + 1.
       
   239 	    tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
       
   240 		       with:data startingAt:srcOffset.
       
   241 	    srcOffset := srcOffset + width.
       
   242 	].
       
   243 
       
   244 	"phase 3: 2, 6, 10, 14, ..."
       
   245 
       
   246 	2 to:(h - 1) by:4 do:[:dstRow |
       
   247 	    dstOffset := dstRow * width + 1.
       
   248 	    tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
       
   249 		       with:data startingAt:srcOffset.
       
   250 	    srcOffset := srcOffset + width.
       
   251 	].
       
   252 
       
   253 	"phase 4: 1, 3, 5, 7, ..."
       
   254 
       
   255 	1 to:(h - 1) by:2 do:[:dstRow |
       
   256 	    dstOffset := dstRow * width + 1.
       
   257 	    tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
       
   258 		       with:data startingAt:srcOffset.
       
   259 	    srcOffset := srcOffset + width.
       
   260 	].
       
   261 
       
   262 	data := tmp.
       
   263 	tmp := nil
       
   264     ].
       
   265 
       
   266     photometric := #palette.
       
   267     samplesPerPixel := 1.
       
   268     bitsPerSample := #(8).
       
   269 
       
   270     "check if only grey values are used,
       
   271      could make it a greyscale image if so (currently not done)"
       
   272 
       
   273 "/    self checkGreyscaleColormap ifTrue:[
       
   274 "/        self makeGreyscale
       
   275 "/    ].
       
   276 
       
   277     colorMap := Colormap redVector:redMap greenVector:greenMap blueVector:blueMap.
       
   278 
       
   279     "
       
   280      GIFReader fromFile:'../fileIn/bitmaps/claus.gif
       
   281      GIFReader fromFile:'../fileIn/bitmaps/garfield.gif'
       
   282     "
       
   283 !
       
   284 
       
   285 makeGreyscale
       
   286     "not yet implemented/needed"
       
   287 !
    95 
   288 
    96 readColorMap:colorMapSize
   289 readColorMap:colorMapSize
    97     "get gif colormap consisting of colorMapSize entries"
   290     "get gif colormap consisting of colorMapSize entries"
    98 
   291 
    99     |sz "{ Class: SmallInteger }"|
   292     |sz "{ Class: SmallInteger }"|
   108     1 to:sz do:[:i |
   301     1 to:sz do:[:i |
   109 	redMap at:i put:(inStream nextByte).
   302 	redMap at:i put:(inStream nextByte).
   110 	greenMap at:i put:(inStream nextByte).
   303 	greenMap at:i put:(inStream nextByte).
   111 	blueMap at:i put:(inStream nextByte)
   304 	blueMap at:i put:(inStream nextByte)
   112     ]
   305     ]
   113 !
   306 ! !
   114 
   307 
   115 checkGreyscaleColormap
   308 !GIFReader class methodsFor:'documentation'!
   116     "return true, if colormap is really a greymap"
   309 
   117 
   310 version
   118     |sz "{ Class: SmallInteger }"
   311     ^ '$Header: /cvs/stx/stx/libview2/GIFReader.st,v 1.20 1995-12-07 11:38:12 cg Exp $'
   119      redVal|
   312 ! !
   120 
       
   121     sz := redMap size.
       
   122 
       
   123     1 to:sz do:[:i |
       
   124 	redVal := redMap at:i.
       
   125 	redVal ~~ (greenMap at:i) ifTrue:[^ false].
       
   126 	redVal ~~ (blueMap at:i) ifTrue:[^ false].
       
   127     ].
       
   128     ^ true
       
   129 !
       
   130 
       
   131 makeGreyscale
       
   132     "not yet implemented/needed"
       
   133 !
       
   134 
       
   135 fromStream:aStream
       
   136     "read a GIF file"
       
   137 
       
   138     |byte index flag count
       
   139      colorMapSize bitsPerPixel scrWidth scrHeight
       
   140      hasColorMap hasLocalColorMap interlaced id
       
   141      leftOffs topOffs codeLen
       
   142      compressedData compressedSize
       
   143      tmp srcOffset dstOffset
       
   144      h "{ Class: SmallInteger }"|
       
   145 
       
   146     inStream := aStream.
       
   147     aStream binary.
       
   148 
       
   149     "GIF-files are always lsb (intel-world)"
       
   150     byteOrder := #lsb.
       
   151 
       
   152     id := String new:6.
       
   153     aStream nextBytes:6 into:id.
       
   154 
       
   155     "all I had for testing where GIF87a files;
       
   156      I hope later versions work too ..."
       
   157 
       
   158     (id ~= 'GIF87a') ifTrue:[
       
   159 	(id startsWith:'GIF') ifFalse:[
       
   160 	    'GIFReader: not a gif file' errorPrintNL.
       
   161 	    ^ nil
       
   162 	].
       
   163 	'GIFReader: not a GIF87a file - hope that works' errorPrintNL.
       
   164     ].
       
   165 
       
   166     "get screen dimensions (not used)"
       
   167 
       
   168     scrWidth := aStream nextShortMSB:false.
       
   169     scrHeight := aStream nextShortMSB:false.
       
   170 
       
   171     "get flag byte"
       
   172     flag := aStream nextByte.
       
   173     hasColorMap :=      (flag bitAnd:2r10000000) ~~ 0.
       
   174     "bitsPerRGB :=     ((flag bitAnd:2r01110000) bitShift:-4) + 1. "
       
   175     "colorMapSorted := ((flag bitAnd:2r00001000) ~~ 0.             "
       
   176     bitsPerPixel :=     (flag bitAnd:2r00000111) + 1.
       
   177     colorMapSize := 1 bitShift:bitsPerPixel.
       
   178 
       
   179     "get background (not used)"
       
   180     aStream nextByte.
       
   181 
       
   182     "aspect ratio (not used)"
       
   183     aStream nextByte.
       
   184 
       
   185     "get colorMap"
       
   186     hasColorMap ifTrue:[
       
   187 	self readColorMap:colorMapSize
       
   188     ].
       
   189 
       
   190     "image separator"
       
   191     byte := aStream nextByte.
       
   192     (byte ~~ 16r2C) ifTrue:[
       
   193 	'GIFReader: corrupted gif file (no imgSep)' errorPrintNL.
       
   194 	^ nil
       
   195     ].
       
   196 
       
   197     "get image data"
       
   198     leftOffs := aStream nextShortMSB:false.
       
   199     topOffs := aStream nextShortMSB:false.
       
   200     width := aStream nextShortMSB:false.
       
   201     height := aStream nextShortMSB:false.
       
   202 
       
   203 "
       
   204 'width ' print. width printNewline.
       
   205 'height ' print. height printNewline.
       
   206 "
       
   207 
       
   208     "another flag byte"
       
   209     flag := aStream nextByte.
       
   210     interlaced :=           (flag bitAnd:2r01000000) ~~ 0.
       
   211     hasLocalColorMap :=     (flag bitAnd:2r10000000) ~~ 0.
       
   212     "localColorMapSorted := (flag bitAnd:2r00100000) ~~ 0.      "
       
   213 
       
   214     "if image has a local colormap, this one is used"
       
   215 
       
   216     hasLocalColorMap ifTrue:[
       
   217 	"local descr. overwrites"
       
   218 	bitsPerPixel := (flag bitAnd:2r00000111) + 1.
       
   219 	colorMapSize := 1 bitShift:bitsPerPixel.
       
   220 " 'local colormap' printNewline. "
       
   221 	"overwrite colormap"
       
   222 	self readColorMap:colorMapSize
       
   223     ].
       
   224 
       
   225     "get codelen for decompression"
       
   226     codeLen := aStream nextByte.
       
   227 
       
   228     compressedData := ByteArray uninitializedNew:(aStream size).
       
   229 
       
   230     "get compressed data"
       
   231     index := 1.
       
   232     count := aStream nextByte.
       
   233     [count notNil and:[count ~~ 0]] whileTrue:[
       
   234 	aStream nextBytes:count into:compressedData startingAt:index.
       
   235 	index := index + count.
       
   236 	count := aStream nextByte
       
   237     ].
       
   238     compressedSize := index - 1.
       
   239 
       
   240     h := height.
       
   241     data := ByteArray new:((width + 1) * (h + 1)).
       
   242     'GIFReader: decompressing ...' infoPrintNL.
       
   243 
       
   244     self class decompressGIFFrom:compressedData
       
   245 			   count:compressedSize
       
   246 			    into:data
       
   247 		      startingAt:1
       
   248 			 codeLen:(codeLen + 1).
       
   249 
       
   250     interlaced ifTrue:[
       
   251 	Transcript showCr:'deinterlacing'.
       
   252 	tmp := ByteArray new:(data size).
       
   253 
       
   254 	"phase 1: 0, 8, 16, 24, ..."
       
   255 
       
   256 	srcOffset := 1.
       
   257 	0 to:(h - 1) by:8 do:[:dstRow |
       
   258 	    dstOffset := dstRow * width + 1.
       
   259 	    tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
       
   260 		       with:data startingAt:srcOffset.
       
   261 	    srcOffset := srcOffset + width.
       
   262 	].
       
   263 
       
   264 	"phase 2: 4, 12, 20, 28, ..."
       
   265 
       
   266 	4 to:(h - 1) by:8 do:[:dstRow |
       
   267 	    dstOffset := dstRow * width + 1.
       
   268 	    tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
       
   269 		       with:data startingAt:srcOffset.
       
   270 	    srcOffset := srcOffset + width.
       
   271 	].
       
   272 
       
   273 	"phase 3: 2, 6, 10, 14, ..."
       
   274 
       
   275 	2 to:(h - 1) by:4 do:[:dstRow |
       
   276 	    dstOffset := dstRow * width + 1.
       
   277 	    tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
       
   278 		       with:data startingAt:srcOffset.
       
   279 	    srcOffset := srcOffset + width.
       
   280 	].
       
   281 
       
   282 	"phase 4: 1, 3, 5, 7, ..."
       
   283 
       
   284 	1 to:(h - 1) by:2 do:[:dstRow |
       
   285 	    dstOffset := dstRow * width + 1.
       
   286 	    tmp replaceFrom:dstOffset to:(dstOffset + width - 1)
       
   287 		       with:data startingAt:srcOffset.
       
   288 	    srcOffset := srcOffset + width.
       
   289 	].
       
   290 
       
   291 	data := tmp.
       
   292 	tmp := nil
       
   293     ].
       
   294 
       
   295     photometric := #palette.
       
   296     samplesPerPixel := 1.
       
   297     bitsPerSample := #(8).
       
   298 
       
   299     "check if only grey values are used,
       
   300      could make it a greyscale image if so (currently not done)"
       
   301 
       
   302 "/    self checkGreyscaleColormap ifTrue:[
       
   303 "/        self makeGreyscale
       
   304 "/    ].
       
   305 
       
   306     colorMap := Colormap redVector:redMap greenVector:greenMap blueVector:blueMap.
       
   307 
       
   308     "
       
   309      GIFReader fromFile:'../fileIn/bitmaps/claus.gif
       
   310      GIFReader fromFile:'../fileIn/bitmaps/garfield.gif'
       
   311     "
       
   312 ! !
       
   313 
       
   314 GIFReader initialize!
   313 GIFReader initialize!