--- a/PNGReader.st Mon Sep 18 09:10:16 2017 +0200
+++ b/PNGReader.st Mon Sep 18 09:10:55 2017 +0200
@@ -17,7 +17,8 @@
instanceVariableNames:'colorType bitsPerChannel compressionMethod filterMethod
interlaceMode bytesPerScanline globalDataChunk thisScanline
prevScanline processTextChunks specialChunkHandlers
- paletteAlphaEntries paletteIndexForMaskedPixels image'
+ paletteAlphaEntries paletteIndexForMaskedPixels image forceRGB
+ depthImage'
classVariableNames:'ColorTypeGray ColorTypeGrayAlpha ColorTypePalette ColorTypeRGB
ColorTypeRGBAlpha Verbose'
poolDictionaries:''
@@ -194,7 +195,7 @@
Leave the image description in instance variables
(i.e. to get the image, ask with image)."
- |header|
+ |header bitsPerSampleOut bytesPerScanlineOut|
inStream := aStream.
aStream binary.
@@ -238,9 +239,39 @@
[self getChunk] whileTrue.
+ "/ kludge: if we get a grey image with alpha,
+ "/ load as rgb+alpha
+ forceRGB := false.
+ depthImage := depth.
+
+ "/ bytesPerScanline is always the in-bytesPerScanline
bytesPerScanline := self bytesPerRow.
- data := ByteArray new:(bytesPerScanline * height).
-
+ bytesPerScanlineOut := bytesPerScanline.
+
+ samplesPerPixel == 2 ifTrue:[
+ photometric == #blackIs0 ifTrue:[
+ depth == 16 ifTrue:[
+ "/ force to r8+g8+b8+a8
+ forceRGB := true.
+ depthImage := 32.
+ bytesPerScanlineOut := width * 4.
+ bitsPerSampleOut := #[8 8 8 8].
+ ] ifFalse:[
+ depth == 32 ifTrue:[
+ "/ force to r8+g8+b8+a8
+ forceRGB := true.
+ depthImage := 32.
+ bytesPerScanlineOut := width * 4.
+ bitsPerSampleOut := #[8 8 8 8].
+ ] ifFalse:[
+ self halt.
+ ].
+ ].
+ ].
+ ].
+
+ data := ByteArray new:(bytesPerScanlineOut * height).
+
globalDataChunk notNil ifTrue:[
self processGlobalIDATChunk.
globalDataChunk := nil.
@@ -260,6 +291,13 @@
self generateMaskFromPaletteAlphaEntries
].
+ forceRGB ifTrue:[
+ depth := depthImage.
+ photometric := #rgba.
+ bitsPerSample := bitsPerSampleOut.
+ samplesPerPixel := 4.
+ ].
+
"
PNGReader fromFile:'/home/cg/libpng-0.89c/pngtest.png'
@@ -268,7 +306,7 @@
"
- "Modified: / 22-02-2017 / 11:00:19 / cg"
+ "Modified: / 17-09-2017 / 15:30:45 / cg"
! !
!PNGReader methodsFor:'reading-private'!
@@ -1359,6 +1397,169 @@
self error:'unsupported depth'.
!
+copyPixelsGrayAlpha:y at:startX by:incX
+ "Handle interlaced pixels of supported colorTypes."
+
+ |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 }"
+ pix alpha gray|
+
+ nPixels := width // incX.
+ srcIndex := 0. srcMask := 0. x := startX.
+
+"/ depth == 1 ifTrue:[
+"/ dstIndex := (y * bytesPerScanline) + (startX // 8) + 1.
+"/ dstMask := 16r80 >> (x \\ 8).
+"/
+"/ 1 to:nPixels do:[:cnt |
+"/ srcMask == 0 ifTrue:[
+"/ srcMask := 16r80.
+"/ srcIndex := srcIndex + 1.
+"/ bits := thisScanline at:srcIndex.
+"/ ].
+"/ bitMask := (bits bitAnd:srcMask) == 0 ifTrue:[0] ifFalse:[dstMask].
+"/ bitMask ~~ 0 ifTrue:[
+"/ data at:dstIndex put:((data at:dstIndex) bitOr:bitMask).
+"/ ].
+"/ x := x + incX.
+"/ dstMask := dstMask >> incX.
+"/ dstMask == 0 ifTrue:[
+"/ dstIndex := dstIndex + 1.
+"/ dstMask := 16r80 >> (x \\ 8).
+"/ ].
+"/ srcMask := srcMask bitShift:-1.
+"/ ].
+"/ ^ self.
+"/ ].
+"/
+"/ depth == 2 ifTrue:[
+"/ dstIndex := (y * bytesPerScanline) + (startX // 4) + 1.
+"/ lS := 6 - ((x \\ 4) * 2).
+"/ rS := -1.
+"/ 1 to:nPixels do:[:cnt |
+"/ rS < 0 ifTrue:[
+"/ srcIndex := srcIndex + 1.
+"/ bits := thisScanline at:srcIndex.
+"/ rS := 6.
+"/ ].
+"/ bitMask := ((bits >> rS) bitAnd:2r11).
+"/ bitMask ~~ 0 ifTrue:[
+"/ bitMask := bitMask << lS.
+"/ data at:dstIndex put:((data at:dstIndex) bitOr:bitMask).
+"/ ].
+"/ lS := lS - (incX * 2).
+"/ lS < 0 ifTrue:[
+"/ lS <= -8 ifTrue:[
+"/ dstIndex := dstIndex + 2.
+"/ lS := lS + 8 + 8.
+"/ ] ifFalse:[
+"/ dstIndex := dstIndex + 1.
+"/ lS := lS + 8.
+"/ ].
+"/ ].
+"/ rS := rS - 2.
+"/ ].
+"/ ^ self.
+"/ ].
+"/
+"/ depth == 4 ifTrue:[
+"/ rowIndex := (y * bytesPerScanline) + 1.
+"/ dstIndex := rowIndex + (x // 2).
+"/ rS := -1.
+"/ 1 to:nPixels do:[:cnt |
+"/ rS < 0 ifTrue:[
+"/ srcIndex := srcIndex + 1.
+"/ bits := thisScanline at:srcIndex.
+"/ rS := 4.
+"/ ].
+"/ bitMask := ((bits >> rS) bitAnd:2r1111).
+"/ x even ifTrue:[
+"/ bitMask := bitMask bitShift:4.
+"/ ].
+"/ data at:dstIndex put:((data at:dstIndex) bitOr:bitMask).
+"/ x := x + incX.
+"/ dstIndex := rowIndex + (x // 2).
+"/ rS := rS - 4.
+"/ ].
+"/ ^ self.
+"/ ].
+"/
+"/ depth == 8 ifTrue:[
+"/ srcIndex := 1.
+"/ dstIndex := (y * bytesPerScanline) + (startX) + 1.
+"/
+"/ 1 to:nPixels do:[:n |
+"/ data at:dstIndex put:(thisScanline at:srcIndex).
+"/ srcIndex := srcIndex + 1.
+"/ dstIndex := dstIndex + incX
+"/ ].
+"/ ^ self.
+"/ ].
+
+ forceRGB ifTrue:[
+ (depth == 16 and:[depthImage == 32]) ifTrue:[
+ "/ converting gray8+alpha8 to r8+g8+b8+alpha8
+
+ srcIndex := 1.
+ dstIndex := (y * (width * 4)) + (startX*4) + 1.
+
+ 1 to:nPixels do:[:n |
+ pix := thisScanline unsignedInt16At:srcIndex.
+ alpha := pix bitAnd:16rFF.
+ gray := (pix rightShift:8) bitAnd:16rFF.
+ "/ put r-g-b-a
+ data at:dstIndex put:gray.
+ data at:dstIndex+1 put:gray.
+ data at:dstIndex+2 put:gray.
+ data at:dstIndex+3 put:alpha.
+
+ srcIndex := srcIndex + 2.
+ dstIndex := dstIndex + (incX * 4)
+ ].
+ ^ self.
+ ].
+ (depth == 32 and:[depthImage == 32]) ifTrue:[
+ "/ converting gray16+alpha16 to r8+g8+b8+alpha8
+
+ srcIndex := 1.
+ dstIndex := (y * (width * 4)) + (startX*4) + 1.
+
+ 1 to:nPixels do:[:n |
+ pix := thisScanline unsignedInt32At:srcIndex.
+
+ alpha := pix bitAnd:16rFFFF.
+ gray := (pix rightShift:16) bitAnd:16rFFFF.
+ "/ reduce to 8 bit
+ alpha := alpha rightShift:8.
+ gray := gray rightShift:8.
+
+ "/ put r-g-b-a
+ data at:dstIndex put:gray.
+ data at:dstIndex+1 put:gray.
+ data at:dstIndex+2 put:gray.
+ data at:dstIndex+3 put:alpha.
+
+ srcIndex := srcIndex + 4.
+ dstIndex := dstIndex + (incX * 4)
+ ].
+ ^ self.
+ ].
+ ].
+ self error:'unsupported depth'.
+
+ "Created: / 17-09-2017 / 14:20:24 / cg"
+ "Modified: / 17-09-2017 / 15:28:38 / cg"
+!
+
copyPixelsIndexed:y at:startX by:incX
self copyPixelsGray:y at:startX by:incX
!