*** empty log message ***
authorClaus Gittinger <cg@exept.de>
Tue, 21 Oct 1997 20:27:06 +0200
changeset 713 548898fdd1dc
parent 712 6403dd3407eb
child 714 c89f5c12538c
*** empty log message ***
AppModel.st
ApplicationModel.st
GIFReader.st
MIMETypes.st
Make.proto
PBMReader.st
SimpleDialog.st
WinIconRdr.st
WindowsIconReader.st
--- a/AppModel.st	Wed Oct 15 19:58:09 1997 +0200
+++ b/AppModel.st	Tue Oct 21 20:27:06 1997 +0200
@@ -10,6 +10,8 @@
  hereby transferred.
 "
 
+'From Smalltalk/X, Version:3.2.1 on 18-oct-1997 at 4:25:23 pm'                  !
+
 Model subclass:#ApplicationModel
 	instanceVariableNames:'builder resources device masterApplication'
 	classVariableNames:'DefaultLabels DefaultVisuals'
@@ -918,18 +920,18 @@
             1) nil                  in which case no interest is registered
             2) a selector           in which case the receiver is understood to be self
             3) an Array             in which case the size is two where the first element is the
-                                            message to be sent and the second element is the receiver."
+                                    message to be sent and the second element is the receiver."
 
     aSelectorOrArray isNil ifTrue: [^ aValueModel].
 
-    (aSelectorOrArray isKindOf:Array) ifTrue:[
+    (aSelectorOrArray isArray) ifTrue:[
         aValueModel onChangeSend:(aSelectorOrArray at: 1) to:(aSelectorOrArray at: 2)
     ] ifFalse: [
         aValueModel onChangeSend:aSelectorOrArray to:self
     ].
     ^aValueModel
 
-
+    "Modified: 18.10.1997 / 15:05:58 / cg"
 !
 
 valueHolderFor:aSelector initialValue:anObject
@@ -947,11 +949,12 @@
      to be the reciever.  If it is an Array, then the first element is the change message and 
      the second element is the interested object. " 
 
-    (self builder bindings includesKey:aSelector) ifFalse:[
+    (builder bindings includesKey:aSelector) ifFalse:[
         ^ self registerInterestIn:(ValueHolder with:anObject) using:aSelectorOrArray
     ].
-    ^ self builder aspectAt:aSelector
+    ^ builder aspectAt:aSelector
 
+    "Modified: 18.10.1997 / 15:41:13 / cg"
 ! !
 
 !ApplicationModel methodsFor:'initialization'!
@@ -1486,6 +1489,6 @@
 !ApplicationModel class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview2/Attic/AppModel.st,v 1.60 1997-10-15 16:07:03 ca Exp $'
+    ^ '$Header: /cvs/stx/stx/libview2/Attic/AppModel.st,v 1.61 1997-10-21 18:26:38 cg Exp $'
 ! !
 ApplicationModel initialize!
--- a/ApplicationModel.st	Wed Oct 15 19:58:09 1997 +0200
+++ b/ApplicationModel.st	Tue Oct 21 20:27:06 1997 +0200
@@ -10,6 +10,8 @@
  hereby transferred.
 "
 
+'From Smalltalk/X, Version:3.2.1 on 18-oct-1997 at 4:25:23 pm'                  !
+
 Model subclass:#ApplicationModel
 	instanceVariableNames:'builder resources device masterApplication'
 	classVariableNames:'DefaultLabels DefaultVisuals'
@@ -918,18 +920,18 @@
             1) nil                  in which case no interest is registered
             2) a selector           in which case the receiver is understood to be self
             3) an Array             in which case the size is two where the first element is the
-                                            message to be sent and the second element is the receiver."
+                                    message to be sent and the second element is the receiver."
 
     aSelectorOrArray isNil ifTrue: [^ aValueModel].
 
-    (aSelectorOrArray isKindOf:Array) ifTrue:[
+    (aSelectorOrArray isArray) ifTrue:[
         aValueModel onChangeSend:(aSelectorOrArray at: 1) to:(aSelectorOrArray at: 2)
     ] ifFalse: [
         aValueModel onChangeSend:aSelectorOrArray to:self
     ].
     ^aValueModel
 
-
+    "Modified: 18.10.1997 / 15:05:58 / cg"
 !
 
 valueHolderFor:aSelector initialValue:anObject
@@ -947,11 +949,12 @@
      to be the reciever.  If it is an Array, then the first element is the change message and 
      the second element is the interested object. " 
 
-    (self builder bindings includesKey:aSelector) ifFalse:[
+    (builder bindings includesKey:aSelector) ifFalse:[
         ^ self registerInterestIn:(ValueHolder with:anObject) using:aSelectorOrArray
     ].
-    ^ self builder aspectAt:aSelector
+    ^ builder aspectAt:aSelector
 
+    "Modified: 18.10.1997 / 15:41:13 / cg"
 ! !
 
 !ApplicationModel methodsFor:'initialization'!
@@ -1486,6 +1489,6 @@
 !ApplicationModel class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview2/ApplicationModel.st,v 1.60 1997-10-15 16:07:03 ca Exp $'
+    ^ '$Header: /cvs/stx/stx/libview2/ApplicationModel.st,v 1.61 1997-10-21 18:26:38 cg Exp $'
 ! !
 ApplicationModel initialize!
--- a/GIFReader.st	Wed Oct 15 19:58:09 1997 +0200
+++ b/GIFReader.st	Tue Oct 21 20:27:06 1997 +0200
@@ -10,6 +10,8 @@
  hereby transferred.
 "
 
+'From Smalltalk/X, Version:3.2.1 on 21-oct-1997 at 5:07:17 pm'                  !
+
 ImageReader subclass:#GIFReader
 	instanceVariableNames:'redMap greenMap blueMap pass xpos ypos rowByteSize remainBitCount
 		bufByte bufStream prefixTable suffixTable clearCode eoiCode
@@ -84,6 +86,15 @@
 
 !GIFReader class methodsFor:'testing'!
 
+canRepresent:anImage
+    "return true, if anImage can be represented in my file format.
+     GIF supports depth 8 images only."
+
+    ^ anImage depth == 8
+
+    "Created: 17.10.1997 / 20:19:20 / cg"
+!
+
 isValidImageFile:aFileName
     "return true, if aFileName contains a GIF image"
 
@@ -804,27 +815,42 @@
     outStream nextPut:0.   "/ background (not used)
     outStream nextPut:0.   "/ aspect ratio
 
-    n := 0.
-    image colorMap notNil ifTrue:[
-        image colorMap do:[:clr |
-            |red green blue|
+    0 to:(1 bitShift:bitsPerPixel)-1 do:[:pixel |
+        |clr red green blue|
 
-            clr isNil ifTrue:[
-                "/ unused colorMap slot
-                red := green := blue := 0.
-            ] ifFalse:[
-                red := (clr redByte).
-                green := (clr greenByte).
-                blue := (clr blueByte).
-            ].
-            outStream
-                nextPut:red; nextPut:green; nextPut:blue.
-            n := n + 1.
-        ]
-    ].
-    n+1 to:(1 bitShift:bitsPerPixel) do:[:i |
-        outStream nextPut:0; nextPut:0; nextPut:0
-    ].
+        clr := image colorFromValue:pixel.
+        clr isNil ifTrue:[
+            "/ unused colorMap slot
+            red := green := blue := 0.
+        ] ifFalse:[
+            red := (clr redByte).
+            green := (clr greenByte).
+            blue := (clr blueByte).
+        ].
+        outStream
+            nextPut:red; nextPut:green; nextPut:blue.
+    ].    
+"/    n := 0.
+"/    image colorMap notNil ifTrue:[
+"/        image colorMap do:[:clr |
+"/            |red green blue|
+"/
+"/            clr isNil ifTrue:[
+"/                "/ unused colorMap slot
+"/                red := green := blue := 0.
+"/            ] ifFalse:[
+"/                red := (clr redByte).
+"/                green := (clr greenByte).
+"/                blue := (clr blueByte).
+"/            ].
+"/            outStream
+"/                nextPut:red; nextPut:green; nextPut:blue.
+"/            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.       "/
@@ -839,12 +865,12 @@
     outStream nextPut:t1       "/ another flag
 
     "Created: 14.10.1997 / 17:41:28 / cg"
-    "Modified: 15.10.1997 / 19:54:30 / cg"
+    "Modified: 21.10.1997 / 04:52:18 / cg"
 ! !
 
 !GIFReader class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview2/GIFReader.st,v 1.59 1997-10-15 17:58:09 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libview2/GIFReader.st,v 1.60 1997-10-21 18:26:40 cg Exp $'
 ! !
 GIFReader initialize!
--- a/MIMETypes.st	Wed Oct 15 19:58:09 1997 +0200
+++ b/MIMETypes.st	Tue Oct 21 20:27:06 1997 +0200
@@ -53,45 +53,55 @@
 initialize
     "initialize wellKnown facts"
 
-    TypeToImageReaderClassMapping isNil ifTrue:[TypeToImageReaderClassMapping := Dictionary new].
-    TypeToImageReaderClassMapping at:'image/jpeg' put:JPEGReader.
-    TypeToImageReaderClassMapping at:'image/gif'  put:GIFReader.
-    TypeToImageReaderClassMapping at:'image/tiff' put:TIFFReader.
+    |t|
+
+    (t := TypeToImageReaderClassMapping) isNil ifTrue:[
+	TypeToImageReaderClassMapping := t := Dictionary new
+    ].
+    t at:'image/jpeg' put:JPEGReader.
+    t at:'image/gif'  put:GIFReader.
+    t at:'image/tiff' put:TIFFReader.
 
-    FileSuffixToTypeMapping isNil ifTrue:[FileSuffixToTypeMapping := Dictionary new].
-    FileSuffixToTypeMapping at:'jpg' put:'image/jpeg'.
-    FileSuffixToTypeMapping at:'gif' put:'image/gif'.
-    FileSuffixToTypeMapping at:'tif' put:'image/tiff'.
+    (t := FileSuffixToTypeMapping) isNil ifTrue:[
+	FileSuffixToTypeMapping := t := Dictionary new
+    ].
+    t at:'jpg' put:'image/jpeg'.
+    t at:'gif' put:'image/gif'.
+    t at:'tif' put:'image/tiff'.
 
-    FileSuffixToTypeMapping at:'htm'  put:'text/html'.
-    FileSuffixToTypeMapping at:'html' put:'text/html'.
-    FileSuffixToTypeMapping at:'ps'   put:'application/postscript'.
-
-    FileSuffixToImageReaderClassMapping isNil ifTrue:[FileSuffixToImageReaderClassMapping := Dictionary new].
-    FileSuffixToImageReaderClassMapping at:'jpg'  put:JPEGReader.
-    FileSuffixToImageReaderClassMapping at:'gif'  put:GIFReader.
-    FileSuffixToImageReaderClassMapping at:'tif'  put:TIFFReader.
+    t at:'htm'  put:'text/html'.
+    t at:'html' put:'text/html'.
+    t at:'ps'   put:'application/postscript'.
 
-    CharSetToFontMapping isNil ifTrue:[CharSetToFontMapping := Dictionary new].
-    CharSetToFontMapping at:'iso2022-jp'   put:'jis*0208*'.
-    CharSetToFontMapping at:'x-iso2022-jp' put:'jis*0208*'.
-    CharSetToFontMapping at:'x-euc-jp'     put:'jis*0208*'.
-    CharSetToFontMapping at:'x-shift-jis'  put:'jis*0208*'.
-    CharSetToFontMapping at:'x-sjis'       put:'jis*0208*'.
-    CharSetToFontMapping at:'x-jis7'       put:'jis*0208*'.
-    CharSetToFontMapping at:'jis7'         put:'jis*0208*'.
-    CharSetToFontMapping at:'euc'          put:'jis*0208*'.
-    CharSetToFontMapping at:'euc-jp'       put:'jis*0208*'.
-    CharSetToFontMapping at:'sjis'         put:'jis*0208*'.
+    (t := FileSuffixToImageReaderClassMapping) isNil ifTrue:[
+	FileSuffixToImageReaderClassMapping := t := Dictionary new
+    ].
+    t at:'jpg'  put:JPEGReader.
+    t at:'gif'  put:GIFReader.
+    t at:'tif'  put:TIFFReader.
 
-    CharSetToFontMapping at:'big5'        put:'big5*'.
+    (t := CharSetToFontMapping) isNil ifTrue:[
+	CharSetToFontMapping := t := Dictionary new
+    ].
+    t at:'iso2022-jp'   put:'jis*0208*'.
+    t at:'x-iso2022-jp' put:'jis*0208*'.
+    t at:'x-euc-jp'     put:'jis*0208*'.
+    t at:'x-shift-jis'  put:'jis*0208*'.
+    t at:'x-sjis'       put:'jis*0208*'.
+    t at:'x-jis7'       put:'jis*0208*'.
+    t at:'jis7'         put:'jis*0208*'.
+    t at:'euc'          put:'jis*0208*'.
+    t at:'euc-jp'       put:'jis*0208*'.
+    t at:'sjis'         put:'jis*0208*'.
 
-    CharSetToFontMapping at:'gb2312'      put:'gb*'.
-    CharSetToFontMapping at:'hz-gb-2312'  put:'gb*'.
-    CharSetToFontMapping at:'x-gbk'       put:'gb*'.
+    t at:'big5'        put:'big5*'.
 
-    CharSetToFontMapping at:'iso2022-kr'  put:'ksc*'.
-    CharSetToFontMapping at:'x-euc-kr'    put:'ksc*'.
+    t at:'gb2312'      put:'gb*'.
+    t at:'hz-gb-2312'  put:'gb*'.
+    t at:'x-gbk'       put:'gb*'.
+
+    t at:'iso2022-kr'  put:'ksc*'.
+    t at:'x-euc-kr'    put:'ksc*'.
 
     "
      self initialize
@@ -219,6 +229,6 @@
 !MIMETypes class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview2/MIMETypes.st,v 1.9 1997-07-16 11:54:25 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libview2/MIMETypes.st,v 1.10 1997-10-21 18:26:41 cg Exp $'
 ! !
 MIMETypes initialize!
--- a/Make.proto	Wed Oct 15 19:58:09 1997 +0200
+++ b/Make.proto	Tue Oct 21 20:27:06 1997 +0200
@@ -1,4 +1,4 @@
-# $Header: /cvs/stx/stx/libview2/Make.proto,v 1.41 1997-09-20 22:19:47 cg Exp $
+# $Header: /cvs/stx/stx/libview2/Make.proto,v 1.42 1997-10-21 18:27:03 cg Exp $
 #
 # -------------- no need to change anything below ----------
 
@@ -23,21 +23,8 @@
 
 #
 # less frequently used/needed
-# if you want them included, uncomment the next lines:
+# these are compiled with +optSpace
 #
-xxAUTOLOADEDOBJS= \
-	  SunReader.$(O)                                \
-	  WinIconRdr.$(O)                               \
-	  PBMReader.$(O)                                \
-	  PCXReader.$(O)                                \
-	  XWDReader.$(O)                                \
-	  STFormRdr.$(O)                                \
-	  TargaReader.$(O)                              \
-	  FaceReader.$(O)                               \
-	  BlitImgRdr.$(O)                               \
-	  JPEGReader.$(O)                               \
-	  ConvValue.$(O)
-
 UNCRITICALOBJS= \
 	  ClrValue.$(O)                 \
 	  Icon.$(O)                     \
@@ -45,6 +32,7 @@
 	  BlockValue.$(O)               \
 	  PrintConv.$(O)                \
 	  EventListener.$(O)            \
+	  MIMETypes.$(O)                \
 	  ActiveHelp.$(O)               \
 	  ActiveHelpView.$(O)
 
--- a/PBMReader.st	Wed Oct 15 19:58:09 1997 +0200
+++ b/PBMReader.st	Tue Oct 21 20:27:06 1997 +0200
@@ -1,4 +1,4 @@
-'From Smalltalk/X, Version:3.2.1 on 14-oct-1997 at 11:14:37 pm'                 !
+'From Smalltalk/X, Version:3.2.1 on 17-oct-1997 at 9:13:03 pm'                  !
 
 ImageReader subclass:#PBMReader
 	instanceVariableNames:''
@@ -30,6 +30,27 @@
 "
 ! !
 
+!PBMReader class methodsFor:'testing'!
+
+canRepresent:anImage
+    "return true, if anImage can be represented in my file format.
+     Currently, only 1bit B&W, 8bit-grey and 24bit RGB images are supported."
+
+    |depth photometric|
+
+    anImage photometric == #rgb ifTrue:[
+        ^ depth==24
+    ].
+    (depth := anImage depth) == 1 ifTrue:[^ true].
+    depth == 8 ifTrue:[
+        photometric := anImage photometric.
+        ^ (photometric == #blackIs0) or:[photometric == #whiteIs0]
+    ].
+    ^ false
+
+    "Modified: 17.10.1997 / 20:20:52 / cg"
+! !
+
 !PBMReader methodsFor:'reading from file'!
 
 readDepth8PGMStream:aStream 
@@ -69,27 +90,6 @@
     "Modified: 14.10.1997 / 19:44:05 / cg"
 ! !
 
-!PBMReader methodsFor:'testing '!
-
-canRepresent:anImage
-    "return true, if anImage can be represented in my file format.
-     Currently, only 1bit B&W, 8bit-grey and 24bit RGB images are supported."
-
-    |depth photometric|
-
-    anImage photometric == #rgb ifTrue:[
-        ^ depth==24
-    ].
-    (depth := anImage depth) == 1 ifTrue:[^ true].
-    depth == 8 ifTrue:[
-        photometric := anImage photometric.
-        ^ (photometric == #blackIs0) or:[photometric == #whiteIs0]
-    ].
-    ^ false
-
-    "Modified: 14.10.1997 / 20:06:34 / cg"
-! !
-
 !PBMReader methodsFor:'writing to file'!
 
 save:image onFile:aFileName
--- a/SimpleDialog.st	Wed Oct 15 19:58:09 1997 +0200
+++ b/SimpleDialog.st	Tue Oct 21 20:27:06 1997 +0200
@@ -11,6 +11,8 @@
 "
 
 
+'From Smalltalk/X, Version:3.2.1 on 18-oct-1997 at 4:26:08 pm'                  !
+
 ApplicationModel subclass:#SimpleDialog
 	instanceVariableNames:'accept cancel close escapeIsCancel postBuildBlock postOpenBlock
 		preBuildBlock'
@@ -173,6 +175,21 @@
     ^ true
 ! !
 
+!SimpleDialog methodsFor:'forced actions'!
+
+doAccept
+    accept value:true
+
+    "Created: 18.10.1997 / 05:18:09 / cg"
+    "Modified: 18.10.1997 / 05:18:28 / cg"
+!
+
+doCancel
+    cancel value:true
+
+    "Created: 18.10.1997 / 05:18:22 / cg"
+! !
+
 !SimpleDialog methodsFor:'initialization'!
 
 initialize
@@ -224,6 +241,21 @@
 !
 
 openFor:anApplication interface:aSelector withBindings:bindings
+    "open the dialog for some appModel from a given specSymbol;
+     the application must provide an interfaceSpec for that symbol.
+     The bindings argument may provide overwriting bindings for the
+     dialog.
+     Return true if accepted, false if canceled"
+
+    ^ self
+        openFor:anApplication 
+        interfaceSpec:(anApplication class interfaceSpecFor:aSelector)
+        withBindings:bindings
+
+    "Modified: 18.10.1997 / 04:43:13 / cg"
+!
+
+openFor:anApplication interfaceSpec:aSpec withBindings:bindings
     "open the dialog for some appModel from a given spec;
      the bindings argument may provide overwriting bindings for the
      dialog.
@@ -231,10 +263,10 @@
 
     builder addBindings:bindings.
     self source:anApplication.
-    ^ self openFrom:(anApplication class interfaceSpecFor:aSelector)
+    ^ self openFrom:aSpec
 
-    "Created: 28.2.1997 / 14:09:06 / cg"
     "Modified: 28.2.1997 / 16:22:00 / cg"
+    "Created: 18.10.1997 / 04:41:29 / cg"
 !
 
 openFrom:anInterfaceSpec
@@ -248,6 +280,55 @@
     "Modified: 28.2.1997 / 16:40:36 / cg"
 !
 
+postBuildWith:aBuilder
+    "this is sent after the dialogs widgets have been created
+     (but before the dialog is opened).
+     If a postBuildBlock was set, evaluate it here."
+
+    postBuildBlock notNil ifTrue:[
+        postBuildBlock numArgs == 0 ifTrue:[
+            postBuildBlock value
+        ] ifFalse:[
+            postBuildBlock value:aBuilder
+        ]
+    ].
+    super postBuildWith:aBuilder
+
+    "Created: 18.10.1997 / 05:17:12 / cg"
+!
+
+postOpenWith:aBuilder
+    "this is sent after the dialogs main window is opened.
+     If a postOpenBlock was set, evaluate it here."
+
+    postOpenBlock notNil ifTrue:[
+        postOpenBlock numArgs == 0 ifTrue:[
+            postOpenBlock value
+        ] ifFalse:[
+            postOpenBlock value:aBuilder
+        ]
+    ].
+    super postOpenWith:aBuilder
+
+    "Created: 18.10.1997 / 05:15:48 / cg"
+!
+
+preBuildWith:aBuilder
+    "this is sent before the dialogs widgets are created.
+     If a preBuildBlock was set, evaluate it here."
+
+    preBuildBlock notNil ifTrue:[
+        preBuildBlock numArgs == 0 ifTrue:[
+            preBuildBlock value
+        ] ifFalse:[
+            preBuildBlock value:aBuilder
+        ]
+    ].
+    super preBuildWith:aBuilder
+
+    "Created: 18.10.1997 / 15:02:27 / cg"
+!
+
 preOpen
     "arrange for #closeAccept & #closeCancel to be invoked when
      either accept or close is triggered
@@ -272,5 +353,5 @@
 !SimpleDialog class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview2/SimpleDialog.st,v 1.12 1997-07-28 11:19:13 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libview2/SimpleDialog.st,v 1.13 1997-10-21 18:27:05 cg Exp $'
 ! !
--- a/WinIconRdr.st	Wed Oct 15 19:58:09 1997 +0200
+++ b/WinIconRdr.st	Tue Oct 21 20:27:06 1997 +0200
@@ -10,6 +10,8 @@
  hereby transferred.
 "
 
+'From Smalltalk/X, Version:3.2.1 on 21-oct-1997 at 5:07:02 pm'                  !
+
 ImageReader subclass:#WindowsIconReader
 	instanceVariableNames:''
 	classVariableNames:''
@@ -36,7 +38,7 @@
 documentation
 "
     this class provides methods for loading Windows and OS2 icon files.
-    Image writing is not supported.
+    Image writing is only supported for BMP format with depth 1,4,8 and 24 bit images.
 
     The reader tries to figure out which version of BMP/ICO is used.
     It seems to be able to load most formats, but who knows ...
@@ -63,6 +65,15 @@
 
 !WindowsIconReader class methodsFor:'testing'!
 
+canRepresent:anImage
+    "return true, if anImage can be represented in my file format.
+     BMP supports depth 1,4,8 and 24."
+
+    ^ (#(1 4 8 24) includes:anImage depth)
+
+    "Created: 17.10.1997 / 20:18:23 / cg"
+!
+
 isValidImageFile:aFileName
     "return true, if aFileName contains a valid windows bitmap-file image"
 
@@ -113,7 +124,7 @@
 loadBMPWidth:w height:h depth:d compression:c from:aStream into:data
     "helper: load a BMP image"
 
-    |buff idx1 idx2 bytesPerRow|
+    |buff idx fileBytesPerRow imgBytesPerRow|
 
     d == 8 ifTrue:[
         (self class loadBMP8Width:w height:h compression:c from:aStream into:data) ifFalse:[
@@ -144,29 +155,31 @@
         ^ true
     ].
     d == 24 ifTrue:[
-        bytesPerRow := w * 3.
-        ((aStream nextBytes:(h * bytesPerRow) into:data) ~~ (h * bytesPerRow)) ifTrue:[
-            'WinIconReader [warning]: read failed' infoPrintNL.
-            ^ false
+        imgBytesPerRow := w * 3.
+        fileBytesPerRow := imgBytesPerRow.
+        (fileBytesPerRow bitAnd:3) ~~ 0 ifTrue:[
+            fileBytesPerRow := (fileBytesPerRow bitAnd:(3 bitInvert)) + 4.
         ].
+        "/
         "/ stupid - last row comes first
+        "/
+        idx := imgBytesPerRow * (height - 1) + 1.
+        buff := ByteArray uninitializedNew:fileBytesPerRow.
 
-        buff := ByteArray uninitializedNew:bytesPerRow.
-        idx1 := 1.
-        idx2 := 1 + (h-1 * bytesPerRow).
-        [idx1 < idx2] whileTrue:[
-            buff replaceFrom:1 to:bytesPerRow with:data startingAt:idx1.
-            data replaceFrom:idx1 to:(idx1 + bytesPerRow - 1) with:data startingAt:idx2.
-            data replaceFrom:idx2 to:(idx2 + bytesPerRow - 1) with:buff startingAt:1.
-            idx1 := idx1 + bytesPerRow.
-            idx2 := idx2 - bytesPerRow.
+        1 to:height do:[:row |
+            (aStream nextBytes:fileBytesPerRow into:buff) ~~ fileBytesPerRow ifTrue:[
+                'WinIconReader [warning]: read failed' infoPrintNL.
+                ^ false
+            ].
+            data replaceFrom:idx to:idx+imgBytesPerRow-1 with:buff.
+            idx := idx - imgBytesPerRow.
         ].
         ^ true
     ].
     'WinIconReader [warning]: unsupported depth:' infoPrint. d infoPrintNL.
 
     "Created: 17.9.1995 / 18:48:11 / claus"
-    "Modified: 28.1.1997 / 01:46:07 / cg"
+    "Modified: 19.10.1997 / 00:01:56 / cg"
 ! !
 
 !WindowsIconReader methodsFor:'reading from file'!
@@ -665,9 +678,126 @@
     "Modified: 24.4.1997 / 22:03:48 / cg"
 ! !
 
+!WindowsIconReader methodsFor:'writing to file'!
+
+save:image onFile:aFileName
+    "save image as BMP file on aFileName.
+     Only depth 1,4,8 and 24 images can be represented in this format."
+
+    self saveBMP:image onFile:aFileName.
+
+    "Modified: 17.10.1997 / 20:16:53 / cg"
+!
+
+saveBMP:image onFile:fileName 
+    "save image as BMP file on aFileName.
+     Only depth 1,4,8 and 24 images can be represented in this format."
+
+    |depth bhSize biSize biClrUsed biSizeImage bfOffBits rowBytes imgBytesPerRow data srcIndex row|
+
+    depth := image depth.
+    width := image width.
+    height := image height.
+
+    (#(1 4 8 24) includes:depth) ifFalse:[
+        ^ Image cannotRepresentImageSignal 
+            raiseWith:image
+            errorString:('BMP format only supports depths 1,4,8 and 24').
+    ].
+    image mask notNil ifTrue:[
+        Image informationLostQuerySignal
+            raiseWith:image
+            errorString:('BMP format does not support an imageMask').
+    ].
+
+    bhSize := 14.  "# bytes in file header"
+    biSize := 40.  "info header size in bytes" 
+    biClrUsed := (depth >= 24) ifTrue:[0] ifFalse:[1 << depth].  "No. color table entries"
+    bfOffBits := biSize + bhSize + (4*biClrUsed).
+    "/ bmp aligns rows on a longword boundary
+    rowBytes := ((depth min:24) * width + 31 // 32) * 4.
+    biSizeImage := height * rowBytes.
+
+    outStream := fileName asFilename writeStream.
+    outStream binary.
+    byteOrder := #lsb.
+
+    "Write the file header"
+    self writeShort:19778.  "bfType = BM" 
+    self writeLong:(bfOffBits + biSizeImage).  "Entire file size in bytes"
+    self writeLong:0.  "bfReserved" 
+    self writeLong:bfOffBits.  "Offset of bitmap data from start of hdr (and file)"
+
+    "Write the bitmap info header"
+    outStream position: bhSize+1.
+    self writeLong:biSize.  "info header size in bytes" 
+    self writeLong:width.  "biWidth" 
+    self writeLong:height.  "biHeight" 
+    self writeShort:1.  "biPlanes" 
+    self writeShort:(depth min:24).  "biBitCount" 
+    self writeLong:0.  "biCompression" 
+    self writeLong:biSizeImage.  "size of image section in bytes"
+    self writeLong:2800.  "biXPelsPerMeter" 
+    self writeLong:2800.  "biYPelsPerMeter" 
+    self writeLong:biClrUsed.
+    self writeLong:0.  "biClrImportant" 
+    1 to:biClrUsed do:[:i |  "Color map"
+        |clr r g b|
+
+        clr := image colorFromValue:i-1.
+        clr isNil ifTrue:[
+            r := g := b := 0.
+        ] ifFalse:[
+            r := clr redByte.
+            g := clr greenByte.
+            b := clr blueByte.
+        ].
+
+        "/ put B,G,R
+        outStream nextPut:b.
+        outStream nextPut:g.
+        outStream nextPut:r.
+        outStream nextPut:0.
+    ].
+
+    imgBytesPerRow := image bytesPerRow.
+    data := image data.
+
+
+    "/ sorry, must extract rows individually
+    "/ (even if alignment is correct),
+    "/ since BMP saves rows bottom-to-top
+
+    row := ByteArray new:rowBytes.
+
+    srcIndex := 1 + (height * imgBytesPerRow).
+    1 to:height do:[:i |
+        srcIndex := srcIndex - imgBytesPerRow.
+        row replaceFrom:1 to:imgBytesPerRow with:data startingAt:srcIndex.
+        outStream nextPutAll:row.
+    ].
+
+    outStream close.
+
+    "
+     |i|
+
+     i := Image fromFile:'bitmaps/SBrowser.xbm'.
+     WindowsIconReader save:i onFile:'test.bmp'.
+    "
+    "
+     |i|
+
+     i := Image fromFile:'bitmaps/gifImages/garfield.gif'.
+     WindowsIconReader save:i onFile:'test.bmp'.
+    "
+
+    "Modified: 21.10.1997 / 05:02:02 / cg"
+! !
+
 !WindowsIconReader class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview2/Attic/WinIconRdr.st,v 1.36 1997-09-10 21:28:18 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libview2/Attic/WinIconRdr.st,v 1.37 1997-10-21 18:27:06 cg Exp $'
 ! !
 WindowsIconReader initialize!
--- a/WindowsIconReader.st	Wed Oct 15 19:58:09 1997 +0200
+++ b/WindowsIconReader.st	Tue Oct 21 20:27:06 1997 +0200
@@ -10,6 +10,8 @@
  hereby transferred.
 "
 
+'From Smalltalk/X, Version:3.2.1 on 21-oct-1997 at 5:07:02 pm'                  !
+
 ImageReader subclass:#WindowsIconReader
 	instanceVariableNames:''
 	classVariableNames:''
@@ -36,7 +38,7 @@
 documentation
 "
     this class provides methods for loading Windows and OS2 icon files.
-    Image writing is not supported.
+    Image writing is only supported for BMP format with depth 1,4,8 and 24 bit images.
 
     The reader tries to figure out which version of BMP/ICO is used.
     It seems to be able to load most formats, but who knows ...
@@ -63,6 +65,15 @@
 
 !WindowsIconReader class methodsFor:'testing'!
 
+canRepresent:anImage
+    "return true, if anImage can be represented in my file format.
+     BMP supports depth 1,4,8 and 24."
+
+    ^ (#(1 4 8 24) includes:anImage depth)
+
+    "Created: 17.10.1997 / 20:18:23 / cg"
+!
+
 isValidImageFile:aFileName
     "return true, if aFileName contains a valid windows bitmap-file image"
 
@@ -113,7 +124,7 @@
 loadBMPWidth:w height:h depth:d compression:c from:aStream into:data
     "helper: load a BMP image"
 
-    |buff idx1 idx2 bytesPerRow|
+    |buff idx fileBytesPerRow imgBytesPerRow|
 
     d == 8 ifTrue:[
         (self class loadBMP8Width:w height:h compression:c from:aStream into:data) ifFalse:[
@@ -144,29 +155,31 @@
         ^ true
     ].
     d == 24 ifTrue:[
-        bytesPerRow := w * 3.
-        ((aStream nextBytes:(h * bytesPerRow) into:data) ~~ (h * bytesPerRow)) ifTrue:[
-            'WinIconReader [warning]: read failed' infoPrintNL.
-            ^ false
+        imgBytesPerRow := w * 3.
+        fileBytesPerRow := imgBytesPerRow.
+        (fileBytesPerRow bitAnd:3) ~~ 0 ifTrue:[
+            fileBytesPerRow := (fileBytesPerRow bitAnd:(3 bitInvert)) + 4.
         ].
+        "/
         "/ stupid - last row comes first
+        "/
+        idx := imgBytesPerRow * (height - 1) + 1.
+        buff := ByteArray uninitializedNew:fileBytesPerRow.
 
-        buff := ByteArray uninitializedNew:bytesPerRow.
-        idx1 := 1.
-        idx2 := 1 + (h-1 * bytesPerRow).
-        [idx1 < idx2] whileTrue:[
-            buff replaceFrom:1 to:bytesPerRow with:data startingAt:idx1.
-            data replaceFrom:idx1 to:(idx1 + bytesPerRow - 1) with:data startingAt:idx2.
-            data replaceFrom:idx2 to:(idx2 + bytesPerRow - 1) with:buff startingAt:1.
-            idx1 := idx1 + bytesPerRow.
-            idx2 := idx2 - bytesPerRow.
+        1 to:height do:[:row |
+            (aStream nextBytes:fileBytesPerRow into:buff) ~~ fileBytesPerRow ifTrue:[
+                'WinIconReader [warning]: read failed' infoPrintNL.
+                ^ false
+            ].
+            data replaceFrom:idx to:idx+imgBytesPerRow-1 with:buff.
+            idx := idx - imgBytesPerRow.
         ].
         ^ true
     ].
     'WinIconReader [warning]: unsupported depth:' infoPrint. d infoPrintNL.
 
     "Created: 17.9.1995 / 18:48:11 / claus"
-    "Modified: 28.1.1997 / 01:46:07 / cg"
+    "Modified: 19.10.1997 / 00:01:56 / cg"
 ! !
 
 !WindowsIconReader methodsFor:'reading from file'!
@@ -665,9 +678,126 @@
     "Modified: 24.4.1997 / 22:03:48 / cg"
 ! !
 
+!WindowsIconReader methodsFor:'writing to file'!
+
+save:image onFile:aFileName
+    "save image as BMP file on aFileName.
+     Only depth 1,4,8 and 24 images can be represented in this format."
+
+    self saveBMP:image onFile:aFileName.
+
+    "Modified: 17.10.1997 / 20:16:53 / cg"
+!
+
+saveBMP:image onFile:fileName 
+    "save image as BMP file on aFileName.
+     Only depth 1,4,8 and 24 images can be represented in this format."
+
+    |depth bhSize biSize biClrUsed biSizeImage bfOffBits rowBytes imgBytesPerRow data srcIndex row|
+
+    depth := image depth.
+    width := image width.
+    height := image height.
+
+    (#(1 4 8 24) includes:depth) ifFalse:[
+        ^ Image cannotRepresentImageSignal 
+            raiseWith:image
+            errorString:('BMP format only supports depths 1,4,8 and 24').
+    ].
+    image mask notNil ifTrue:[
+        Image informationLostQuerySignal
+            raiseWith:image
+            errorString:('BMP format does not support an imageMask').
+    ].
+
+    bhSize := 14.  "# bytes in file header"
+    biSize := 40.  "info header size in bytes" 
+    biClrUsed := (depth >= 24) ifTrue:[0] ifFalse:[1 << depth].  "No. color table entries"
+    bfOffBits := biSize + bhSize + (4*biClrUsed).
+    "/ bmp aligns rows on a longword boundary
+    rowBytes := ((depth min:24) * width + 31 // 32) * 4.
+    biSizeImage := height * rowBytes.
+
+    outStream := fileName asFilename writeStream.
+    outStream binary.
+    byteOrder := #lsb.
+
+    "Write the file header"
+    self writeShort:19778.  "bfType = BM" 
+    self writeLong:(bfOffBits + biSizeImage).  "Entire file size in bytes"
+    self writeLong:0.  "bfReserved" 
+    self writeLong:bfOffBits.  "Offset of bitmap data from start of hdr (and file)"
+
+    "Write the bitmap info header"
+    outStream position: bhSize+1.
+    self writeLong:biSize.  "info header size in bytes" 
+    self writeLong:width.  "biWidth" 
+    self writeLong:height.  "biHeight" 
+    self writeShort:1.  "biPlanes" 
+    self writeShort:(depth min:24).  "biBitCount" 
+    self writeLong:0.  "biCompression" 
+    self writeLong:biSizeImage.  "size of image section in bytes"
+    self writeLong:2800.  "biXPelsPerMeter" 
+    self writeLong:2800.  "biYPelsPerMeter" 
+    self writeLong:biClrUsed.
+    self writeLong:0.  "biClrImportant" 
+    1 to:biClrUsed do:[:i |  "Color map"
+        |clr r g b|
+
+        clr := image colorFromValue:i-1.
+        clr isNil ifTrue:[
+            r := g := b := 0.
+        ] ifFalse:[
+            r := clr redByte.
+            g := clr greenByte.
+            b := clr blueByte.
+        ].
+
+        "/ put B,G,R
+        outStream nextPut:b.
+        outStream nextPut:g.
+        outStream nextPut:r.
+        outStream nextPut:0.
+    ].
+
+    imgBytesPerRow := image bytesPerRow.
+    data := image data.
+
+
+    "/ sorry, must extract rows individually
+    "/ (even if alignment is correct),
+    "/ since BMP saves rows bottom-to-top
+
+    row := ByteArray new:rowBytes.
+
+    srcIndex := 1 + (height * imgBytesPerRow).
+    1 to:height do:[:i |
+        srcIndex := srcIndex - imgBytesPerRow.
+        row replaceFrom:1 to:imgBytesPerRow with:data startingAt:srcIndex.
+        outStream nextPutAll:row.
+    ].
+
+    outStream close.
+
+    "
+     |i|
+
+     i := Image fromFile:'bitmaps/SBrowser.xbm'.
+     WindowsIconReader save:i onFile:'test.bmp'.
+    "
+    "
+     |i|
+
+     i := Image fromFile:'bitmaps/gifImages/garfield.gif'.
+     WindowsIconReader save:i onFile:'test.bmp'.
+    "
+
+    "Modified: 21.10.1997 / 05:02:02 / cg"
+! !
+
 !WindowsIconReader class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview2/WindowsIconReader.st,v 1.36 1997-09-10 21:28:18 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libview2/WindowsIconReader.st,v 1.37 1997-10-21 18:27:06 cg Exp $'
 ! !
 WindowsIconReader initialize!