PNGReader.st
branchjv
changeset 3619 80c85dc20c32
parent 3603 f961a8175037
parent 3612 0784a518d8f4
child 3642 79f73b8182e2
--- a/PNGReader.st	Thu Mar 24 07:06:00 2016 +0100
+++ b/PNGReader.st	Sat Mar 26 08:00:39 2016 +0000
@@ -1,5 +1,3 @@
-"{ Encoding: utf8 }"
-
 "
  COPYRIGHT (c) 1996 by Claus Gittinger
               All Rights Reserved
@@ -253,8 +251,17 @@
 processInterlacedGlobalDATA
     "adam7 interlace method"
 
-    | zlibReader filter bytesPerPass startingCol colIncrement rowIncrement 
-      startingRow cx sc temp "filtersSeen" bitsPerPixel cy|
+    | zlibReader filter 
+      bytesPerPass startingCol colIncrement rowIncrement 
+      startingRow 
+      temp "filtersSeen"  
+      cx       "{ Class: SmallInteger }"
+      sc       "{ Class: SmallInteger }"
+      cy       "{ Class: SmallInteger }"
+      startRow "{ Class: SmallInteger }"
+      w        "{ Class: SmallInteger }"
+      h        "{ Class: SmallInteger }"
+    |
 
     interlaceMode == 1 ifFalse: [
         self error:'unsupported interlaced mode'.
@@ -270,17 +277,19 @@
 
     zlibReader := ZipStream readOpenAsZipStreamOn:(globalDataChunk readStream) suppressHeaderAndChecksum:false.
     zlibReader binary.
-    bitsPerPixel := self bitsPerPixel.
 
+    h := height.
+    w := width.
     1 to: 7 do: [:pass |
         (self doPass: pass) ifTrue:[
             cx := colIncrement at: pass.
             sc := startingCol at: pass.
             cy := rowIncrement at: pass.
-            bytesPerPass := (((width - sc + cx - 1) // cx * bitsPerPixel) + 7) // 8.
+            bytesPerPass := (((w - sc + cx - 1) // cx * depth) + 7) // 8.
             prevScanline := ByteArray new: bytesPerPass.
             thisScanline := ByteArray new: bytesPerScanline.
-            (startingRow at: pass) to: height - 1 by: cy do: [:y |
+            startRow := startingRow at: pass.
+            startRow to: h-1 by: cy do: [:y |
                 filter := zlibReader nextByte.
                 "/ filtersSeen add: filter.
                 (filter isNil or: [(filter between: 0 and: 4) not])
@@ -470,7 +479,31 @@
     
     |delta|
 
-    delta := self bitsPerPixel // 8 max:1.
+%{
+    if (__isByteArray(__INST(thisScanline))
+     && __isByteArray(__INST(prevScanline))
+     && __isSmallInteger(__INST(depth))
+     && __isSmallInteger(count)) {
+        unsigned char *__thisScanline = __byteArrayVal(__INST(thisScanline));
+        unsigned int __sz_this = __byteArraySize(__INST(thisScanline));
+        unsigned char *__prevScanline = __byteArrayVal(__INST(prevScanline));
+        unsigned int __sz_prev = __byteArraySize(__INST(prevScanline));
+        INT __count = __intVal(count);
+        INT __delta = __intVal(__INST(depth)) / 8;
+        int __i;
+
+        if (__delta < 1) __delta = 1;
+        for (__i=0; __i<__delta; __i++) {
+            __thisScanline[__i] += (__prevScanline[__i] >> 1);
+        }
+        for (; __i < __count; __i++) {
+            __thisScanline[__i] += ((__prevScanline[__i] + __thisScanline[__i-__delta]) >> 1);
+        }
+        RETURN(self);
+    }
+%}.
+
+    delta := depth // 8 max:1.
     1 to:delta do:[:i | 
         thisScanline at:i put:((thisScanline at:i) + ((prevScanline at:i) // 2) bitAnd:255)
     ].
@@ -486,7 +519,28 @@
 
     |delta|
 
-    delta := self bitsPerPixel // 8 max:1.
+%{
+    if (__isByteArray(__INST(thisScanline))
+     && __isByteArray(__INST(prevScanline))
+     && __isSmallInteger(__INST(depth))
+     && __isSmallInteger(count)) {
+        unsigned char *__thisScanline = __byteArrayVal(__INST(thisScanline));
+        unsigned int __sz_this = __byteArraySize(__INST(thisScanline));
+        unsigned char *__prevScanline = __byteArrayVal(__INST(prevScanline));
+        unsigned int __sz_prev = __byteArraySize(__INST(prevScanline));
+        INT __count = __intVal(count);
+        INT __delta = __intVal(__INST(depth)) / 8;
+        int __i;
+
+        if (__delta < 1) __delta = 1;
+        for (__i = __delta; __i < __count; __i++) {
+            __thisScanline[__i] = __thisScanline[__i] + __thisScanline[__i-__delta];
+        }
+        RETURN(self);
+    }
+%}.
+
+    delta := depth // 8 max:1.
     delta+1 to:count do:[:i|
         thisScanline at:i put:(((thisScanline at:i)+ (thisScanline at:i-delta)) bitAnd:255) 
     ]
@@ -504,7 +558,49 @@
     
     |delta|
 
-    delta := self bitsPerPixel // 8 max:1.
+%{
+    if (__isByteArray(__INST(thisScanline))
+     && __isByteArray(__INST(prevScanline))
+     && __isSmallInteger(__INST(depth))
+     && __isSmallInteger(count)) {
+        unsigned char *__thisScanline = __byteArrayVal(__INST(thisScanline));
+        unsigned int __sz_this = __byteArraySize(__INST(thisScanline));
+        unsigned char *__prevScanline = __byteArrayVal(__INST(prevScanline));
+        unsigned int __sz_prev = __byteArraySize(__INST(prevScanline));
+        INT __count = __intVal(count);
+        INT __delta = __intVal(__INST(depth)) / 8;
+        int __i;
+        
+        if (__delta < 1) __delta = 1;
+        for (__i=0; __i<__delta; __i++) {
+            unsigned int __pix = __thisScanline[__i] + __prevScanline[__i];
+            __thisScanline[__i] = __pix;
+        }
+        for (; __i < __count; __i++) {
+            int __pCenter = __thisScanline[__i];
+            int __pLeft = __thisScanline[__i - __delta];
+            int __pAbove = __prevScanline[__i];
+            int __pAboveLeft = __prevScanline[__i - __delta];
+            int __pa, __pb, __pc;
+            int __p;
+            
+            __pa = (__pAbove - __pAboveLeft); 
+            __pa = __pa < 0 ? -__pa : __pa;
+            __pb = (__pLeft - __pAboveLeft);
+            __pb = __pb < 0 ? -__pb : __pb;
+            __pc = __pLeft + __pAbove - __pAboveLeft - __pAboveLeft;
+            __pc = __pc < 0 ? -__pc : __pc; 
+            if ((__pa <= __pb) && (__pa <= __pc)) __p = __pLeft;
+            else if (__pb <= __pc) __p = __pAbove;
+            else __p = __pAboveLeft;
+            
+            __thisScanline[__i] = __pCenter + __p;
+        }
+        RETURN(self);
+    }
+%}.
+
+    delta := depth // 8 max:1.
     1 to:delta do:[:i | 
         thisScanline 
             at:i
@@ -524,8 +620,10 @@
 !
 
 filterScanline:filterType count:count
+    filterType == 0 ifTrue:[^ self].
+    
     self 
-        perform:(#(filterNone: filterHorizontal: filterVertical: filterAverage: filterPaeth:) at:filterType+1)
+        perform:(#(filterHorizontal: filterVertical: filterAverage: filterPaeth:) at:filterType)
         with:count
 
     "Modified: / 03-05-2011 / 12:13:31 / cg"
@@ -534,6 +632,25 @@
 filterVertical:count 
     "Use the pixel above as a predictor"
     
+%{
+    if (__isByteArray(__INST(thisScanline))
+     && __isByteArray(__INST(prevScanline))
+     && __isSmallInteger(count)) {
+        unsigned char *__thisScanline = __byteArrayVal(__INST(thisScanline));
+        unsigned int __sz_this = __byteArraySize(__INST(thisScanline));
+        unsigned char *__prevScanline = __byteArrayVal(__INST(prevScanline));
+        unsigned int __sz_prev = __byteArraySize(__INST(prevScanline));
+        INT __count = __intVal(count);
+        int __i;
+
+        for (__i=0; __i<__count; __i++) {
+            unsigned int __pix = __thisScanline[__i] + __prevScanline[__i];
+            __thisScanline[__i] = __pix;
+        }
+        RETURN(self);
+    }
+%}.
+
     1 to:count do:[:i | 
         thisScanline 
             at:i
@@ -543,20 +660,20 @@
     "Modified: / 03-05-2011 / 12:14:34 / cg"
 !
 
-paethPredictLeft: a above: b aboveLeft: c
+paethPredictLeft: l above: a aboveLeft: al
     "Predicts the value of a pixel based on nearby pixels, based on Paeth (GG II, 1991)"
 
     | pa pb pc |
 
-    pa := b > c ifTrue: [b - c] ifFalse: [c - b].
-    pb := a > c ifTrue: [a - c] ifFalse: [c - a].
-    pc := a + b - c - c.
+    pa := a > al ifTrue: [a - al] ifFalse: [al - a].
+    pb := l > al ifTrue: [l - al] ifFalse: [al - l].
+    pc := l + a - al - al.
     pc < 0 ifTrue: [
         pc := pc * -1
     ].
-    ((pa <= pb) and: [pa <= pc]) ifTrue: [^ a].
-    (pb <= pc) ifTrue: [^ b].
-    ^ c
+    ((pa <= pb) and: [pa <= pc]) ifTrue: [^ l].
+    (pb <= pc) ifTrue: [^ a].
+    ^ al
 ! !
 
 !PNGReader methodsFor:'private-pixel copy'!
@@ -585,8 +702,17 @@
     "Handle interlaced pixels of supported colorTypes.
      Untested code - please verify"
 
-    |srcIndex srcMask nPixels dstIndex dstMask x 
-     bits bitMask rS lS rowIndex|
+    |srcIndex "{ Class: SmallInteger }"
+     srcMask  "{ Class: SmallInteger }"
+     nPixels  "{ Class: SmallInteger }"
+     dstIndex "{ Class: SmallInteger }"
+     dstMask  "{ Class: SmallInteger }"
+     x        "{ Class: SmallInteger }"
+     bits     "{ Class: SmallInteger }"
+     bitMask  "{ Class: SmallInteger }"
+     rS       "{ Class: SmallInteger }"
+     lS       "{ Class: SmallInteger }"
+     rowIndex "{ Class: SmallInteger }"|
     
     nPixels := width // incX.
     srcIndex := 0. srcMask := 0. x := startX.
@@ -702,7 +828,11 @@
     "Handle interlaced pixels of supported colorTypes.
      Untested code - please verify"
 
-    |srcIndex nPixels dstIndex dstInc bpp|
+    |srcIndex "{ Class: SmallInteger }" 
+     nPixels  "{ Class: SmallInteger }"
+     dstIndex "{ Class: SmallInteger }"
+     dstInc   "{ Class: SmallInteger }"
+     bpp      "{ Class: SmallInteger }"|
 
     bpp := bytesPerScanline // width.
     
@@ -723,7 +853,10 @@
     "Handle interlaced pixels of supported colorTypes.
      Untested code - please verify"
 
-    |srcIndex nPixels dstIndex dstInc|
+    |srcIndex "{ Class: SmallInteger }"
+     nPixels  "{ Class: SmallInteger }"
+     dstIndex "{ Class: SmallInteger }"
+     dstInc   "{ Class: SmallInteger }"|
 
     srcIndex := 1.
     dstIndex := (y * bytesPerScanline) + (startX * 4) + 1.
@@ -783,7 +916,8 @@
     ].
     self reportDimension.
 
-    depth := inStream nextByte.            "/ bits-per-channel
+    bitsPerChannel := inStream nextByte.
+    depth := bitsPerChannel. "/ will be changed by setColorType.
     colorType := inStream nextByte.
 
     compressionMethod := inStream nextByte.
@@ -794,7 +928,7 @@
         'PNGReader: IHDR:' infoPrintCR.
         'PNGReader:   width: ' infoPrint. width infoPrintCR.
         'PNGReader:   height: ' infoPrint. height infoPrintCR.
-        'PNGReader:   depth: ' infoPrint. depth infoPrintCR.
+        'PNGReader:   bitsPerChannel: ' infoPrint. bitsPerChannel infoPrintCR.
         'PNGReader:   colorType: ' infoPrint. colorType infoPrintCR.
         'PNGReader:   compressionMethod: ' infoPrint. compressionMethod infoPrintCR.
         'PNGReader:   filterMethod: ' infoPrint. filterMethod infoPrintCR.
@@ -811,51 +945,56 @@
     pngColorType == 0 ifTrue:[
         photometric := #blackIs0.
         samplesPerPixel := 1.
-        bitsPerSample := Array with:depth.
+        bitsPerSample := Array with:bitsPerChannel.
+        depth := bitsPerChannel.
         ^ true.
     ].
 
     pngColorType == 2 ifTrue:[
-        depth < 8 ifTrue:[
+        bitsPerChannel < 8 ifTrue:[
             'PNGReader: invalid colorType/depth combination' infoPrintCR.
             ^ false.
         ].
         photometric := #rgb.
         samplesPerPixel := 3.
-        bitsPerSample := Array with:depth with:depth with:depth.
+        bitsPerSample := Array with:bitsPerChannel with:bitsPerChannel with:bitsPerChannel.
+        depth := bitsPerChannel * 3.
         ^ true.
     ].
 
     pngColorType == 3 ifTrue:[
-        depth == 16 ifTrue:[
+        bitsPerChannel == 16 ifTrue:[
             'PNGReader: invalid colorType/depth combination' infoPrintCR.
             ^ false.
         ].
         photometric := #palette.
         samplesPerPixel := 1.
-        bitsPerSample := Array with:depth.
+        bitsPerSample := Array with:bitsPerChannel.
+        depth := bitsPerChannel.
         ^ true.
     ].
 
     pngColorType == 4 ifTrue:[
-        depth < 8 ifTrue:[
+        bitsPerChannel < 8 ifTrue:[
             'PNGReader: invalid colorType/depth combination' infoPrintCR.
             ^ false.
         ].
         photometric := #blackIs0.
         samplesPerPixel := 2.
-        bitsPerSample := Array with:depth with:depth.
+        bitsPerSample := Array with:bitsPerChannel with:bitsPerChannel.
+        depth := bitsPerChannel * 2.
         ^ true.
     ].
 
     pngColorType == 6 ifTrue:[
-        depth < 8 ifTrue:[
+        bitsPerChannel < 8 ifTrue:[
             'PNGReader: invalid colorType/depth combination' infoPrintCR.
             ^ false.
         ].
         photometric := #rgba.
         samplesPerPixel := 4.
-        bitsPerSample := Array with:depth with:depth with:depth with:depth.
+        bitsPerSample := Array with:bitsPerChannel with:bitsPerChannel with:bitsPerChannel with:bitsPerChannel.
+        depth := bitsPerChannel * 4.
         ^ true.
     ].