"
COPYRIGHT (c) 1994 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
ImageReader subclass:#TargaReader
instanceVariableNames:'orientation'
classVariableNames:''
poolDictionaries:''
category:'Graphics-Images-Support'
!
!TargaReader class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 1994 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
documentation
"
this class provides methods for loading targa-file (tga) images.
Limitations:
not fully tested (I only had a few targa files to check things)
only supports 8,24 and 32 bits/pixel formats; alpha channel is ignored
Image saving not supported
I had two tga files to test this code with - it may not work with
other targa files (it certainly does not work with 1/16 bit images).
Suggestions: adapt & use the pbmplus library here.
[See also:]
Image Form Icon
BlitImageReader FaceReader GIFReader JPEGReader PBMReader PCXReader
ST80FormReader SunRasterReader TIFFReader WindowsIconReader
XBMReader XPMReader XWDReader
"
! !
!TargaReader class methodsFor:'initialization'!
initialize
"tell Image-class, that a new fileReader is present
for the '.tga' extension."
Image addReader:self suffix:'tga' mimeType:'image/x-targa'.
"Modified: 27.6.1997 / 18:39:43 / cg"
! !
!TargaReader class methodsFor:'testing'!
isValidImageFile:aFileName
"return true, if aFileName contains a targa-file image"
|aStream w h depth flags|
aStream := self streamReadingFile:aFileName.
aStream isNil ifTrue:[^ false].
aStream binary.
aStream skip:12. "/ skip 12 bytes
w := aStream nextShortMSB:false.
h := aStream nextShortMSB:false.
depth := aStream next.
flags := aStream next.
(#(8 "16" 24 32) includes:depth) ifFalse:[
aStream close. ^ false
].
aStream close.
^ true
"
TargaReader isValidImageFile:'bitmaps/test.tga'
TargaReader isValidImageFile:'bitmaps/garfield.gif'
"
"Modified: 21.4.1997 / 20:46:52 / cg"
! !
!TargaReader methodsFor:'reading from file'!
fromStream:aStream
"read a targa-image from aFileName. return the receiver (with all
relevant instance variables set for the image) or nil on error"
|depth flags nBytes ok lenID hasColorMap imageType
cmapOffset cmapLength cmapEntrySize xOrg yOrg
t bytesPerPixel bytesPerRow rowIdx startIdx endIdx rle
dSize "{ Class: SmallInteger }" |
inStream := aStream.
aStream binary.
lenID := aStream next.
hasColorMap := aStream next.
imageType := aStream next.
cmapOffset := aStream nextShortMSB:false.
cmapLength := aStream nextShortMSB:false.
cmapEntrySize := aStream next.
xOrg := aStream nextShortMSB:false.
yOrg := aStream nextShortMSB:false.
width := aStream nextShortMSB:false.
height := aStream nextShortMSB:false.
depth := aStream next.
(#(8 "16" 24 32) includes:depth) ifFalse:[
'TargaReader [warning]: unsupported depth: ' errorPrint. depth errorPrintCR.
^ nil
].
depth == 32 ifTrue:[
'TargaReader [info]: alpha channel ignored' infoPrintCR.
] ifFalse:[
'TargaReader [info]: depth: ' infoPrint. depth infoPrintCR.
].
"/ MapRGB == 1
"/ RawRGB == 2
"/ RawMono == 3
"/ MapEnCode == 9
"/ RawEnCode == 10
(#(1 2 9 10) includes:imageType) ifFalse:[
'TargaReader [warning]: unsupported imageType: ' errorPrint. imageType errorPrintCR.
].
'TargaReader [info]: imageType: ' infoPrint. imageType infoPrintCR.
"/ flags:
"/ 0000 xxxx attribute-bits-per-pixel
"/ 0000 0001 greysc
"/ 0000 0010 colour
"/ 0000 0011 mapped
"/ 0000 0100 rleEncoded
"/ 0000 1000 interlaced
"/ 00xx 0000 origin (0 -> lower-left / 1 -> l-r / 2 -> u-l / 3 -> u-r)
"/ xx00 0000 interleave (0 -> none / 1 -> odd/even / 2 ->4-fould / 3 reserved)
"/
flags := aStream next.
(flags bitAnd:2r11000000) ~~ 0 ifTrue:[
'TargaReader [warning]: unsupported interlace: ' errorPrint. flags errorPrintCR.
^ nil
].
rle := flags bitTest:2r000001000.
flags := flags bitAnd:2r111110111.
(flags bitAnd:2r00001111) ~~ 0 ifTrue:[
'TargaReader [warning]: unsupported flags: ' errorPrint. flags errorPrintCR.
^ nil
].
(flags bitAnd:2r00110000) == 16r20 ifTrue:[
orientation := #topLeft
] ifFalse:[
(flags bitAnd:2r00110000) == 16r30 ifTrue:[
orientation := #topRight
] ifFalse:[
(flags bitAnd:2r00110000) == 16r10 ifTrue:[
orientation := #bottomRight
] ifFalse:[
(flags bitAnd:2r00110000) == 0 ifTrue:[
orientation := #bottomLeft
]
]
]
].
lenID ~~ 0 ifTrue:[
aStream skip:lenID
].
hasColorMap ~~ 0 ifTrue:[
"/ read the colorMap
colorMap := Array new:cmapLength.
1 to:cmapLength do:[:index |
|r g b|
b := aStream nextByte.
g := aStream nextByte.
r := aStream nextByte.
colorMap at:index put:(Color redByte:r greenByte:g blueByte:b).
].
'TargaReader [info]: has colorMap' infoPrintCR.
].
depth == 32 ifTrue:[
imageType == 2 ifTrue:[
"/ rle ifTrue:[self halt].
self read32.
] ifFalse:[
"/ rle ifFalse:[self halt].
self read32RLE.
].
bytesPerRow := width*3.
bytesPerPixel := 3.
].
depth == 24 ifTrue:[
imageType == 2 ifTrue:[
"/ rle ifTrue:[self halt].
self read24.
] ifFalse:[
"/ rle ifFalse:[self halt].
self read24RLE.
].
bytesPerRow := width*3.
bytesPerPixel := 3.
].
depth == 8 ifTrue:[
imageType == 1 ifTrue:[
"/ rle ifTrue:[self halt].
self read8.
] ifFalse:[
"/ rle ifFalse:[self halt].
self read8RLE
].
bytesPerRow := width.
bytesPerPixel := 1.
].
orientation == #topLeft ifTrue:[
] ifFalse:[
orientation == #topRight ifTrue:[
"/ flip horizontal
rowIdx := 1.
1 to:height do:[:row |
startIdx := rowIdx.
endIdx := rowIdx + bytesPerRow - bytesPerPixel.
1 to:width//2 do:[:x |
0 to:bytesPerPixel-1 do:[:c |
t := data at:startIdx+c.
data at:startIdx+c put:(data at:endIdx+c).
data at:endIdx+c put:t.
].
startIdx := startIdx + bytesPerPixel.
endIdx := endIdx - bytesPerPixel.
].
rowIdx := rowIdx + width.
].
] ifFalse:[
orientation == #bottomLeft ifTrue:[
"/ flip vertical
startIdx := 1.
endIdx := 1 + ((height - 1) * bytesPerRow).
t := ByteArray new:bytesPerRow.
1 to:height//2 do:[:row |
t replaceFrom:1 to:bytesPerRow with:data startingAt:startIdx.
data replaceFrom:startIdx to:startIdx+bytesPerRow-1 with:data startingAt:endIdx.
data replaceFrom:endIdx to:endIdx+bytesPerRow-1 with:t startingAt:1.
startIdx := startIdx + bytesPerRow.
endIdx := endIdx - bytesPerRow
].
] ifFalse:[
'TargaReader [warning]: unsupported orientation: ' errorPrint. orientation errorPrintCR.
]
]
].
^ self
"
TargaReader fromFile:'bitmaps/test.tga'
"
"Modified: 21.4.1997 / 21:03:36 / cg"
!
read24
"read a 24 bit/pixel targa-image"
|nBytes ok dSize t|
data := ByteArray new:(width * height * 3).
inStream nextBytes:(dSize := data size) into:data.
"
mhmh - pixel-byte order is blue-green-red
swap blue & red bytes
"
nBytes := data size.
ok := false.
%{ /* OPTIONAL */
if (__isByteArray(_INST(data))) {
int __lastIndex = __intVal(nBytes) - 2;
unsigned char *__cp = __ByteArrayInstPtr(_INST(data))->ba_element;
int __i;
unsigned char __t;
for (__i=0; __i<__lastIndex; __i+=3, __cp+=3) {
__t = __cp[0];
__cp[0] = __cp[2];
__cp[2] = __t;
}
ok = true;
}
%}.
ok ifFalse:[
1 to:(dSize - 2) by:3 do:[:i |
t := data at:i.
data at:i put:(data at:i+2).
data at:i+2 put:t
]
].
photometric := #rgb.
samplesPerPixel := 3.
bitsPerSample := #(8 8 8).
!
read24RLE
"read an 8 bit/pixel rle encoded targa-image"
|total count dstIndex code n r g b|
data := ByteArray new:((total := width * height * 3)).
count := 0.
dstIndex := 1.
[count < total] whileTrue:[
code := inStream nextByte.
n := (code bitAnd:16r7F) + 1.
(code bitAnd:16r80) ~~ 0 ifTrue:[
b := inStream nextByte.
g := inStream nextByte.
r := inStream nextByte.
n timesRepeat:[
data at:dstIndex put:r.
data at:dstIndex+1 put:g.
data at:dstIndex+2 put:b.
dstIndex := dstIndex + 3
].
] ifFalse:[
n timesRepeat:[
b := inStream nextByte.
g := inStream nextByte.
r := inStream nextByte.
data at:dstIndex put:r.
data at:dstIndex+1 put:g.
data at:dstIndex+2 put:b.
dstIndex := dstIndex + 3
]
].
count := count + (n * 3).
].
photometric := #rgb.
samplesPerPixel := 3.
bitsPerSample := #(8 8 8).
"Modified: 21.4.1997 / 20:21:12 / cg"
"Created: 21.4.1997 / 20:43:23 / cg"
!
read32
"read a 32 bit/pixel targa-image; skip alpha channel (for now)"
|total dstIndex a r g b|
data := ByteArray new:((total := width * height * 3)).
dstIndex := 1.
[total > 0] whileTrue:[
inStream nextByte.
a := inStream nextByte.
b := inStream nextByte.
g := inStream nextByte.
r := inStream nextByte.
data at:dstIndex put:r.
data at:dstIndex+1 put:g.
data at:dstIndex+2 put:b.
dstIndex := dstIndex + 3.
total := total - 3.
].
photometric := #rgb.
samplesPerPixel := 3.
bitsPerSample := #(8 8 8).
"Modified: 21.4.1997 / 20:21:12 / cg"
"Created: 21.4.1997 / 20:45:35 / cg"
!
read32RLE
"read a 32 bit/pixel rle encoded targa-image; skip alpha channel (for now)"
|total count dstIndex code n a r g b|
data := ByteArray new:((total := width * height * 3)).
count := 0.
dstIndex := 1.
[count < total] whileTrue:[
code := inStream nextByte.
n := (code bitAnd:16r7F) + 1.
(code bitAnd:16r80) ~~ 0 ifTrue:[
a := inStream nextByte.
b := inStream nextByte.
g := inStream nextByte.
r := inStream nextByte.
n timesRepeat:[
data at:dstIndex put:r.
data at:dstIndex+1 put:g.
data at:dstIndex+2 put:b.
dstIndex := dstIndex + 3
].
] ifFalse:[
n timesRepeat:[
a := inStream nextByte.
b := inStream nextByte.
g := inStream nextByte.
r := inStream nextByte.
data at:dstIndex put:r.
data at:dstIndex+1 put:g.
data at:dstIndex+2 put:b.
dstIndex := dstIndex + 3
]
].
count := count + (n * 3).
].
photometric := #rgb.
samplesPerPixel := 3.
bitsPerSample := #(8 8 8).
"Created: 21.4.1997 / 20:43:54 / cg"
"Modified: 21.4.1997 / 20:45:49 / cg"
!
read8
"read an 8 bit/pixel targa-image"
data := ByteArray new:(width * height).
inStream nextBytes:(data size) into:data.
colorMap isNil ifTrue:[
photometric := #blackIs0.
] ifFalse:[
photometric := #palette.
].
samplesPerPixel := 1.
bitsPerSample := #(8).
"Created: 21.4.1997 / 20:12:35 / cg"
"Modified: 21.4.1997 / 20:39:02 / cg"
!
read8RLE
"read an 8 bit/pixel rle encoded targa-image"
|total count dstIndex code n byte|
data := ByteArray new:((total := width * height)).
count := 0.
dstIndex := 1.
[count < total] whileTrue:[
code := inStream nextByte.
n := (code bitAnd:16r7F) + 1.
(code bitAnd:16r80) ~~ 0 ifTrue:[
byte := inStream nextByte.
data from:dstIndex to:dstIndex+n-1 put:byte.
] ifFalse:[
inStream nextBytes:n into:data startingAt:dstIndex.
].
count := count + n.
dstIndex := dstIndex + n.
].
photometric := #palette.
samplesPerPixel := 1.
bitsPerSample := #(8).
"Created: 21.4.1997 / 20:19:46 / cg"
"Modified: 21.4.1997 / 20:21:12 / cg"
! !
!TargaReader class methodsFor:'documentation'!
version
^ '$Header: /cvs/stx/stx/libview2/TargaReader.st,v 1.14 1997-06-27 16:47:23 cg Exp $'
! !
TargaReader initialize!