Initial revision
authorclaus
Fri, 03 Jun 1994 02:54:13 +0200
changeset 22 24b4aff428c0
parent 21 66b31c91177f
child 23 11c422f6d825
Initial revision
XPMReader.st
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/XPMReader.st	Fri Jun 03 02:54:13 1994 +0200
@@ -0,0 +1,279 @@
+"
+ 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:#XPMReader
+         instanceVariableNames:''
+         classVariableNames:''
+         poolDictionaries:''
+         category:'Graphics-Support'
+!
+
+XPMReader comment:'
+COPYRIGHT (c) 1994 by Claus Gittinger
+              All Rights Reserved
+'!
+
+!XPMReader 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/XPMReader.st,v 1.1 1994-06-03 00:54:13 claus Exp $
+"
+!
+
+documentation
+"
+    this class provides methods for loading x-pixmap-file (xpm) images.
+    These images are used (in X) for palette images (see ctwm or hp-vue for a lot of them).
+    The code here is a hack - it may not work for all images (it works for the testfiles
+    I got here).
+    Limitations: only reads the full-color specification, ignoring monochrome
+    and greyscale info.
+    Can only handle single-character index.
+    Does not (currently) handle none-colors (i.e. for image-masks).
+
+    Suggestions: adapt & use the XPM library here.
+"
+! !
+
+!XPMReader class methodsFor:'testing'!
+
+isValidImageFile:aFileName
+    "return true, if aFileName contains an x-bitmap-file image"
+
+    |line inStream |
+
+    inStream := self streamReadingFile:aFileName.
+    inStream isNil ifTrue:[^ false].
+
+    line := inStream nextLine.
+    inStream close.
+    line isNil ifTrue:[^ false].
+    (line startsWith:'/* XPM') ifFalse:[^ false].
+    ^ true
+
+    "
+     XPMReader isValidImageFile:'bitmaps/magtape.xpm'    
+     XPMReader isValidImageFile:'bitmaps/ljet.xpm'      
+     XPMReader isValidImageFile:'bitmaps/garfield.gif' 
+    " 
+! !
+
+!XPMReader methodsFor:'reading from file'!
+
+colorNameFrom:aStream
+    "read either a color-name or value specified in X-notation
+     (#rrggbb where rr, gg and bb are 2-digit hex numbers)"
+
+    |s|
+
+    aStream peek == $# ifTrue:[
+        aStream next.
+        s := '#'.
+        [aStream peek isAlphaNumeric] whileTrue:[
+            s := s copyWith:aStream next
+        ].
+        ^ s
+    ].
+    ^ aStream upTo:$"
+!
+
+fromFile:aFileName
+    "read an XPM-image from aFileName. return the receiver (with all
+     relevant instance variables set for the image) or nil on error"
+
+    |line 
+     srcIndex "{ Class: SmallInteger }"
+     dstIndex "{ Class: SmallInteger }"
+     colorName colorMapSize redMap greenMap blueMap
+     charsPerPixel xlation s bitsPerPixel char lineDone|
+
+    inStream := self class streamReadingFile:aFileName.
+    inStream isNil ifTrue:[
+        'XPM: file open error' errorPrintNL.
+        ^ nil
+    ].
+
+    line := inStream nextLine.
+    (line notNil and:[line startsWith:'/* XPM']) ifFalse:[
+        'XPM: format error (expected XPM)' errorPrintNL.
+        inStream close.
+        ^ nil
+    ].
+
+    line := inStream nextLine.
+    [line notNil and:[line startsWith:'/*']] whileTrue:[
+        line := inStream nextLine.
+    ].
+    (line notNil and:[line startsWith:'static char']) ifFalse:[
+        'XPM: format error (expected static char)' errorPrintNL.
+        inStream close.
+        ^ nil
+    ].
+    line := inStream nextLine.
+    [line notNil and:[line startsWith:'/*']] whileTrue:[
+        line := inStream nextLine.
+    ].
+    (line notNil and:[line startsWith:'"']) ifFalse:[
+        'XPM: format error (expected "ww hh nn mm)' errorPrintNL.
+        inStream close.
+        ^ nil
+    ].
+    s := ReadStream on:line.
+    s next.  "skip quote"
+    width := Integer readFrom:s.
+    height := Integer readFrom:s.
+    colorMapSize := Integer readFrom:s.
+    charsPerPixel := Integer readFrom:s.
+    charsPerPixel ~~ 1 ifTrue:[
+        'XPM: can only handle single-character xpm-files' errorPrintNL.
+        ^ nil
+    ].
+    xlation := Array new:256.
+
+    redMap := Array new:colorMapSize.
+    greenMap := Array new:colorMapSize.
+    blueMap := Array new:colorMapSize.
+    colorMap := Array with:redMap with:greenMap with:blueMap.
+
+    1 to:colorMapSize do:[:colorIndex |
+        |index line color|
+
+        line := inStream nextLine.
+        [line notNil and:[line startsWith:'/*']] whileTrue:[
+            line := inStream nextLine.
+        ].
+        (line notNil and:[line startsWith:'"']) ifFalse:[
+            'XPM: format error (expected color spec)' errorPrintNL.
+            inStream close.
+            ^ nil
+        ].
+        s := ReadStream on:line.
+        s next. "skip quote"
+        index := s next asciiValue.
+        xlation at:index put:colorIndex - 1.
+
+        lineDone := false.
+        [lineDone] whileFalse:[
+            s skipSeparators.
+            char := s peek.
+            char == $" ifTrue:[
+                lineDone := true
+            ] ifFalse:[
+                char == $s ifTrue:[
+                    "
+                     symbolic name
+                    "
+                    s next.
+                    s skipSeparators.
+                    s nextWord.    
+                    s skipSeparators.
+                ] ifFalse:[
+                    char == $m ifTrue:[
+                        "
+                         monochrome data
+                        "
+                        s next.
+                        s skipSeparators.
+                        s nextWord.
+                        s skipSeparators.
+                    ] ifFalse:[
+                        (char == $g) ifTrue:[
+                            "
+                             greyscale data
+                            "
+                            s next.
+                            s peek == 4 ifTrue:[s next].
+                            s skipSeparators.
+                            s nextWord.
+                            s skipSeparators.
+                        ] ifFalse:[
+                            (char == $c) ifTrue:[
+                                "
+                                 color data
+                                "
+                                s next.
+                                s skipSeparators.
+                                colorName := self colorNameFrom:s.
+                                s skipSeparators.
+                            ] ifFalse:[
+                                'XPM: expected ''c'',''m'',''g'' or ''s''' errorPrintNL.
+                                s next.
+                            ].
+                        ]
+                    ]
+                ]
+            ].
+        ].
+        ((colorName = 'none') or:[colorName = 'None']) ifTrue:[
+            "mhmh must add mask to Image-instances soon ..."
+            color := Color white
+        ] ifFalse:[
+            color := Color name:colorName.
+        ].
+        redMap at:colorIndex put:(color red * 255 // 100).
+        greenMap at:colorIndex put:(color green * 255 // 100).
+        blueMap at:colorIndex put:(color blue * 255 // 100).
+    ].
+
+    "actually, could make it an image with less depth most of the time ..."
+
+"
+    bitsPerPixel := ((colorMapSize - 1) log:2) truncated + 1.
+"
+    bitsPerPixel := 8.
+    data := ByteArray new:(width * height).
+
+    dstIndex := 1.
+    1 to:height do:[:row |
+        line := inStream nextLine withoutSpaces.
+        [line notNil and:[line startsWith:'/*']] whileTrue:[
+            line := inStream nextLine withoutSpaces.
+        ].
+        (line notNil and:[line startsWith:'"']) ifFalse:[
+            'XPM: format error (expected pixels)' errorPrintNL.
+            inStream close.
+            ^ nil
+        ].
+        srcIndex := 2.
+        1 to: width do:[:col |
+            |char|
+
+            char := line at:srcIndex.
+            data at:dstIndex put:(xlation at:char asciiValue).
+            srcIndex := srcIndex + 1.
+            dstIndex := dstIndex + 1
+        ]
+    ].
+
+    photometric := #palette.
+    samplesPerPixel := 1.
+    bitsPerSample := Array with:bitsPerPixel.
+
+    "XPMReader fromFile:'bitmaps/magtape.xpm'" 
+    "XPMReader fromFile:'bitmaps/pixmap.xpm'" 
+    "XPMReader fromFile:'bitmaps/ljet.xpm'" 
+! !