aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/image/png
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2017-01-14 00:05:42 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2017-01-14 00:05:42 +0000
commitc2047754c300b68c05d65faa8dc2925fe67b71b4 (patch)
treee183ae81a1f48a02945cb6de463a70c5be1b06f6 /libgo/go/image/png
parent829afb8f05602bb31c9c597b24df7377fed4f059 (diff)
downloadgcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.zip
gcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.tar.gz
gcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.tar.bz2
libgo: update to Go 1.8 release candidate 1
Compiler changes: * Change map assignment to use mapassign and assign value directly. * Change string iteration to use decoderune, faster for ASCII strings. * Change makeslice to take int, and use makeslice64 for larger values. * Add new noverflow field to hmap struct used for maps. Unresolved problems, to be fixed later: * Commented out test in go/types/sizes_test.go that doesn't compile. * Commented out reflect.TestStructOf test for padding after zero-sized field. Reviewed-on: https://go-review.googlesource.com/35231 gotools/: Updates for Go 1.8rc1. * Makefile.am (go_cmd_go_files): Add bug.go. (s-zdefaultcc): Write defaultPkgConfig. * Makefile.in: Rebuild. From-SVN: r244456
Diffstat (limited to 'libgo/go/image/png')
-rw-r--r--libgo/go/image/png/example_test.go79
-rw-r--r--libgo/go/image/png/reader.go266
-rw-r--r--libgo/go/image/png/reader_test.go175
-rw-r--r--libgo/go/image/png/testdata/pngsuite/README21
-rw-r--r--libgo/go/image/png/writer.go5
5 files changed, 463 insertions, 83 deletions
diff --git a/libgo/go/image/png/example_test.go b/libgo/go/image/png/example_test.go
new file mode 100644
index 0000000..2a03be5
--- /dev/null
+++ b/libgo/go/image/png/example_test.go
@@ -0,0 +1,79 @@
+// Copyright 2016 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.
+
+// +build ignore
+
+package png_test
+
+import (
+ "encoding/base64"
+ "fmt"
+ "image"
+ "image/color"
+ "image/png"
+ "io"
+ "log"
+ "os"
+ "strings"
+)
+
+const gopher = `iVBORw0KGgoAAAANSUhEUgAAAEsAAAA8CAAAAAALAhhPAAAFfUlEQVRYw62XeWwUVRzHf2+OPbo9d7tsWyiyaZti6eWGAhISoIGKECEKCAiJJkYTiUgTMYSIosYYBBIUIxoSPIINEBDi2VhwkQrVsj1ESgu9doHWdrul7ba73WNm3vOPtsseM9MdwvvrzTs+8/t95ze/33sI5BqiabU6m9En8oNjduLnAEDLUsQXFF8tQ5oxK3vmnNmDSMtrncks9Hhtt/qeWZapHb1ha3UqYSWVl2ZmpWgaXMXGohQAvmeop3bjTRtv6SgaK/Pb9/bFzUrYslbFAmHPp+3WhAYdr+7GN/YnpN46Opv55VDsJkoEpMrY/vO2BIYQ6LLvm0ThY3MzDzzeSJeeWNyTkgnIE5ePKsvKlcg/0T9QMzXalwXMlj54z4c0rh/mzEfr+FgWEz2w6uk8dkzFAgcARAgNp1ZYef8bH2AgvuStbc2/i6CiWGj98y2tw2l4FAXKkQBIf+exyRnteY83LfEwDQAYCoK+P6bxkZm/0966LxcAAILHB56kgD95PPxltuYcMtFTWw/FKkY/6Opf3GGd9ZF+Qp6mzJxzuRSractOmJrH1u8XTvWFHINNkLQLMR+XHXvfPPHw967raE1xxwtA36IMRfkAAG29/7mLuQcb2WOnsJReZGfpiHsSBX81cvMKywYZHhX5hFPtOqPGWZCXnhWGAu6lX91ElKXSalcLXu3UaOXVay57ZSe5f6Gpx7J2MXAsi7EqSp09b/MirKSyJfnfEEgeDjl8FgDAfvewP03zZ+AJ0m9aFRM8eEHBDRKjfcreDXnZdQuAxXpT2NRJ7xl3UkLBhuVGU16gZiGOgZmrSbRdqkILuL/yYoSXHHkl9KXgqNu3PB8oRg0geC5vFmLjad6mUyTKLmF3OtraWDIfACyXqmephaDABawfpi6tqqBZytfQMqOz6S09iWXhktrRaB8Xz4Yi/8gyABDm5NVe6qq/3VzPrcjELWrebVuyY2T7ar4zQyybUCtsQ5Es1FGaZVrRVQwAgHGW2ZCRZshI5bGQi7HesyE972pOSeMM0dSktlzxRdrlqb3Osa6CCS8IJoQQQgBAbTAa5l5epO34rJszibJI8rxLfGzcp1dRosutGeb2VDNgqYrwTiPNsLxXiPi3dz7LiS1WBRBDBOnqEjyy3aQb+/bLiJzz9dIkscVBBLxMfSEac7kO4Fpkngi0ruNBeSOal+u8jgOuqPz12nryMLCniEjtOOOmpt+KEIqsEdocJjYXwrh9OZqWJQyPCTo67LNS/TdxLAv6R5ZNK9npEjbYdT33gRo4o5oTqR34R+OmaSzDBWsAIPhuRcgyoteNi9gF0KzNYWVItPf2TLoXEg+7isNC7uJkgo1iQWOfRSP9NR11RtbZZ3OMG/VhL6jvx+J1m87+RCfJChAtEBQkSBX2PnSiihc/Twh3j0h7qdYQAoRVsRGmq7HU2QRbaxVGa1D6nIOqaIWRjyRZpHMQKWKpZM5feA+lzC4ZFultV8S6T0mzQGhQohi5I8iw+CsqBSxhFMuwyLgSwbghGb0AiIKkSDmGZVmJSiKihsiyOAUs70UkywooYP0bii9GdH4sfr1UNysd3fUyLLMQN+rsmo3grHl9VNJHbbwxoa47Vw5gupIqrZcjPh9R4Nye3nRDk199V+aetmvVtDRE8/+cbgAAgMIWGb3UA0MGLE9SCbWX670TDy1y98c3D27eppUjsZ6fql3jcd5rUe7+ZIlLNQny3Rd+E5Tct3WVhTM5RBCEdiEK0b6B+/ca2gYU393nFj/n1AygRQxPIUA043M42u85+z2SnssKrPl8Mx76NL3E6eXc3be7OD+H4WHbJkKI8AU8irbITQjZ+0hQcPEgId/Fn/pl9crKH02+5o2b9T/eMx7pKoskYgAAAABJRU5ErkJggg==`
+
+// gopherPNG creates an io.Reader by decoding the base64 encoded image data string in the gopher constant.
+func gopherPNG() io.Reader { return base64.NewDecoder(base64.StdEncoding, strings.NewReader(gopher)) }
+
+func ExampleDecode() {
+ // This example uses png.Decode which can only decode PNG images.
+ // Consider using the general image.Decode as it can sniff and decode any registered image format.
+ img, err := png.Decode(gopherPNG())
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ levels := []string{" ", "░", "▒", "▓", "█"}
+
+ for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
+ for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
+ c := color.GrayModel.Convert(img.At(x, y)).(color.Gray)
+ level := c.Y / 51 // 51 * 5 = 255
+ if level == 5 {
+ level--
+ }
+ fmt.Print(levels[level])
+ }
+ fmt.Print("\n")
+ }
+}
+
+func ExampleEncode() {
+ const width, height = 256, 256
+
+ // Create a colored image of the given width and height.
+ img := image.NewNRGBA(image.Rect(0, 0, width, height))
+
+ for y := 0; y < height; y++ {
+ for x := 0; x < width; x++ {
+ img.Set(x, y, color.NRGBA{
+ R: uint8((x + y) & 255),
+ G: uint8((x + y) << 1 & 255),
+ B: uint8((x + y) << 2 & 255),
+ A: 255,
+ })
+ }
+ }
+
+ f, err := os.Create("image.png")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if err := png.Encode(f, img); err != nil {
+ f.Close()
+ log.Fatal(err)
+ }
+
+ if err := f.Close(); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/libgo/go/image/png/reader.go b/libgo/go/image/png/reader.go
index 2dd5ed8..32f78f0 100644
--- a/libgo/go/image/png/reader.go
+++ b/libgo/go/image/png/reader.go
@@ -113,6 +113,11 @@ type decoder struct {
idatLength uint32
tmp [3 * 256]byte
interlace int
+
+ // useTransparent and transparent are used for grayscale and truecolor
+ // transparency, as opposed to palette transparency.
+ useTransparent bool
+ transparent [6]byte
}
// A FormatError reports that the input is not a valid PNG.
@@ -252,20 +257,51 @@ func (d *decoder) parsePLTE(length uint32) error {
}
func (d *decoder) parsetRNS(length uint32) error {
- if length > 256 {
- return FormatError("bad tRNS length")
- }
- n, err := io.ReadFull(d.r, d.tmp[:length])
- if err != nil {
- return err
- }
- d.crc.Write(d.tmp[:n])
switch d.cb {
- case cbG8, cbG16:
- return UnsupportedError("grayscale transparency")
+ case cbG1, cbG2, cbG4, cbG8, cbG16:
+ if length != 2 {
+ return FormatError("bad tRNS length")
+ }
+ n, err := io.ReadFull(d.r, d.tmp[:length])
+ if err != nil {
+ return err
+ }
+ d.crc.Write(d.tmp[:n])
+
+ copy(d.transparent[:], d.tmp[:length])
+ switch d.cb {
+ case cbG1:
+ d.transparent[1] *= 0xff
+ case cbG2:
+ d.transparent[1] *= 0x55
+ case cbG4:
+ d.transparent[1] *= 0x11
+ }
+ d.useTransparent = true
+
case cbTC8, cbTC16:
- return UnsupportedError("truecolor transparency")
+ if length != 6 {
+ return FormatError("bad tRNS length")
+ }
+ n, err := io.ReadFull(d.r, d.tmp[:length])
+ if err != nil {
+ return err
+ }
+ d.crc.Write(d.tmp[:n])
+
+ copy(d.transparent[:], d.tmp[:length])
+ d.useTransparent = true
+
case cbP1, cbP2, cbP4, cbP8:
+ if length > 256 {
+ return FormatError("bad tRNS length")
+ }
+ n, err := io.ReadFull(d.r, d.tmp[:length])
+ if err != nil {
+ return err
+ }
+ d.crc.Write(d.tmp[:n])
+
if len(d.palette) < n {
d.palette = d.palette[:n]
}
@@ -273,7 +309,8 @@ func (d *decoder) parsetRNS(length uint32) error {
rgba := d.palette[i].(color.RGBA)
d.palette[i] = color.NRGBA{rgba.R, rgba.G, rgba.B, d.tmp[i]}
}
- case cbGA8, cbGA16, cbTCA8, cbTCA16:
+
+ default:
return FormatError("tRNS, color type mismatch")
}
return d.verifyChecksum()
@@ -366,7 +403,7 @@ func (d *decoder) decode() (image.Image, error) {
// readImagePass reads a single image pass, sized according to the pass number.
func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image.Image, error) {
- var bitsPerPixel int = 0
+ bitsPerPixel := 0
pixOffset := 0
var (
gray *image.Gray
@@ -394,16 +431,26 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
switch d.cb {
case cbG1, cbG2, cbG4, cbG8:
bitsPerPixel = d.depth
- gray = image.NewGray(image.Rect(0, 0, width, height))
- img = gray
+ if d.useTransparent {
+ nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
+ img = nrgba
+ } else {
+ gray = image.NewGray(image.Rect(0, 0, width, height))
+ img = gray
+ }
case cbGA8:
bitsPerPixel = 16
nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
img = nrgba
case cbTC8:
bitsPerPixel = 24
- rgba = image.NewRGBA(image.Rect(0, 0, width, height))
- img = rgba
+ if d.useTransparent {
+ nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
+ img = nrgba
+ } else {
+ rgba = image.NewRGBA(image.Rect(0, 0, width, height))
+ img = rgba
+ }
case cbP1, cbP2, cbP4, cbP8:
bitsPerPixel = d.depth
paletted = image.NewPaletted(image.Rect(0, 0, width, height), d.palette)
@@ -414,16 +461,26 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
img = nrgba
case cbG16:
bitsPerPixel = 16
- gray16 = image.NewGray16(image.Rect(0, 0, width, height))
- img = gray16
+ if d.useTransparent {
+ nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
+ img = nrgba64
+ } else {
+ gray16 = image.NewGray16(image.Rect(0, 0, width, height))
+ img = gray16
+ }
case cbGA16:
bitsPerPixel = 32
nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
img = nrgba64
case cbTC16:
bitsPerPixel = 48
- rgba64 = image.NewRGBA64(image.Rect(0, 0, width, height))
- img = rgba64
+ if d.useTransparent {
+ nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
+ img = nrgba64
+ } else {
+ rgba64 = image.NewRGBA64(image.Rect(0, 0, width, height))
+ img = rgba64
+ }
case cbTCA16:
bitsPerPixel = 64
nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
@@ -483,27 +540,75 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
// Convert from bytes to colors.
switch d.cb {
case cbG1:
- for x := 0; x < width; x += 8 {
- b := cdat[x/8]
- for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
- gray.SetGray(x+x2, y, color.Gray{(b >> 7) * 0xff})
- b <<= 1
+ if d.useTransparent {
+ ty := d.transparent[1]
+ for x := 0; x < width; x += 8 {
+ b := cdat[x/8]
+ for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
+ ycol := (b >> 7) * 0xff
+ acol := uint8(0xff)
+ if ycol == ty {
+ acol = 0x00
+ }
+ nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol})
+ b <<= 1
+ }
+ }
+ } else {
+ for x := 0; x < width; x += 8 {
+ b := cdat[x/8]
+ for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
+ gray.SetGray(x+x2, y, color.Gray{(b >> 7) * 0xff})
+ b <<= 1
+ }
}
}
case cbG2:
- for x := 0; x < width; x += 4 {
- b := cdat[x/4]
- for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
- gray.SetGray(x+x2, y, color.Gray{(b >> 6) * 0x55})
- b <<= 2
+ if d.useTransparent {
+ ty := d.transparent[1]
+ for x := 0; x < width; x += 4 {
+ b := cdat[x/4]
+ for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
+ ycol := (b >> 6) * 0x55
+ acol := uint8(0xff)
+ if ycol == ty {
+ acol = 0x00
+ }
+ nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol})
+ b <<= 2
+ }
+ }
+ } else {
+ for x := 0; x < width; x += 4 {
+ b := cdat[x/4]
+ for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
+ gray.SetGray(x+x2, y, color.Gray{(b >> 6) * 0x55})
+ b <<= 2
+ }
}
}
case cbG4:
- for x := 0; x < width; x += 2 {
- b := cdat[x/2]
- for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
- gray.SetGray(x+x2, y, color.Gray{(b >> 4) * 0x11})
- b <<= 4
+ if d.useTransparent {
+ ty := d.transparent[1]
+ for x := 0; x < width; x += 2 {
+ b := cdat[x/2]
+ for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
+ ycol := (b >> 4) * 0x11
+ acol := uint8(0xff)
+ if ycol == ty {
+ acol = 0x00
+ }
+ nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol})
+ b <<= 4
+ }
+ }
+ } else {
+ for x := 0; x < width; x += 2 {
+ b := cdat[x/2]
+ for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
+ gray.SetGray(x+x2, y, color.Gray{(b >> 4) * 0x11})
+ b <<= 4
+ }
}
}
case cbG8:
@@ -515,16 +620,37 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
nrgba.SetNRGBA(x, y, color.NRGBA{ycol, ycol, ycol, cdat[2*x+1]})
}
case cbTC8:
- pix, i, j := rgba.Pix, pixOffset, 0
- for x := 0; x < width; x++ {
- pix[i+0] = cdat[j+0]
- pix[i+1] = cdat[j+1]
- pix[i+2] = cdat[j+2]
- pix[i+3] = 0xff
- i += 4
- j += 3
+ if d.useTransparent {
+ pix, i, j := nrgba.Pix, pixOffset, 0
+ tr, tg, tb := d.transparent[1], d.transparent[3], d.transparent[5]
+ for x := 0; x < width; x++ {
+ r := cdat[j+0]
+ g := cdat[j+1]
+ b := cdat[j+2]
+ a := uint8(0xff)
+ if r == tr && g == tg && b == tb {
+ a = 0x00
+ }
+ pix[i+0] = r
+ pix[i+1] = g
+ pix[i+2] = b
+ pix[i+3] = a
+ i += 4
+ j += 3
+ }
+ pixOffset += nrgba.Stride
+ } else {
+ pix, i, j := rgba.Pix, pixOffset, 0
+ for x := 0; x < width; x++ {
+ pix[i+0] = cdat[j+0]
+ pix[i+1] = cdat[j+1]
+ pix[i+2] = cdat[j+2]
+ pix[i+3] = 0xff
+ i += 4
+ j += 3
+ }
+ pixOffset += rgba.Stride
}
- pixOffset += rgba.Stride
case cbP1:
for x := 0; x < width; x += 8 {
b := cdat[x/8]
@@ -575,9 +701,21 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
copy(nrgba.Pix[pixOffset:], cdat)
pixOffset += nrgba.Stride
case cbG16:
- for x := 0; x < width; x++ {
- ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
- gray16.SetGray16(x, y, color.Gray16{ycol})
+ if d.useTransparent {
+ ty := uint16(d.transparent[0])<<8 | uint16(d.transparent[1])
+ for x := 0; x < width; x++ {
+ ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
+ acol := uint16(0xffff)
+ if ycol == ty {
+ acol = 0x0000
+ }
+ nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol})
+ }
+ } else {
+ for x := 0; x < width; x++ {
+ ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
+ gray16.SetGray16(x, y, color.Gray16{ycol})
+ }
}
case cbGA16:
for x := 0; x < width; x++ {
@@ -586,11 +724,27 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol})
}
case cbTC16:
- for x := 0; x < width; x++ {
- rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
- gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
- bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
- rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff})
+ if d.useTransparent {
+ tr := uint16(d.transparent[0])<<8 | uint16(d.transparent[1])
+ tg := uint16(d.transparent[2])<<8 | uint16(d.transparent[3])
+ tb := uint16(d.transparent[4])<<8 | uint16(d.transparent[5])
+ for x := 0; x < width; x++ {
+ rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
+ gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
+ bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
+ acol := uint16(0xffff)
+ if rcol == tr && gcol == tg && bcol == tb {
+ acol = 0x0000
+ }
+ nrgba64.SetNRGBA64(x, y, color.NRGBA64{rcol, gcol, bcol, acol})
+ }
+ } else {
+ for x := 0; x < width; x++ {
+ rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
+ gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
+ bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
+ rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff})
+ }
}
case cbTCA16:
for x := 0; x < width; x++ {
@@ -709,7 +863,11 @@ func (d *decoder) parseChunk() error {
d.stage = dsSeenPLTE
return d.parsePLTE(length)
case "tRNS":
- if d.stage != dsSeenPLTE {
+ if cbPaletted(d.cb) {
+ if d.stage != dsSeenPLTE {
+ return chunkOrderError
+ }
+ } else if d.stage != dsSeenIHDR {
return chunkOrderError
}
d.stage = dsSeentRNS
diff --git a/libgo/go/image/png/reader_test.go b/libgo/go/image/png/reader_test.go
index 0bc4203..b9e9f4d 100644
--- a/libgo/go/image/png/reader_test.go
+++ b/libgo/go/image/png/reader_test.go
@@ -39,6 +39,21 @@ var filenames = []string{
"basn4a16",
"basn6a08",
"basn6a16",
+ "ftbbn0g01",
+ "ftbbn0g02",
+ "ftbbn0g04",
+ "ftbbn2c16",
+ "ftbbn3p08",
+ "ftbgn2c16",
+ "ftbgn3p08",
+ "ftbrn2c08",
+ "ftbwn0g16",
+ "ftbwn3p08",
+ "ftbyn3p08",
+ "ftp0n0g08",
+ "ftp0n2c08",
+ "ftp0n3p08",
+ "ftp1n3p08",
}
var filenamesPaletted = []string{
@@ -64,6 +79,50 @@ func readPNG(filename string) (image.Image, error) {
return Decode(f)
}
+// fakebKGDs maps from filenames to fake bKGD chunks for our approximation to
+// the sng command-line tool. Package png doesn't keep that metadata when
+// png.Decode returns an image.Image.
+var fakebKGDs = map[string]string{
+ "ftbbn0g01": "bKGD {gray: 0;}\n",
+ "ftbbn0g02": "bKGD {gray: 0;}\n",
+ "ftbbn0g04": "bKGD {gray: 0;}\n",
+ "ftbbn2c16": "bKGD {red: 0; green: 0; blue: 65535;}\n",
+ "ftbbn3p08": "bKGD {index: 245}\n",
+ "ftbgn2c16": "bKGD {red: 0; green: 65535; blue: 0;}\n",
+ "ftbgn3p08": "bKGD {index: 245}\n",
+ "ftbrn2c08": "bKGD {red: 255; green: 0; blue: 0;}\n",
+ "ftbwn0g16": "bKGD {gray: 65535;}\n",
+ "ftbwn3p08": "bKGD {index: 0}\n",
+ "ftbyn3p08": "bKGD {index: 245}\n",
+}
+
+// fakegAMAs maps from filenames to fake gAMA chunks for our approximation to
+// the sng command-line tool. Package png doesn't keep that metadata when
+// png.Decode returns an image.Image.
+var fakegAMAs = map[string]string{
+ "ftbbn0g01": "",
+ "ftbbn0g02": "gAMA {0.45455}\n",
+}
+
+// fakeIHDRUsings maps from filenames to fake IHDR "using" lines for our
+// approximation to the sng command-line tool. The PNG model is that
+// transparency (in the tRNS chunk) is separate to the color/grayscale/palette
+// color model (in the IHDR chunk). The Go model is that the concrete
+// image.Image type returned by png.Decode, such as image.RGBA (with all pixels
+// having 100% alpha) or image.NRGBA, encapsulates whether or not the image has
+// transparency. This map is a hack to work around the fact that the Go model
+// can't otherwise discriminate PNG's "IHDR says color (with no alpha) but tRNS
+// says alpha" and "IHDR says color with alpha".
+var fakeIHDRUsings = map[string]string{
+ "ftbbn0g01": " using grayscale;\n",
+ "ftbbn0g02": " using grayscale;\n",
+ "ftbbn0g04": " using grayscale;\n",
+ "ftbbn2c16": " using color;\n",
+ "ftbgn2c16": " using color;\n",
+ "ftbrn2c08": " using color;\n",
+ "ftbwn0g16": " using grayscale;\n",
+}
+
// An approximation of the sng command-line tool.
func sng(w io.WriteCloser, filename string, png image.Image) {
defer w.Close()
@@ -95,25 +154,35 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
// Write the filename and IHDR.
io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n")
fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth)
- switch {
- case cm == color.RGBAModel, cm == color.RGBA64Model:
- io.WriteString(w, " using color;\n")
- case cm == color.NRGBAModel, cm == color.NRGBA64Model:
- io.WriteString(w, " using color alpha;\n")
- case cm == color.GrayModel, cm == color.Gray16Model:
- io.WriteString(w, " using grayscale;\n")
- case cpm != nil:
- io.WriteString(w, " using color palette;\n")
- default:
- io.WriteString(w, "unknown PNG decoder color model\n")
+ if s, ok := fakeIHDRUsings[filename]; ok {
+ io.WriteString(w, s)
+ } else {
+ switch {
+ case cm == color.RGBAModel, cm == color.RGBA64Model:
+ io.WriteString(w, " using color;\n")
+ case cm == color.NRGBAModel, cm == color.NRGBA64Model:
+ io.WriteString(w, " using color alpha;\n")
+ case cm == color.GrayModel, cm == color.Gray16Model:
+ io.WriteString(w, " using grayscale;\n")
+ case cpm != nil:
+ io.WriteString(w, " using color palette;\n")
+ default:
+ io.WriteString(w, "unknown PNG decoder color model\n")
+ }
}
io.WriteString(w, "}\n")
- // We fake a gAMA output. The test files have a gAMA chunk but the go PNG parser ignores it
- // (the PNG spec section 11.3 says "Ancillary chunks may be ignored by a decoder").
- io.WriteString(w, "gAMA {1.0000}\n")
+ // We fake a gAMA chunk. The test files have a gAMA chunk but the go PNG
+ // parser ignores it (the PNG spec section 11.3 says "Ancillary chunks may
+ // be ignored by a decoder").
+ if s, ok := fakegAMAs[filename]; ok {
+ io.WriteString(w, s)
+ } else {
+ io.WriteString(w, "gAMA {1.0000}\n")
+ }
// Write the PLTE and tRNS (if applicable).
+ useTransparent := false
if cpm != nil {
lastAlpha := -1
io.WriteString(w, "PLTE {\n")
@@ -133,6 +202,9 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b)
}
io.WriteString(w, "}\n")
+ if s, ok := fakebKGDs[filename]; ok {
+ io.WriteString(w, s)
+ }
if lastAlpha != -1 {
io.WriteString(w, "tRNS {\n")
for i := 0; i <= lastAlpha; i++ {
@@ -142,6 +214,42 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
}
io.WriteString(w, "}\n")
}
+ } else if strings.HasPrefix(filename, "ft") {
+ if s, ok := fakebKGDs[filename]; ok {
+ io.WriteString(w, s)
+ }
+ // We fake a tRNS chunk. The test files' grayscale and truecolor
+ // transparent images all have their top left corner transparent.
+ switch c := png.At(0, 0).(type) {
+ case color.NRGBA:
+ if c.A == 0 {
+ useTransparent = true
+ io.WriteString(w, "tRNS {\n")
+ switch filename {
+ case "ftbbn0g01", "ftbbn0g02", "ftbbn0g04":
+ // The standard image package doesn't have a "gray with
+ // alpha" type. Instead, we use an image.NRGBA.
+ fmt.Fprintf(w, " gray: %d;\n", c.R)
+ default:
+ fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B)
+ }
+ io.WriteString(w, "}\n")
+ }
+ case color.NRGBA64:
+ if c.A == 0 {
+ useTransparent = true
+ io.WriteString(w, "tRNS {\n")
+ switch filename {
+ case "ftbwn0g16":
+ // The standard image package doesn't have a "gray16 with
+ // alpha" type. Instead, we use an image.NRGBA64.
+ fmt.Fprintf(w, " gray: %d;\n", c.R)
+ default:
+ fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B)
+ }
+ io.WriteString(w, "}\n")
+ }
+ }
}
// Write the IMAGE.
@@ -171,12 +279,30 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
case cm == color.NRGBAModel:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
nrgba := png.At(x, y).(color.NRGBA)
- fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
+ switch filename {
+ case "ftbbn0g01", "ftbbn0g02", "ftbbn0g04":
+ fmt.Fprintf(w, "%02x", nrgba.R)
+ default:
+ if useTransparent {
+ fmt.Fprintf(w, "%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B)
+ } else {
+ fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
+ }
+ }
}
case cm == color.NRGBA64Model:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
nrgba64 := png.At(x, y).(color.NRGBA64)
- fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
+ switch filename {
+ case "ftbwn0g16":
+ fmt.Fprintf(w, "%04x ", nrgba64.R)
+ default:
+ if useTransparent {
+ fmt.Fprintf(w, "%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B)
+ } else {
+ fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
+ }
+ }
}
case cpm != nil:
var b, c int
@@ -256,8 +382,23 @@ func TestReader(t *testing.T) {
}
ps := pb.Text()
ss := sb.Text()
+
+ // Newer versions of the sng command line tool append an optional
+ // color name to the RGB tuple. For example:
+ // # rgb = (0xff,0xff,0xff) grey100
+ // # rgb = (0x00,0x00,0xff) blue1
+ // instead of the older version's plainer:
+ // # rgb = (0xff,0xff,0xff)
+ // # rgb = (0x00,0x00,0xff)
+ // We strip any such name.
+ if strings.Contains(ss, "# rgb = (") && !strings.HasSuffix(ss, ")") {
+ if i := strings.LastIndex(ss, ") "); i >= 0 {
+ ss = ss[:i+1]
+ }
+ }
+
if ps != ss {
- t.Errorf("%s: Mismatch\n%sversus\n%s\n", fn, ps, ss)
+ t.Errorf("%s: Mismatch\n%s\nversus\n%s\n", fn, ps, ss)
break
}
}
diff --git a/libgo/go/image/png/testdata/pngsuite/README b/libgo/go/image/png/testdata/pngsuite/README
index c0f78bd..01d1d89 100644
--- a/libgo/go/image/png/testdata/pngsuite/README
+++ b/libgo/go/image/png/testdata/pngsuite/README
@@ -1,21 +1,20 @@
The *.png and README.original files in this directory are copied from
-libpng.org, specifically contrib/pngsuite/* in libpng-1.2.40.tar.gz.
+libpng.org, specifically contrib/pngsuite/* in libpng 1.6.26.
+
README.original gives the following license for those files:
Permission to use, copy, and distribute these images for any purpose
and without fee is hereby granted.
-
-The files basn0g01-30.png, basn0g02-29.png and basn0g04-31.png are in fact
-not part of pngsuite but were created from files in pngsuite. Their non-power-
-of-two sizes makes them useful for testing bit-depths smaller than a byte.
+The files basn0g01-30.png, basn0g02-29.png and basn0g04-31.png are in fact not
+part of pngsuite but were created from files in pngsuite. Their non-power-of-2
+sizes makes them useful for testing bit-depths smaller than a byte.
basn3a08.png was generated from basn6a08.png using the pngnq tool, which
converted it to the 8-bit paletted image with alpha values in tRNS chunk.
-The *.sng files in this directory were generated from the *.png files
-by the sng command-line tool and some hand editing. The files
-basn0g0{1,2,4}.sng were actually generated by first converting the PNG
-to a bitdepth of 8 and then running sng on them. basn4a08.sng was generated
-by from a 16-bit rgba version of basn4a08.png rather than the original
-gray + alpha.
+The *.sng files in this directory were generated from the *.png files by the
+sng command-line tool and some hand editing. The files basn0g0{1,2,4}.sng and
+ftbbn0g0{1,2,4}.sng were actually generated by first converting the PNG to a
+bitdepth of 8 and then running sng on them. basn4a08.sng was generated from a
+16-bit rgba version of basn4a08.png rather than the original gray + alpha.
diff --git a/libgo/go/image/png/writer.go b/libgo/go/image/png/writer.go
index df23270..dd87d81 100644
--- a/libgo/go/image/png/writer.go
+++ b/libgo/go/image/png/writer.go
@@ -420,8 +420,11 @@ func writeImage(w io.Writer, m image.Image, cb int, level int) error {
}
// Apply the filter.
+ // Skip filter for NoCompression and paletted images (cbP8) as
+ // "filters are rarely useful on palette images" and will result
+ // in larger files (see http://www.libpng.org/pub/png/book/chapter09.html).
f := ftNone
- if level != zlib.NoCompression {
+ if level != zlib.NoCompression && cb != cbP8 {
f = filter(&cr, pr, bpp)
}