PCXReader.st
author claus
Mon, 10 Oct 1994 03:32:51 +0100
changeset 27 93da277c5ddd
child 29 e04e1aceff6f
permissions -rw-r--r--
Initial revision

"
 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.
"

'From Smalltalk/X, Version:2.10.3 on 22-sep-1994 at 7:31:01 pm'!

ImageReader subclass:#PCXReader
	 instanceVariableNames:''
	 classVariableNames:''
	 poolDictionaries:''
	 category:'Graphics-Support'
!

PCXReader comment:'
COPYRIGHT (c) 1994 by Claus Gittinger
	      All Rights Reserved

$Header: /cvs/stx/stx/libview2/PCXReader.st,v 1.1 1994-10-10 02:32:51 claus Exp $
'!

!PCXReader class methodsFor:'testing'!

isValidPCXHeader:aHeader
    "return true, if aHeader looks like a PCX image header"

    "check id"
    ((aHeader at:1) ~~ 16r0A) ifTrue:[
	^ false
    ].

    "check version"
    (#(0 2 3 5) includes:(aHeader at:2)) ifFalse:[
	^ false
    ].

    ^ true
!

isValidImageFile:aFilename
    "return true, if aFilename contains a PCX image"

    |fileSize header inStream|

    inStream := self streamReadingFile:aFilename.
    inStream isNil ifTrue:[^ false].

    inStream binary.
    fileSize := inStream size.

    fileSize < 128 ifTrue:[
	inStream close.
	^ false
    ].

    header := ByteArray uninitializedNew:128.
    inStream nextBytes:128 into:header.
    inStream close.

    (self isValidPCXHeader:header) ifFalse:[
	^ false
    ].
    ^ true
! !

!PCXReader 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.
"
!

version
"
$Header: /cvs/stx/stx/libview2/PCXReader.st,v 1.1 1994-10-10 02:32:51 claus Exp $
"
!

documentation
"
    this class provides methods for loading PCX bitmap files..
"
! !

!PCXReader class methodsFor:'initialization'!

initialize
    "tell Image-class, that a new fileReader is present"

    Image fileFormats at:'.pcx'  put:self.
! !

!PCXReader methodsFor:'reading from file'!

fromStreamWithHeader:header 
    | inDepth version compression nPlanes xmin ymin xmax ymax
      paletteType rawMap rMap gMap bMap 
      endIndex "{Class: SmallInteger }"
      srcIndex "{Class: SmallInteger }"
      dstIndex "{Class: SmallInteger }"
      rowIndex "{Class: SmallInteger }"
      h        "{Class: SmallInteger }"
      byte     "{Class: SmallInteger }"
      nByte    "{Class: SmallInteger }"
      idx2
      dataBytes bytesPerRow value|

    version := header at:2.
"/    'version=' print. version printNL.
    compression := header at:3.
"/    'compression=' print. compression printNL.
    (#(0 1) includes:compression) ifFalse:[
	self error:'PCXREADER: unknown compression'.
	^ nil
    ].
    inDepth := header at:4.
"/    'depth=' print. inDepth printNL.
    nPlanes := header at:66.
"/    'planes=' print. nPlanes printNL.
    bytesPerRow := header wordAt:67.
"/    'bytesPerRow=' print. bytesPerRow printNL.
    paletteType := header at:69.

    "
     although it would be easy to implement ...
     I have no test pictures for other formats.
     So its not (yet) implemented
    "
    ((inDepth ~~ 8) or:[nPlanes ~~ 1]) ifTrue:[
	'PCXReader: can only handle 1-plane 256 color images' errorPrintNL.
	^ nil
    ].

    xmin := header wordAt:5.
    ymin := header wordAt:7.
    xmax := header wordAt:9.
    ymax := header wordAt:11.

    width := (xmax - xmin + 1).
    height := (ymax - ymin + 1).
"/    'width=' print. width printNL.
"/    'height=' print. width printNL.

    (version == 2) ifTrue:[
	"read the 16-entry colormap"

	rawMap := ByteArray uninitializedNew:(16*3).
	rawMap replaceFrom:1 to:(16*3) with:header startingAt:17.
	rMap := Array new:16.
	gMap := Array new:16.
	bMap := Array new:16.
	srcIndex := 1.
	1 to:16 do:[:i |
	    rMap at:i put:(rawMap at:srcIndex).
	    srcIndex := srcIndex + 1.
	    gMap at:i put:(rawMap at:srcIndex).
	    srcIndex := srcIndex + 1.
	    bMap at:i put:(rawMap at:srcIndex).
	    srcIndex := srcIndex + 1.
	].
    ].

    data := dataBytes := ByteArray new:(height * bytesPerRow).

    compression == 1 ifTrue:[
	rowIndex := 1.
	h := height.
	1 to:h do:[:row |
	    dstIndex := rowIndex.
	    endIndex := dstIndex + bytesPerRow.
	    [dstIndex <= endIndex] whileTrue:[
		byte := inStream nextByte.
		((byte bitAnd:16rC0) ~~ 16rC0) ifTrue:[
		    dataBytes at:dstIndex put:byte.
		    dstIndex := dstIndex + 1.
		] ifFalse:[
		    nByte := byte bitAnd:2r00111111.
		    value := inStream nextByte.
		    value notNil ifTrue:[
			idx2 := endIndex min:(dstIndex + nByte - 1).
			dataBytes from:dstIndex to:idx2 put:value.
			dstIndex := dstIndex + nByte.
		    ]
		].
	    ].
	    rowIndex := rowIndex + bytesPerRow
	]
    ] ifFalse:[
	"
	 actually untested ...
	"
	inStream nextBytes:(height * bytesPerRow) into:data
    ].

    (version == 5) ifTrue:[
	"read the 256-entry colormap"

	(byte := inStream next) == 16rC0 ifFalse:[
	   'PCXREADER: no valid 256-entry palette' printNL.
	].
	rawMap := ByteArray uninitializedNew:(256*3).
	inStream nextBytes:(256*3) into:rawMap.
	rMap := Array new:256.
	gMap := Array new:256.
	bMap := Array new:256.
	srcIndex := 1.
	1 to:256 do:[:i |
	    rMap at:i put:(rawMap at:srcIndex).
	    srcIndex := srcIndex + 1.
	    gMap at:i put:(rawMap at:srcIndex).
	    srcIndex := srcIndex + 1.
	    bMap at:i put:(rawMap at:srcIndex).
	    srcIndex := srcIndex + 1.
	].
    ].

    photometric := #palette.
    samplesPerPixel := 1.
    bitsPerSample := #(8).
    colorMap := Array with:rMap with:gMap with:bMap.

    "
     |i f|
     i := Image fromFile:'/LocalLibrary/Images/OS2/dos3.ico'.
     f := i asFormOn:Display.
     v displayOpaqueForm:(f magnifyBy:2@2) x:5 y:5
    "
!

fromFile:aFilename 
    | fileSize header img |

    inStream := self class streamReadingFile:aFilename.
    inStream isNil ifTrue:[^ nil].

    inStream binary.
    fileSize := inStream size.

    fileSize < 128 ifTrue:[
	inStream close.
	self error:'PCXREADER: short file'.
	^ nil
    ].

    header := ByteArray uninitializedNew:128.
    inStream nextBytes:128 into:header.

    (self class isValidPCXHeader:header) ifFalse:[
	inStream close.
	self error:'PCXREADER: wrong header'.
	^ nil
    ].

    img := self fromStreamWithHeader:header.
    inStream close.
    ^ img
! !

PCXReader initialize!