diff --git a/src/pkg/image/png/paeth_test.go b/src/pkg/image/png/paeth_test.go new file mode 100644 index 0000000000..b0cec1c8f6 --- /dev/null +++ b/src/pkg/image/png/paeth_test.go @@ -0,0 +1,51 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package png + +import ( + "testing" +) + +func abs(x int) int { + if x < 0 { + return -x + } + return x +} + +// slowPaeth is a slow but simple implementation of the Paeth function. +// It is a straight port of the sample code in the PNG spec, section 9.4. +func slowPaeth(a, b, c uint8) uint8 { + p := int(a) + int(b) - int(c) + pa := abs(p - int(a)) + pb := abs(p - int(b)) + pc := abs(p - int(c)) + if pa <= pb && pa <= pc { + return a + } else if pb <= pc { + return b + } + return c +} + +func TestPaeth(t *testing.T) { + for a := 0; a < 256; a += 15 { + for b := 0; b < 256; b += 15 { + for c := 0; c < 256; c += 15 { + got := paeth(uint8(a), uint8(b), uint8(c)) + want := slowPaeth(uint8(a), uint8(b), uint8(c)) + if got != want { + t.Errorf("a, b, c = %d, %d, %d: got %d, want %d", a, b, c, got, want) + } + } + } + } +} + +func BenchmarkPaeth(b *testing.B) { + for i := 0; i < b.N; i++ { + paeth(uint8(i>>16), uint8(i>>8), uint8(i)) + } +} diff --git a/src/pkg/image/png/reader.go b/src/pkg/image/png/reader.go index c781be1837..6b2100badd 100644 --- a/src/pkg/image/png/reader.go +++ b/src/pkg/image/png/reader.go @@ -98,13 +98,6 @@ type UnsupportedError string func (e UnsupportedError) Error() string { return "png: unsupported feature: " + string(e) } -func abs(x int) int { - if x < 0 { - return -x - } - return x -} - func min(a, b int) int { if a < b { return a @@ -241,12 +234,28 @@ func (d *decoder) parsetRNS(length uint32) error { return d.verifyChecksum() } -// The Paeth filter function, as per the PNG specification. +// paeth implements the Paeth filter function, as per the PNG specification. func paeth(a, b, c uint8) uint8 { - p := int(a) + int(b) - int(c) - pa := abs(p - int(a)) - pb := abs(p - int(b)) - pc := abs(p - int(c)) + // This is an optimized version of the sample code in the PNG spec. + // For example, the sample code starts with: + // p := int(a) + int(b) - int(c) + // pa := abs(p - int(a)) + // but the optimized form uses fewer arithmetic operations: + // pa := int(b) - int(c) + // pa = abs(pa) + pc := int(c) + pa := int(b) - pc + pb := int(a) - pc + pc = pa + pb + if pa < 0 { + pa = -pa + } + if pb < 0 { + pb = -pb + } + if pc < 0 { + pc = -pc + } if pa <= pb && pa <= pc { return a } else if pb <= pc {