[BUG][FIX] CORRECTED: PNGReadWriter tweaks

Duane Maxwell dmaxwell at entrypoint.com
Thu Apr 27 20:35:20 UTC 2000


Sorry - attached the wrong changeset - correct one attached.
----------------------------------

Change Set:		PNGTweaks
Date:			27 April 2000
Author:			Duane Maxwell/EntryPoint

This is a changeset to Squeak 2.8a #2040.

It deals with a couple of bugs in the PNGReadWriter class.

1) fixes bug with unusual-depth odd-sized non-interlaced indexed images
2) fixes bug with extremely small interlaced images (even Netscape has a
bug here)

With this changeset, all of the non-corrupt images at:
    http://www.cdrom.com/pub/png/pngsuite.html
should be correctly rendered to the degree we support PNG's esoterica.

Note that this page contains three intentionally corrupt images which may
cause walkbalks.
-------------- next part --------------
'From Squeak2.8alpha of 26 April 2000 [latest update: #2040] on 27 April
2000 at 1:28:37 pm'!
"Change Set:		PNGTweaks
Date:			27 April 2000
Author:			Duane Maxwell/EntryPoint

This is a changeset to Squeak 2.8a #2040.

It deals with a couple of bugs in the PNGReadWriter class.

1) fixes bug with unusual-depth odd-sized non-interlaced indexed images
2) fixes bug with extremely small interlaced images (even Netscape has a
bug here)

With this changeset, all of the non-corrupt images at:
    http://www.cdrom.com/pub/png/pngsuite.html
should be correctly rendered to the degree we support PNG's esoterica.

Note that this page contains three intentionally corrupt images which may
cause walkbalks.
"!


!PNGReadWriter methodsFor: 'accessing' stamp: 'DSM 4/27/2000 13:26'!
nextImage

	| length type dataChunk |

	dataChunk _ nil.
	stream reset.
	(stream respondsTo: #binary) ifTrue: [ stream binary] .
	stream skip: 8.
	[stream atEnd] whileFalse: [
		length _ self nextLong.
		type _ self nextLong.
		chunk _ self next: length.
		"crc _" self nextLong. "TODO - validate crc"
		type = IHDR ifTrue: [self processIHDRChunk].
		type = PLTE ifTrue: [self processPLTEChunk].
		type = IDAT ifTrue: [
			"---since the compressed data can span multiple
			chunks, stitch them all together first. later,
			if memory is an issue, we need to figure out how
			to do this on the fly---"
			dataChunk _ dataChunk ifNil: [chunk] ifNotNil:
				[dataChunk,chunk].
		].
	].
	chunk _ dataChunk.
	chunk ifNotNil: [self processIDATChunk].
	^ form
! !

!PNGReadWriter methodsFor: 'chunks' stamp: 'DSM 4/27/2000 13:10'!
processInterlaced
	| z filter bytesPerPass startingCol colIncrement rowIncrement
startingRow cx sc |
	startingCol _ #(0 4 0 2 0 1 0 ).
	colIncrement _ #(8 8 4 4 2 2 1 ).
	rowIncrement _ #(8 8 8 4 4 2 2 ).
	startingRow _ #(0 0 4 0 2 0 1 ).
	z _ ZLibReadStream
				on: chunk
				from: 1
				to: chunk size.
	1 to: 7 do: [:pass |
		(self doPass: pass)
			ifTrue:
				[cx _ colIncrement at: pass.
				sc _ startingCol at: pass.
				bytesPerPass _ width - sc + cx - 1 // cx *
bitsPerPixel + 7 // 8.
				prevScanline _ ByteArray new: bytesPerPass.
				(startingRow at: pass)
					to: height - 1
					by: (rowIncrement at: pass)
					do:
						[:y |
						filter _ z next.
						(filter isNil or: [(filter
between: 0 and: 4) not])
							ifTrue: [^ self].
						thisScanline _ z next:
bytesPerPass.
						self filterScanline: filter
count: bytesPerPass.
						self
							copyPixels: y
							at: sc
							by: cx.
						prevScanline
							replaceFrom: 1
							to: bytesPerPass
							with: thisScanline
							startingAt: 1]]]! !

!PNGReadWriter methodsFor: 'chunks' stamp: 'DSM 4/27/2000 13:27'!
processNonInterlaced
	| z filter |
	z _ ZLibReadStream on: chunk from: 1 to: chunk size.
	prevScanline _ ByteArray new: bytesPerScanline.
	0 to: height-1 do: [ :y |
		filter _ z next.
		(filter isNil or: [(filter between: 0 and: 4) not])
			ifTrue: [^ self].
		thisScanline _ z next: bytesPerScanline.
		self filterScanline: filter count: bytesPerScanline.
		self copyPixels: y.
		prevScanline replaceFrom: 1 to: bytesPerScanline with:
			thisScanline startingAt: 1
		]
! !

!PNGReadWriter methodsFor: 'pixel copies' stamp: 'DSM 4/27/2000 12:34'!
copyPixelsGray: y
	"Handle non-interlaced grayscale color mode (colorType = 0)"
	| blitter pixPerByte mask shifts pixelNumber rawByte pixel |
	blitter _ BitBlt bitPokerToForm: form.
	bitsPerChannel = 16
		ifTrue:
			[0 to: width - 1 do: [:x | blitter pixelAt: x @ y
put: 255 - (thisScanline at: x << 1 + 1)].
			^ self]
		ifFalse:
			[bitsPerChannel = 8
				ifTrue:
					[1 to: width do: [:x | blitter
pixelAt: x - 1 @ y put: (thisScanline at: x)].
					^ self].
			bitsPerChannel = 1
				ifTrue:
					[pixPerByte _ 8.
					mask _ 1.
					shifts _ #(7 6 5 4 3 2 1 0 )].
			bitsPerChannel = 2
				ifTrue:
					[pixPerByte _ 4.
					mask _ 3.
					shifts _ #(6 4 2 0 )].
			bitsPerChannel = 4
				ifTrue:
					[pixPerByte _ 2.
					mask _ 15.
					shifts _ #(4 0 )].
			pixelNumber _ 0.
			0 to: width - 1 do:
				[:x |
				rawByte _ thisScanline at: pixelNumber // pixPerByte + 1.
				pixel _ rawByte >> (shifts at: pixelNumber
\\ pixPerByte + 1) bitAnd: mask.
				blitter pixelAt: x @ y put: pixel.
				pixelNumber _ pixelNumber + 1]]! !

!PNGReadWriter methodsFor: 'pixel copies' stamp: 'DSM 4/27/2000 12:35'!
copyPixelsIndexed: y
	"Handle non-interlaced indexed color mode (colorType = 3)"
	| blitter pixPerByte mask shifts pixelNumber rawByte pixel |
	blitter _ BitBlt bitPokerToForm: form.
	bitsPerChannel = 8
		ifTrue:
			[1 to: width do: [:x | blitter pixelAt: x - 1 @ y
put: (thisScanline at: x)].
			^ self].
	bitsPerChannel = 1
		ifTrue:
			[pixPerByte _ 8.
			mask _ 1.
			shifts _ #(7 6 5 4 3 2 1 0 )].
	bitsPerChannel = 2
		ifTrue:
			[pixPerByte _ 4.
			mask _ 3.
			shifts _ #(6 4 2 0 )].
	bitsPerChannel = 4
		ifTrue:
			[pixPerByte _ 2.
			mask _ 15.
			shifts _ #(4 0 )].
	pixelNumber _ 0.
	0 to: width - 1 do:
		[:x |
		rawByte _ thisScanline at: pixelNumber // pixPerByte + 1.
		pixel _ rawByte >> (shifts at: pixelNumber \\ pixPerByte +
1) bitAnd: mask.
		blitter pixelAt: x @ y put: pixel.
		pixelNumber _ pixelNumber + 1]! !

!PNGReadWriter methodsFor: 'miscellaneous' stamp: 'DSM 4/27/2000 13:09'!
doPass: pass
	"Certain interlace passes are skipped with certain small image
dimensions"

	pass = 1 ifTrue: [ ^ true ].
	((width = 1) and: [height = 1]) ifTrue: [ ^ false ].
	pass = 2 ifTrue: [ ^ width >= 5 ].
	pass = 3 ifTrue: [ ^ height >= 5 ].
	pass = 4 ifTrue: [ ^ (width >=3 ) or: [height >= 5] ].
	pass = 5 ifTrue: [ ^ height >=3 ].
	pass = 6 ifTrue: [ ^ width >=2 ].
	pass = 7 ifTrue: [ ^ height >=2 ].

! !



More information about the Squeak-dev mailing list