#FEATURE
authorClaus Gittinger <cg@exept.de>
Fri, 04 Mar 2016 19:12:00 +0100
changeset 3578 6bd3a34492f9
parent 3576 2bf0d46c19d4
child 3579 94a3b7222275
#FEATURE class: WindowsIconReader added: #loadRLECompressedBMP4From:into: changed: #loadBMPWidth:height:bytesPerPixel:from:into: #loadBMPWidth:height:depth:from:into: compression 3 (16/24 bit) and RLE4 compression.
WindowsIconReader.st
--- a/WindowsIconReader.st	Wed Mar 02 14:25:19 2016 +0100
+++ b/WindowsIconReader.st	Fri Mar 04 19:12:00 2016 +0100
@@ -1,5 +1,3 @@
-"{ Encoding: utf8 }"
-
 "
  COPYRIGHT (c) 1993 by Claus Gittinger
 	      All Rights Reserved
@@ -352,27 +350,32 @@
 
     align := 4.
 
-    compression == 0 ifTrue:[
-	imgBytesPerRow := w * bpp.
-	fileBytesPerRow := imgBytesPerRow.
-	(fileBytesPerRow bitAnd:(align-1)) ~~ 0 ifTrue:[
-	    fileBytesPerRow := (fileBytesPerRow bitAnd:((align-1) bitInvert)) + align.
-	].
-	"/
-	"/ stupid - last row comes first
-	"/
-	idx := imgBytesPerRow * (h - 1) + 1.
-	buff := ByteArray uninitializedNew:fileBytesPerRow.
+    ((compression == 0) or:[compression == 3]) ifTrue:[
+        imgBytesPerRow := w * bpp.
+        fileBytesPerRow := imgBytesPerRow.
+        (fileBytesPerRow bitAnd:(align-1)) ~~ 0 ifTrue:[
+            fileBytesPerRow := (fileBytesPerRow bitAnd:((align-1) bitInvert)) + align.
+        ].
+        "/
+        "/ stupid - last row comes first
+        "/
+        idx := imgBytesPerRow * (h - 1) + 1.
+        buff := ByteArray uninitializedNew:fileBytesPerRow.
 
-	1 to:h do:[:row |
-	    (aStream nextBytes:fileBytesPerRow into:buff) ~~ fileBytesPerRow ifTrue:[
-		^ false
-	    ].
-	    data replaceFrom:idx to:idx+imgBytesPerRow-1 with:buff.
-	    idx := idx - imgBytesPerRow.
-	].
-	^ true
+        1 to:h do:[:row |
+            (aStream nextBytes:fileBytesPerRow into:buff) == fileBytesPerRow ifFalse:[
+                ^ false
+            ].
+            data replaceFrom:idx to:idx+imgBytesPerRow-1 with:buff.
+            idx := idx - imgBytesPerRow.
+        ].
+        compression == 3 ifTrue:[
+            self breakPoint:#cg. "/ TODO: check what we have to do here...
+        ].    
+        ^ true
     ].
+    "/ 'BMPReader: unsupported compression: ' infoPrint. compression infoPrintCR. 
+    self fileFormatError:('unsupported compression:', compression printString).
     ^ false.
 !
 
@@ -386,7 +389,8 @@
         compression == 1 ifTrue:[
             ^ self loadRLECompressedBMP8From:aStream into:data.
         ].
-        self breakPoint:#cg info:'unhandled compression'.
+        "/ self breakPoint:#cg info:'unhandled compression'.
+        self fileFormatError:('unsupported compression:', compression printString).
         ^ false
     ].
     d == 4 ifTrue:[
@@ -415,12 +419,89 @@
 
         ^ true
     ].
+    self fileFormatError:('unsupported depth:', d printString).
     ^ false
 
     "Created: / 17.9.1995 / 18:48:11 / claus"
     "Modified: / 3.2.1998 / 20:21:16 / cg"
 !
 
+loadRLECompressedBMP4From:aStream into:aByteArray
+    "load bmp-rle-4 pixel imagedata"
+
+    |bytesPerRowInData x y dstIndex lineStartIndex cnt pair clr1 clr2 code n nbyte|
+
+    bytesPerRowInData := self bytesPerRow.
+    x := 0.
+    y := height - 1.
+    lineStartIndex := (y * bytesPerRowInData) + 1.
+    dstIndex := lineStartIndex.
+
+    [ y < height ] whileTrue:[
+        cnt := aStream nextByte.
+        pair := aStream nextByte.
+        cnt ~~ 0 ifTrue:[
+            clr1 := pair bitShift:-4.
+            clr2 := pair bitAnd:16rF.
+            [cnt > 1] whileTrue:[
+                aByteArray at:dstIndex put:((clr2 << 4) bitOr:clr1).
+                dstIndex := dstIndex + 1.
+                cnt := cnt - 2.
+                x := x + 2.
+            ].
+            (cnt > 0) ifTrue:[
+                "/ got odd count
+                aByteArray at:dstIndex put:clr1.
+                x := x + 1.
+                self halt.
+            ].    
+        ] ifFalse:[
+            "/ cnt == 0: escape codes */
+            code := pair.
+            code == 0 ifTrue:[
+                "/ end of line
+                x := 0.
+                y := y - 1.
+                lineStartIndex := lineStartIndex - bytesPerRowInData.
+                dstIndex := lineStartIndex.
+            ] ifFalse:[
+                code == 1 ifTrue:[
+                    "/ end of pic
+                    ^ true
+                ].
+                code == 2 ifTrue:[
+                    "/ delta
+                    x := x + aStream nextSignedByte.
+                    y := y - aStream nextSignedByte.
+                    lineStartIndex := (y * bytesPerRowInData) + 1.
+                    dstIndex := lineStartIndex + x.
+                ] ifFalse:[
+                    "/ absolute; cnt pixels coming
+                    cnt := code.
+                    nbyte := cnt // 2.
+                    n := aStream nextBytes:nbyte into:aByteArray startingAt:dstIndex.
+                    n ~~ nbyte ifTrue:[^ false].
+                    dstIndex := dstIndex + nbyte.
+                    x := x + cnt.
+                    
+                    cnt odd ifTrue:[
+                        clr1 := aStream nextByte.
+                        aByteArray at:dstIndex put:clr1.
+                        x := x + 1.
+                        self halt.
+                    ].
+                    
+                    "/ odd count - padd
+                    nbyte odd ifTrue:[
+                        aStream skip:1.
+                    ].
+                ].
+            ].
+        ].
+    ].
+    ^ true.
+!
+
 loadRLECompressedBMP8From:aStream into:aByteArray
     "load bmp-8 bit per pixel imagedata"