diff options
author | Ian Lance Taylor <iant@golang.org> | 2017-01-14 00:05:42 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2017-01-14 00:05:42 +0000 |
commit | c2047754c300b68c05d65faa8dc2925fe67b71b4 (patch) | |
tree | e183ae81a1f48a02945cb6de463a70c5be1b06f6 /libgo/go/image/png | |
parent | 829afb8f05602bb31c9c597b24df7377fed4f059 (diff) | |
download | gcc-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.go | 79 | ||||
-rw-r--r-- | libgo/go/image/png/reader.go | 266 | ||||
-rw-r--r-- | libgo/go/image/png/reader_test.go | 175 | ||||
-rw-r--r-- | libgo/go/image/png/testdata/pngsuite/README | 21 | ||||
-rw-r--r-- | libgo/go/image/png/writer.go | 5 |
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) } |