PCXReader.st
changeset 3993 921798977590
parent 3992 b7c4e0a78b6b
child 3994 8ab8729d5dec
--- a/PCXReader.st	Mon Aug 28 13:34:44 2017 +0200
+++ b/PCXReader.st	Mon Aug 28 19:31:18 2017 +0200
@@ -41,6 +41,9 @@
     this class provides methods to load PCX bitmap files.
     PCX used to be a popular image format in the early PC times,
     but became almost obsolete in the meantime.
+    This reader is not tuned and performs slow on non-8bit images;
+    if at all, use it to convert old image files to newer formats,
+    such as png, tiff or jpg.
     
     Due to not having too many examples for testing, 
     this could fail to read some files. 
@@ -162,8 +165,8 @@
 !
 
 readCompressedData
-    |bendIndex rowIndex dstIndex endIndex byte nByte value idx2
-     srcIndex bytesPerPane planeData imageBytesPerRow|
+    |bendIndex rowStartIndex  endIndex byte nByte value idx2
+     srcIndex dstIndex srcRowStartIndex dstRowStartIndex bytesPerPane planeData imageBytesPerRow|
 
     imageBytesPerRow := (((width * depth) + 7) // 8).
     
@@ -175,15 +178,14 @@
     bufferIndex := 1.
     bendIndex := 1.
 
-    
-    rowIndex := 1.
+    rowStartIndex := 1.
     1 to:height do:[:row |
         1 to:nPlanes do:[:planeNr |
-            |dst|
+            |planeBytes|
 
-            dst := planeData at:planeNr.
+            planeBytes := planeData at:planeNr.
             
-            dstIndex := rowIndex.
+            dstIndex := rowStartIndex.
             endIndex := dstIndex + sourceBytesPerRow.
             
             [dstIndex < endIndex] whileTrue:[
@@ -195,7 +197,7 @@
                 byte := buffer at:bufferIndex.
                 bufferIndex := bufferIndex + 1.
                 ((byte bitAnd:2r11000000) ~~ 2r11000000) ifTrue:[
-                    dst at:dstIndex put:byte.
+                    planeBytes at:dstIndex put:byte.
                     dstIndex := dstIndex + 1.
                 ] ifFalse:[
                     nByte := byte bitAnd:2r00111111.
@@ -207,37 +209,89 @@
                     value := buffer at:bufferIndex.
                     bufferIndex := bufferIndex + 1.
                     idx2 := ((dstIndex + nByte) min:endIndex) - 1.
-                    dst from:dstIndex to:idx2 put:value.
+                    planeBytes from:dstIndex to:idx2 put:value.
                     dstIndex := dstIndex + nByte.
                 ].
             ].
         ].
-        "/ rowIndex := rowIndex + endIndex.
-        rowIndex := rowIndex + imageBytesPerRow. "/endIndex.
+        "/ rowStartIndex := endIndex.
+        rowStartIndex := rowStartIndex + imageBytesPerRow.
     ].
     nBuffer := endIndex - bufferIndex.
 
     "/ now merge the planes
     nPlanes > 1 ifTrue:[
         depth == 8 ifTrue:[
-            (nPlanes == 3 or:[nPlanes == 4]) ifTrue:[
+            (nPlanes >= 3) ifTrue:[
                 "/ a simple rgb image
+                nPlanes := nPlanes min:4.
+
                 data := ByteArray uninitializedNew:(nPlanes*width*height).
+                srcRowStartIndex := dstRowStartIndex := 1.
+                1 to:height do:[:y |
+                    1 to:nPlanes do:[:p |
+                        |planeBytes|
+                        
+                        dstIndex := dstRowStartIndex + (p - 1).
+                        srcIndex := srcRowStartIndex.
+                        planeBytes := planeData at:p.
+                        1 to:width do:[:x |
+                            data at:dstIndex put:(planeBytes at:srcIndex).
+                            dstIndex := dstIndex + nPlanes.
+                            srcIndex := srcIndex + 1.
+                        ].    
+                    ].
+                    srcRowStartIndex := srcRowStartIndex + imageBytesPerRow.
+                    dstRowStartIndex := dstRowStartIndex + (width * nPlanes).
+                ].
+            ].
+            depth := nPlanes * 8.
+            photometric := nPlanes==3 ifTrue:[#rgb] ifFalse:[#rgba].
+        ] ifFalse:[
+            (depth == 1) ifTrue:[
+                |newDepth nPlanesUsed|
+
+                nPlanesUsed := nPlanes min:4.
+                newDepth := (nPlanesUsed * depth) nextPowerOf2.
+                
+                data := ByteArray new:((width*height*newDepth)+7)//8.
                 srcIndex := dstIndex := 1.
                 1 to:height do:[:y |
+                    |inMask outBitCount outBits|
+                    
+                    inMask := 16r80.
+                    outBitCount := 0.
+                    outBits := 0.
                     1 to:width do:[:x |
-                        1 to:nPlanes do:[:p |
-                            data at:dstIndex put:((planeData at:p) at:srcIndex).
+                        1 to:nPlanesUsed do:[:p |
+                            outBits := (outBits bitShift:1).
+                            (((planeData at:p) at:srcIndex) bitAnd:inMask) ~~ 0 ifTrue:[
+                                outBits := outBits bitOr:1.
+                            ].
+                        ].
+                        outBits := outBits bitShift:(newDepth-nPlanesUsed).
+                        outBitCount := outBitCount + newDepth.
+                        
+                        outBitCount >= 8 ifTrue:[
+                            data at:dstIndex put:((data at:dstIndex) bitOr:outBits).
                             dstIndex := dstIndex + 1.
-                        ].    
-                        srcIndex := srcIndex + 1.
+                            outBitCount := 0.
+                            outBits := 0.
+                        ].
+                        inMask := inMask rightShift:1.
+                        inMask == 0 ifTrue:[
+                            inMask := 16r80.
+                            srcIndex := srcIndex + 1.
+                        ].
                     ].
                 ].
+                depth := newDepth.
+                "/ rgbi colormap.
+self halt.
+
+            ] ifFalse:[
+                self halt.
             ].
-            depth := nPlanes * depth.
-            photometric := #rgb.
-        ] ifFalse:[
-            self halt.
         ].    
     ].
 
@@ -262,7 +316,7 @@
 "/        ].
 "/    ].
 
-    "Modified: / 28-08-2017 / 13:28:56 / cg"
+    "Modified (format): / 28-08-2017 / 18:01:46 / cg"
 !
 
 readRestAfterHeader
@@ -356,6 +410,22 @@
         self readUncompressedData
     ].
 
+    "/ warning: depth might be changed by readCompressedData
+    depth == 24 ifTrue:[
+        samplesPerPixel := 3.
+        bitsPerSample := #( 8 8 8 ).
+        photometric := #rgb.
+    ] ifFalse:[    
+        depth == 32 ifTrue:[
+            samplesPerPixel := 4.
+            bitsPerSample := #( 8 8 8 8).
+            photometric := #rgba.
+        ] ifFalse:[    
+            samplesPerPixel := 1.
+            bitsPerSample := { depth }.
+        ].
+    ].
+
     photometric == #palette ifTrue:[ 
        (version == 5) ifTrue:[
             true "depth == 8" ifTrue:[
@@ -388,21 +458,13 @@
         ].    
     ].
         
-    depth == 24 ifTrue:[
-        samplesPerPixel := 3.
-        bitsPerSample := #( 8 8 8 ).
-    ] ifFalse:[    
-        samplesPerPixel := 1.
-        bitsPerSample := { depth }.
-    ].
-    
     "
      |i f|
      i := Image fromFile:'somefile.pcx'.
      i inspect.
     "
 
-    "Modified: / 28-08-2017 / 13:30:58 / cg"
+    "Modified: / 28-08-2017 / 15:53:11 / cg"
 !
 
 readUncompressedData