diff options
author | Ian Lance Taylor <iant@golang.org> | 2019-01-18 19:04:36 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2019-01-18 19:04:36 +0000 |
commit | 4f4a855d82a889cebcfca150a7a43909bcb6a346 (patch) | |
tree | f12bae0781920fa34669fe30b6f4615a86d9fb80 /libgo/go/image | |
parent | 225220d668dafb8262db7012bced688acbe63b33 (diff) |
libgo: update to Go1.12beta2
Reviewed-on: https://go-review.googlesource.com/c/158019
gotools/:
* Makefile.am (go_cmd_vet_files): Update for Go1.12beta2 release.
(GOTOOLS_TEST_TIMEOUT): Increase to 600.
(check-runtime): Export LD_LIBRARY_PATH before computing GOARCH
and GOOS.
(check-vet): Copy golang.org/x/tools into check-vet-dir.
* Makefile.in: Regenerate.
gcc/testsuite/:
* go.go-torture/execute/names-1.go: Stop using debug/xcoff, which
is no longer externally visible.
From-SVN: r268084
Diffstat (limited to 'libgo/go/image')
-rw-r--r-- | libgo/go/image/draw/draw.go | 126 | ||||
-rw-r--r-- | libgo/go/image/format.go | 13 | ||||
-rw-r--r-- | libgo/go/image/image.go | 149 | ||||
-rw-r--r-- | libgo/go/image/image_test.go | 214 | ||||
-rw-r--r-- | libgo/go/image/jpeg/fdct.go | 32 | ||||
-rw-r--r-- | libgo/go/image/png/reader_test.go | 4 | ||||
-rw-r--r-- | libgo/go/image/png/writer.go | 90 | ||||
-rw-r--r-- | libgo/go/image/png/writer_test.go | 112 |
8 files changed, 549 insertions, 191 deletions
diff --git a/libgo/go/image/draw/draw.go b/libgo/go/image/draw/draw.go index 977d7c52215..3ff1828dc0c 100644 --- a/libgo/go/image/draw/draw.go +++ b/libgo/go/image/draw/draw.go @@ -309,23 +309,20 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image. dpix := dst.Pix[d0:] spix := src.Pix[s0:] for i := i0; i != i1; i += idelta { - sr := uint32(spix[i+0]) * 0x101 - sg := uint32(spix[i+1]) * 0x101 - sb := uint32(spix[i+2]) * 0x101 - sa := uint32(spix[i+3]) * 0x101 - - dr := &dpix[i+0] - dg := &dpix[i+1] - db := &dpix[i+2] - da := &dpix[i+3] + s := spix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + sr := uint32(s[0]) * 0x101 + sg := uint32(s[1]) * 0x101 + sb := uint32(s[2]) * 0x101 + sa := uint32(s[3]) * 0x101 // The 0x101 is here for the same reason as in drawRGBA. a := (m - sa) * 0x101 - *dr = uint8((uint32(*dr)*a/m + sr) >> 8) - *dg = uint8((uint32(*dg)*a/m + sg) >> 8) - *db = uint8((uint32(*db)*a/m + sb) >> 8) - *da = uint8((uint32(*da)*a/m + sa) >> 8) + d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + d[0] = uint8((uint32(d[0])*a/m + sr) >> 8) + d[1] = uint8((uint32(d[1])*a/m + sg) >> 8) + d[2] = uint8((uint32(d[2])*a/m + sb) >> 8) + d[3] = uint8((uint32(d[3])*a/m + sa) >> 8) } d0 += ddelta s0 += sdelta @@ -372,23 +369,25 @@ func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp imag for i, si := i0, si0; i < i1; i, si = i+4, si+4 { // Convert from non-premultiplied color to pre-multiplied color. - sa := uint32(spix[si+3]) * 0x101 - sr := uint32(spix[si+0]) * sa / 0xff - sg := uint32(spix[si+1]) * sa / 0xff - sb := uint32(spix[si+2]) * sa / 0xff - - dr := uint32(dpix[i+0]) - dg := uint32(dpix[i+1]) - db := uint32(dpix[i+2]) - da := uint32(dpix[i+3]) + s := spix[si : si+4 : si+4] // Small cap improves performance, see https://golang.org/issue/27857 + sa := uint32(s[3]) * 0x101 + sr := uint32(s[0]) * sa / 0xff + sg := uint32(s[1]) * sa / 0xff + sb := uint32(s[2]) * sa / 0xff + + d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + dr := uint32(d[0]) + dg := uint32(d[1]) + db := uint32(d[2]) + da := uint32(d[3]) // The 0x101 is here for the same reason as in drawRGBA. a := (m - sa) * 0x101 - dpix[i+0] = uint8((dr*a/m + sr) >> 8) - dpix[i+1] = uint8((dg*a/m + sg) >> 8) - dpix[i+2] = uint8((db*a/m + sb) >> 8) - dpix[i+3] = uint8((da*a/m + sa) >> 8) + d[0] = uint8((dr*a/m + sr) >> 8) + d[1] = uint8((dg*a/m + sg) >> 8) + d[2] = uint8((db*a/m + sb) >> 8) + d[3] = uint8((da*a/m + sa) >> 8) } } } @@ -407,15 +406,17 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image for i, si := i0, si0; i < i1; i, si = i+4, si+4 { // Convert from non-premultiplied color to pre-multiplied color. - sa := uint32(spix[si+3]) * 0x101 - sr := uint32(spix[si+0]) * sa / 0xff - sg := uint32(spix[si+1]) * sa / 0xff - sb := uint32(spix[si+2]) * sa / 0xff - - dpix[i+0] = uint8(sr >> 8) - dpix[i+1] = uint8(sg >> 8) - dpix[i+2] = uint8(sb >> 8) - dpix[i+3] = uint8(sa >> 8) + s := spix[si : si+4 : si+4] // Small cap improves performance, see https://golang.org/issue/27857 + sa := uint32(s[3]) * 0x101 + sr := uint32(s[0]) * sa / 0xff + sg := uint32(s[1]) * sa / 0xff + sb := uint32(s[2]) * sa / 0xff + + d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + d[0] = uint8(sr >> 8) + d[1] = uint8(sg >> 8) + d[2] = uint8(sb >> 8) + d[3] = uint8(sa >> 8) } } } @@ -434,10 +435,11 @@ func drawGray(dst *image.RGBA, r image.Rectangle, src *image.Gray, sp image.Poin for i, si := i0, si0; i < i1; i, si = i+4, si+1 { p := spix[si] - dpix[i+0] = p - dpix[i+1] = p - dpix[i+2] = p - dpix[i+3] = 255 + d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + d[0] = p + d[1] = p + d[2] = p + d[3] = 255 } } } @@ -455,9 +457,10 @@ func drawCMYK(dst *image.RGBA, r image.Rectangle, src *image.CMYK, sp image.Poin spix := src.Pix[sy*src.Stride:] for i, si := i0, si0; i < i1; i, si = i+4, si+4 { - dpix[i+0], dpix[i+1], dpix[i+2] = - color.CMYKToRGB(spix[si+0], spix[si+1], spix[si+2], spix[si+3]) - dpix[i+3] = 255 + s := spix[si : si+4 : si+4] // Small cap improves performance, see https://golang.org/issue/27857 + d := dpix[i : i+4 : i+4] + d[0], d[1], d[2] = color.CMYKToRGB(s[0], s[1], s[2], s[3]) + d[3] = 255 } } } @@ -475,18 +478,14 @@ func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask } ma |= ma << 8 - dr := &dst.Pix[i+0] - dg := &dst.Pix[i+1] - db := &dst.Pix[i+2] - da := &dst.Pix[i+3] - // The 0x101 is here for the same reason as in drawRGBA. a := (m - (sa * ma / m)) * 0x101 - *dr = uint8((uint32(*dr)*a + sr*ma) / m >> 8) - *dg = uint8((uint32(*dg)*a + sg*ma) / m >> 8) - *db = uint8((uint32(*db)*a + sb*ma) / m >> 8) - *da = uint8((uint32(*da)*a + sa*ma) / m >> 8) + d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + d[0] = uint8((uint32(d[0])*a + sr*ma) / m >> 8) + d[1] = uint8((uint32(d[1])*a + sg*ma) / m >> 8) + d[2] = uint8((uint32(d[2])*a + sb*ma) / m >> 8) + d[3] = uint8((uint32(d[3])*a + sa*ma) / m >> 8) } i0 += dst.Stride i1 += dst.Stride @@ -518,11 +517,12 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin _, _, _, ma = mask.At(mx, my).RGBA() } sr, sg, sb, sa := src.At(sx, sy).RGBA() + d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 if op == Over { - dr := uint32(dst.Pix[i+0]) - dg := uint32(dst.Pix[i+1]) - db := uint32(dst.Pix[i+2]) - da := uint32(dst.Pix[i+3]) + dr := uint32(d[0]) + dg := uint32(d[1]) + db := uint32(d[2]) + da := uint32(d[3]) // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255]. // We work in 16-bit color, and so would normally do: @@ -532,16 +532,16 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin // This yields the same result, but is fewer arithmetic operations. a := (m - (sa * ma / m)) * 0x101 - dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8) - dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8) - dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8) - dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8) + d[0] = uint8((dr*a + sr*ma) / m >> 8) + d[1] = uint8((dg*a + sg*ma) / m >> 8) + d[2] = uint8((db*a + sb*ma) / m >> 8) + d[3] = uint8((da*a + sa*ma) / m >> 8) } else { - dst.Pix[i+0] = uint8(sr * ma / m >> 8) - dst.Pix[i+1] = uint8(sg * ma / m >> 8) - dst.Pix[i+2] = uint8(sb * ma / m >> 8) - dst.Pix[i+3] = uint8(sa * ma / m >> 8) + d[0] = uint8(sr * ma / m >> 8) + d[1] = uint8(sg * ma / m >> 8) + d[2] = uint8(sb * ma / m >> 8) + d[3] = uint8(sa * ma / m >> 8) } } i0 += dy * dst.Stride diff --git a/libgo/go/image/format.go b/libgo/go/image/format.go index 3668de4e685..a53b8f9b554 100644 --- a/libgo/go/image/format.go +++ b/libgo/go/image/format.go @@ -8,6 +8,8 @@ import ( "bufio" "errors" "io" + "sync" + "sync/atomic" ) // ErrFormat indicates that decoding encountered an unknown format. @@ -21,7 +23,10 @@ type format struct { } // Formats is the list of registered formats. -var formats []format +var ( + formatsMu sync.Mutex + atomicFormats atomic.Value +) // RegisterFormat registers an image format for use by Decode. // Name is the name of the format, like "jpeg" or "png". @@ -30,7 +35,10 @@ var formats []format // Decode is the function that decodes the encoded image. // DecodeConfig is the function that decodes just its configuration. func RegisterFormat(name, magic string, decode func(io.Reader) (Image, error), decodeConfig func(io.Reader) (Config, error)) { - formats = append(formats, format{name, magic, decode, decodeConfig}) + formatsMu.Lock() + formats, _ := atomicFormats.Load().([]format) + atomicFormats.Store(append(formats, format{name, magic, decode, decodeConfig})) + formatsMu.Unlock() } // A reader is an io.Reader that can also peek ahead. @@ -62,6 +70,7 @@ func match(magic string, b []byte) bool { // Sniff determines the format of r's data. func sniff(r reader) format { + formats, _ := atomicFormats.Load().([]format) for _, f := range formats { b, err := r.Peek(len(f.magic)) if err == nil && match(f.magic, b) { diff --git a/libgo/go/image/image.go b/libgo/go/image/image.go index bebb9f70fa6..ffd6de73837 100644 --- a/libgo/go/image/image.go +++ b/libgo/go/image/image.go @@ -80,7 +80,8 @@ func (p *RGBA) RGBAAt(x, y int) color.RGBA { return color.RGBA{} } i := p.PixOffset(x, y) - return color.RGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]} + s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + return color.RGBA{s[0], s[1], s[2], s[3]} } // PixOffset returns the index of the first element of Pix that corresponds to @@ -95,10 +96,11 @@ func (p *RGBA) Set(x, y int, c color.Color) { } i := p.PixOffset(x, y) c1 := color.RGBAModel.Convert(c).(color.RGBA) - p.Pix[i+0] = c1.R - p.Pix[i+1] = c1.G - p.Pix[i+2] = c1.B - p.Pix[i+3] = c1.A + s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = c1.R + s[1] = c1.G + s[2] = c1.B + s[3] = c1.A } func (p *RGBA) SetRGBA(x, y int, c color.RGBA) { @@ -106,10 +108,11 @@ func (p *RGBA) SetRGBA(x, y int, c color.RGBA) { return } i := p.PixOffset(x, y) - p.Pix[i+0] = c.R - p.Pix[i+1] = c.G - p.Pix[i+2] = c.B - p.Pix[i+3] = c.A + s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = c.R + s[1] = c.G + s[2] = c.B + s[3] = c.A } // SubImage returns an image representing the portion of the image p visible @@ -179,11 +182,12 @@ func (p *RGBA64) RGBA64At(x, y int) color.RGBA64 { return color.RGBA64{} } i := p.PixOffset(x, y) + s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857 return color.RGBA64{ - uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]), - uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]), - uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]), - uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]), + uint16(s[0])<<8 | uint16(s[1]), + uint16(s[2])<<8 | uint16(s[3]), + uint16(s[4])<<8 | uint16(s[5]), + uint16(s[6])<<8 | uint16(s[7]), } } @@ -199,14 +203,15 @@ func (p *RGBA64) Set(x, y int, c color.Color) { } i := p.PixOffset(x, y) c1 := color.RGBA64Model.Convert(c).(color.RGBA64) - p.Pix[i+0] = uint8(c1.R >> 8) - p.Pix[i+1] = uint8(c1.R) - p.Pix[i+2] = uint8(c1.G >> 8) - p.Pix[i+3] = uint8(c1.G) - p.Pix[i+4] = uint8(c1.B >> 8) - p.Pix[i+5] = uint8(c1.B) - p.Pix[i+6] = uint8(c1.A >> 8) - p.Pix[i+7] = uint8(c1.A) + s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = uint8(c1.R >> 8) + s[1] = uint8(c1.R) + s[2] = uint8(c1.G >> 8) + s[3] = uint8(c1.G) + s[4] = uint8(c1.B >> 8) + s[5] = uint8(c1.B) + s[6] = uint8(c1.A >> 8) + s[7] = uint8(c1.A) } func (p *RGBA64) SetRGBA64(x, y int, c color.RGBA64) { @@ -214,14 +219,15 @@ func (p *RGBA64) SetRGBA64(x, y int, c color.RGBA64) { return } i := p.PixOffset(x, y) - p.Pix[i+0] = uint8(c.R >> 8) - p.Pix[i+1] = uint8(c.R) - p.Pix[i+2] = uint8(c.G >> 8) - p.Pix[i+3] = uint8(c.G) - p.Pix[i+4] = uint8(c.B >> 8) - p.Pix[i+5] = uint8(c.B) - p.Pix[i+6] = uint8(c.A >> 8) - p.Pix[i+7] = uint8(c.A) + s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = uint8(c.R >> 8) + s[1] = uint8(c.R) + s[2] = uint8(c.G >> 8) + s[3] = uint8(c.G) + s[4] = uint8(c.B >> 8) + s[5] = uint8(c.B) + s[6] = uint8(c.A >> 8) + s[7] = uint8(c.A) } // SubImage returns an image representing the portion of the image p visible @@ -291,7 +297,8 @@ func (p *NRGBA) NRGBAAt(x, y int) color.NRGBA { return color.NRGBA{} } i := p.PixOffset(x, y) - return color.NRGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]} + s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + return color.NRGBA{s[0], s[1], s[2], s[3]} } // PixOffset returns the index of the first element of Pix that corresponds to @@ -306,10 +313,11 @@ func (p *NRGBA) Set(x, y int, c color.Color) { } i := p.PixOffset(x, y) c1 := color.NRGBAModel.Convert(c).(color.NRGBA) - p.Pix[i+0] = c1.R - p.Pix[i+1] = c1.G - p.Pix[i+2] = c1.B - p.Pix[i+3] = c1.A + s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = c1.R + s[1] = c1.G + s[2] = c1.B + s[3] = c1.A } func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) { @@ -317,10 +325,11 @@ func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) { return } i := p.PixOffset(x, y) - p.Pix[i+0] = c.R - p.Pix[i+1] = c.G - p.Pix[i+2] = c.B - p.Pix[i+3] = c.A + s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = c.R + s[1] = c.G + s[2] = c.B + s[3] = c.A } // SubImage returns an image representing the portion of the image p visible @@ -390,11 +399,12 @@ func (p *NRGBA64) NRGBA64At(x, y int) color.NRGBA64 { return color.NRGBA64{} } i := p.PixOffset(x, y) + s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857 return color.NRGBA64{ - uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]), - uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]), - uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]), - uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]), + uint16(s[0])<<8 | uint16(s[1]), + uint16(s[2])<<8 | uint16(s[3]), + uint16(s[4])<<8 | uint16(s[5]), + uint16(s[6])<<8 | uint16(s[7]), } } @@ -410,14 +420,15 @@ func (p *NRGBA64) Set(x, y int, c color.Color) { } i := p.PixOffset(x, y) c1 := color.NRGBA64Model.Convert(c).(color.NRGBA64) - p.Pix[i+0] = uint8(c1.R >> 8) - p.Pix[i+1] = uint8(c1.R) - p.Pix[i+2] = uint8(c1.G >> 8) - p.Pix[i+3] = uint8(c1.G) - p.Pix[i+4] = uint8(c1.B >> 8) - p.Pix[i+5] = uint8(c1.B) - p.Pix[i+6] = uint8(c1.A >> 8) - p.Pix[i+7] = uint8(c1.A) + s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = uint8(c1.R >> 8) + s[1] = uint8(c1.R) + s[2] = uint8(c1.G >> 8) + s[3] = uint8(c1.G) + s[4] = uint8(c1.B >> 8) + s[5] = uint8(c1.B) + s[6] = uint8(c1.A >> 8) + s[7] = uint8(c1.A) } func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) { @@ -425,14 +436,15 @@ func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) { return } i := p.PixOffset(x, y) - p.Pix[i+0] = uint8(c.R >> 8) - p.Pix[i+1] = uint8(c.R) - p.Pix[i+2] = uint8(c.G >> 8) - p.Pix[i+3] = uint8(c.G) - p.Pix[i+4] = uint8(c.B >> 8) - p.Pix[i+5] = uint8(c.B) - p.Pix[i+6] = uint8(c.A >> 8) - p.Pix[i+7] = uint8(c.A) + s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = uint8(c.R >> 8) + s[1] = uint8(c.R) + s[2] = uint8(c.G >> 8) + s[3] = uint8(c.G) + s[4] = uint8(c.B >> 8) + s[5] = uint8(c.B) + s[6] = uint8(c.A >> 8) + s[7] = uint8(c.A) } // SubImage returns an image representing the portion of the image p visible @@ -850,7 +862,8 @@ func (p *CMYK) CMYKAt(x, y int) color.CMYK { return color.CMYK{} } i := p.PixOffset(x, y) - return color.CMYK{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]} + s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + return color.CMYK{s[0], s[1], s[2], s[3]} } // PixOffset returns the index of the first element of Pix that corresponds to @@ -865,10 +878,11 @@ func (p *CMYK) Set(x, y int, c color.Color) { } i := p.PixOffset(x, y) c1 := color.CMYKModel.Convert(c).(color.CMYK) - p.Pix[i+0] = c1.C - p.Pix[i+1] = c1.M - p.Pix[i+2] = c1.Y - p.Pix[i+3] = c1.K + s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = c1.C + s[1] = c1.M + s[2] = c1.Y + s[3] = c1.K } func (p *CMYK) SetCMYK(x, y int, c color.CMYK) { @@ -876,10 +890,11 @@ func (p *CMYK) SetCMYK(x, y int, c color.CMYK) { return } i := p.PixOffset(x, y) - p.Pix[i+0] = c.C - p.Pix[i+1] = c.M - p.Pix[i+2] = c.Y - p.Pix[i+3] = c.K + s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = c.C + s[1] = c.M + s[2] = c.Y + s[3] = c.K } // SubImage returns an image representing the portion of the image p visible diff --git a/libgo/go/image/image_test.go b/libgo/go/image/image_test.go index 08ba61ea0c7..dfd8eb35a80 100644 --- a/libgo/go/image/image_test.go +++ b/libgo/go/image/image_test.go @@ -22,22 +22,29 @@ func cmp(cm color.Model, c0, c1 color.Color) bool { return r0 == r1 && g0 == g1 && b0 == b1 && a0 == a1 } -func TestImage(t *testing.T) { - testImage := []image{ - NewRGBA(Rect(0, 0, 10, 10)), - NewRGBA64(Rect(0, 0, 10, 10)), - NewNRGBA(Rect(0, 0, 10, 10)), - NewNRGBA64(Rect(0, 0, 10, 10)), - NewAlpha(Rect(0, 0, 10, 10)), - NewAlpha16(Rect(0, 0, 10, 10)), - NewGray(Rect(0, 0, 10, 10)), - NewGray16(Rect(0, 0, 10, 10)), - NewPaletted(Rect(0, 0, 10, 10), color.Palette{ +var testImages = []struct { + name string + image func() image +}{ + {"rgba", func() image { return NewRGBA(Rect(0, 0, 10, 10)) }}, + {"rgba64", func() image { return NewRGBA64(Rect(0, 0, 10, 10)) }}, + {"nrgba", func() image { return NewNRGBA(Rect(0, 0, 10, 10)) }}, + {"nrgba64", func() image { return NewNRGBA64(Rect(0, 0, 10, 10)) }}, + {"alpha", func() image { return NewAlpha(Rect(0, 0, 10, 10)) }}, + {"alpha16", func() image { return NewAlpha16(Rect(0, 0, 10, 10)) }}, + {"gray", func() image { return NewGray(Rect(0, 0, 10, 10)) }}, + {"gray16", func() image { return NewGray16(Rect(0, 0, 10, 10)) }}, + {"paletted", func() image { + return NewPaletted(Rect(0, 0, 10, 10), color.Palette{ Transparent, Opaque, - }), - } - for _, m := range testImage { + }) + }}, +} + +func TestImage(t *testing.T) { + for _, tc := range testImages { + m := tc.image() if !Rect(0, 0, 10, 10).Eq(m.Bounds()) { t.Errorf("%T: want bounds %v, got %v", m, Rect(0, 0, 10, 10), m.Bounds()) continue @@ -111,3 +118,182 @@ func Test16BitsPerColorChannel(t *testing.T) { } } } + +func BenchmarkAt(b *testing.B) { + for _, tc := range testImages { + b.Run(tc.name, func(b *testing.B) { + m := tc.image() + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.At(4, 5) + } + }) + } +} + +func BenchmarkSet(b *testing.B) { + c := color.Gray{0xff} + for _, tc := range testImages { + b.Run(tc.name, func(b *testing.B) { + m := tc.image() + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.Set(4, 5, c) + } + }) + } +} + +func BenchmarkRGBAAt(b *testing.B) { + m := NewRGBA(Rect(0, 0, 10, 10)) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.RGBAAt(4, 5) + } +} + +func BenchmarkRGBASetRGBA(b *testing.B) { + m := NewRGBA(Rect(0, 0, 10, 10)) + c := color.RGBA{0xff, 0xff, 0xff, 0x13} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.SetRGBA(4, 5, c) + } +} + +func BenchmarkRGBA64At(b *testing.B) { + m := NewRGBA64(Rect(0, 0, 10, 10)) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.RGBA64At(4, 5) + } +} + +func BenchmarkRGBA64SetRGBA64(b *testing.B) { + m := NewRGBA64(Rect(0, 0, 10, 10)) + c := color.RGBA64{0xffff, 0xffff, 0xffff, 0x1357} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.SetRGBA64(4, 5, c) + } +} + +func BenchmarkNRGBAAt(b *testing.B) { + m := NewNRGBA(Rect(0, 0, 10, 10)) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.NRGBAAt(4, 5) + } +} + +func BenchmarkNRGBASetNRGBA(b *testing.B) { + m := NewNRGBA(Rect(0, 0, 10, 10)) + c := color.NRGBA{0xff, 0xff, 0xff, 0x13} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.SetNRGBA(4, 5, c) + } +} + +func BenchmarkNRGBA64At(b *testing.B) { + m := NewNRGBA64(Rect(0, 0, 10, 10)) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.NRGBA64At(4, 5) + } +} + +func BenchmarkNRGBA64SetNRGBA64(b *testing.B) { + m := NewNRGBA64(Rect(0, 0, 10, 10)) + c := color.NRGBA64{0xffff, 0xffff, 0xffff, 0x1357} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.SetNRGBA64(4, 5, c) + } +} + +func BenchmarkAlphaAt(b *testing.B) { + m := NewAlpha(Rect(0, 0, 10, 10)) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.AlphaAt(4, 5) + } +} + +func BenchmarkAlphaSetAlpha(b *testing.B) { + m := NewAlpha(Rect(0, 0, 10, 10)) + c := color.Alpha{0x13} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.SetAlpha(4, 5, c) + } +} + +func BenchmarkAlpha16At(b *testing.B) { + m := NewAlpha16(Rect(0, 0, 10, 10)) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.Alpha16At(4, 5) + } +} + +func BenchmarkAlphaSetAlpha16(b *testing.B) { + m := NewAlpha16(Rect(0, 0, 10, 10)) + c := color.Alpha16{0x13} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.SetAlpha16(4, 5, c) + } +} + +func BenchmarkGrayAt(b *testing.B) { + m := NewGray(Rect(0, 0, 10, 10)) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.GrayAt(4, 5) + } +} + +func BenchmarkGraySetGray(b *testing.B) { + m := NewGray(Rect(0, 0, 10, 10)) + c := color.Gray{0x13} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.SetGray(4, 5, c) + } +} + +func BenchmarkGray16At(b *testing.B) { + m := NewGray16(Rect(0, 0, 10, 10)) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.Gray16At(4, 5) + } +} + +func BenchmarkGraySetGray16(b *testing.B) { + m := NewGray16(Rect(0, 0, 10, 10)) + c := color.Gray16{0x13} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.SetGray16(4, 5, c) + } +} diff --git a/libgo/go/image/jpeg/fdct.go b/libgo/go/image/jpeg/fdct.go index 3f8be4e3260..201a5abd0ba 100644 --- a/libgo/go/image/jpeg/fdct.go +++ b/libgo/go/image/jpeg/fdct.go @@ -123,14 +123,14 @@ func fdct(b *block) { tmp13 = tmp1 + tmp3 z1 = (tmp12 + tmp13) * fix_1_175875602 z1 += 1 << (constBits - pass1Bits - 1) - tmp0 = tmp0 * fix_1_501321110 - tmp1 = tmp1 * fix_3_072711026 - tmp2 = tmp2 * fix_2_053119869 - tmp3 = tmp3 * fix_0_298631336 - tmp10 = tmp10 * -fix_0_899976223 - tmp11 = tmp11 * -fix_2_562915447 - tmp12 = tmp12 * -fix_0_390180644 - tmp13 = tmp13 * -fix_1_961570560 + tmp0 *= fix_1_501321110 + tmp1 *= fix_3_072711026 + tmp2 *= fix_2_053119869 + tmp3 *= fix_0_298631336 + tmp10 *= -fix_0_899976223 + tmp11 *= -fix_2_562915447 + tmp12 *= -fix_0_390180644 + tmp13 *= -fix_1_961570560 tmp12 += z1 tmp13 += z1 @@ -171,14 +171,14 @@ func fdct(b *block) { tmp13 = tmp1 + tmp3 z1 = (tmp12 + tmp13) * fix_1_175875602 z1 += 1 << (constBits + pass1Bits - 1) - tmp0 = tmp0 * fix_1_501321110 - tmp1 = tmp1 * fix_3_072711026 - tmp2 = tmp2 * fix_2_053119869 - tmp3 = tmp3 * fix_0_298631336 - tmp10 = tmp10 * -fix_0_899976223 - tmp11 = tmp11 * -fix_2_562915447 - tmp12 = tmp12 * -fix_0_390180644 - tmp13 = tmp13 * -fix_1_961570560 + tmp0 *= fix_1_501321110 + tmp1 *= fix_3_072711026 + tmp2 *= fix_2_053119869 + tmp3 *= fix_0_298631336 + tmp10 *= -fix_0_899976223 + tmp11 *= -fix_2_562915447 + tmp12 *= -fix_0_390180644 + tmp13 *= -fix_1_961570560 tmp12 += z1 tmp13 += z1 diff --git a/libgo/go/image/png/reader_test.go b/libgo/go/image/png/reader_test.go index 66bcfcb437e..33dcd3debcc 100644 --- a/libgo/go/image/png/reader_test.go +++ b/libgo/go/image/png/reader_test.go @@ -364,10 +364,6 @@ func TestReader(t *testing.T) { } defer sf.Close() sb := bufio.NewScanner(sf) - if err != nil { - t.Error(fn, err) - continue - } // Compare the two, in SNG format, line by line. for { diff --git a/libgo/go/image/png/writer.go b/libgo/go/image/png/writer.go index 49f1ad2e7fa..c03335120eb 100644 --- a/libgo/go/image/png/writer.go +++ b/libgo/go/image/png/writer.go @@ -7,6 +7,7 @@ package png import ( "bufio" "compress/zlib" + "encoding/binary" "hash/crc32" "image" "image/color" @@ -62,14 +63,6 @@ const ( // compression level, although that is not implemented yet. ) -// Big-endian. -func writeUint32(b []uint8, u uint32) { - b[0] = uint8(u >> 24) - b[1] = uint8(u >> 16) - b[2] = uint8(u >> 8) - b[3] = uint8(u >> 0) -} - type opaquer interface { Opaque() bool } @@ -108,7 +101,7 @@ func (e *encoder) writeChunk(b []byte, name string) { e.err = UnsupportedError(name + " chunk is too large: " + strconv.Itoa(len(b))) return } - writeUint32(e.header[:4], n) + binary.BigEndian.PutUint32(e.header[:4], n) e.header[4] = name[0] e.header[5] = name[1] e.header[6] = name[2] @@ -116,7 +109,7 @@ func (e *encoder) writeChunk(b []byte, name string) { crc := crc32.NewIEEE() crc.Write(e.header[4:8]) crc.Write(b) - writeUint32(e.footer[:4], crc.Sum32()) + binary.BigEndian.PutUint32(e.footer[:4], crc.Sum32()) _, e.err = e.w.Write(e.header[:8]) if e.err != nil { @@ -131,8 +124,8 @@ func (e *encoder) writeChunk(b []byte, name string) { func (e *encoder) writeIHDR() { b := e.m.Bounds() - writeUint32(e.tmp[0:4], uint32(b.Dx())) - writeUint32(e.tmp[4:8], uint32(b.Dy())) + binary.BigEndian.PutUint32(e.tmp[0:4], uint32(b.Dx())) + binary.BigEndian.PutUint32(e.tmp[4:8], uint32(b.Dy())) // Set bit depth and color type. switch e.cb { case cbG8: @@ -144,6 +137,15 @@ func (e *encoder) writeIHDR() { case cbP8: e.tmp[8] = 8 e.tmp[9] = ctPaletted + case cbP4: + e.tmp[8] = 4 + e.tmp[9] = ctPaletted + case cbP2: + e.tmp[8] = 2 + e.tmp[9] = ctPaletted + case cbP1: + e.tmp[8] = 1 + e.tmp[9] = ctPaletted case cbTCA8: e.tmp[8] = 8 e.tmp[9] = ctTrueColorAlpha @@ -312,31 +314,38 @@ func (e *encoder) writeImage(w io.Writer, m image.Image, cb int, level int) erro } defer e.zw.Close() - bpp := 0 // Bytes per pixel. + bitsPerPixel := 0 switch cb { case cbG8: - bpp = 1 + bitsPerPixel = 8 case cbTC8: - bpp = 3 + bitsPerPixel = 24 case cbP8: - bpp = 1 + bitsPerPixel = 8 + case cbP4: + bitsPerPixel = 4 + case cbP2: + bitsPerPixel = 2 + case cbP1: + bitsPerPixel = 1 case cbTCA8: - bpp = 4 + bitsPerPixel = 32 case cbTC16: - bpp = 6 + bitsPerPixel = 48 case cbTCA16: - bpp = 8 + bitsPerPixel = 64 case cbG16: - bpp = 2 + bitsPerPixel = 16 } + // cr[*] and pr are the bytes for the current and previous row. // cr[0] is unfiltered (or equivalently, filtered with the ftNone filter). // cr[ft], for non-zero filter types ft, are buffers for transforming cr[0] under the // other PNG filter types. These buffers are allocated once and re-used for each row. // The +1 is for the per-row filter type, which is at cr[*][0]. b := m.Bounds() - sz := 1 + bpp*b.Dx() + sz := 1 + (bitsPerPixel*b.Dx()+7)/8 for i := range e.cr { if cap(e.cr[i]) < sz { e.cr[i] = make([]uint8, sz) @@ -412,6 +421,30 @@ func (e *encoder) writeImage(w io.Writer, m image.Image, cb int, level int) erro i += 1 } } + + case cbP4, cbP2, cbP1: + pi := m.(image.PalettedImage) + + var a uint8 + var c int + for x := b.Min.X; x < b.Max.X; x++ { + a = a<<uint(bitsPerPixel) | pi.ColorIndexAt(x, y) + c++ + if c == 8/bitsPerPixel { + cr[0][i] = a + i += 1 + a = 0 + c = 0 + } + } + if c != 0 { + for c != 8/bitsPerPixel { + a = a << uint(bitsPerPixel) + c++ + } + cr[0][i] = a + } + case cbTCA8: if nrgba != nil { offset := (y - b.Min.Y) * nrgba.Stride @@ -467,7 +500,10 @@ func (e *encoder) writeImage(w io.Writer, m image.Image, cb int, level int) erro // "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 && cb != cbP8 { + if level != zlib.NoCompression && cb != cbP8 && cb != cbP4 && cb != cbP2 && cb != cbP1 { + // Since we skip paletted images we don't have to worry about + // bitsPerPixel not being a multiple of 8 + bpp := bitsPerPixel / 8 f = filter(&cr, pr, bpp) } @@ -558,7 +594,15 @@ func (enc *Encoder) Encode(w io.Writer, m image.Image) error { pal, _ = m.ColorModel().(color.Palette) } if pal != nil { - e.cb = cbP8 + if len(pal) <= 2 { + e.cb = cbP1 + } else if len(pal) <= 4 { + e.cb = cbP2 + } else if len(pal) <= 16 { + e.cb = cbP4 + } else { + e.cb = cbP8 + } } else { switch m.ColorModel() { case color.GrayModel: diff --git a/libgo/go/image/png/writer_test.go b/libgo/go/image/png/writer_test.go index 1107ea0e7fc..5d131ff823a 100644 --- a/libgo/go/image/png/writer_test.go +++ b/libgo/go/image/png/writer_test.go @@ -6,9 +6,12 @@ package png import ( "bytes" + "compress/zlib" + "encoding/binary" "fmt" "image" "image/color" + "io" "io/ioutil" "testing" ) @@ -61,12 +64,12 @@ func TestWriter(t *testing.T) { m1, err := readPNG(qfn) if err != nil { t.Error(fn, err) - return + continue } m2, err := encodeDecode(m1) if err != nil { t.Error(fn, err) - return + continue } // Compare the two. err = diff(m0, m2) @@ -77,6 +80,111 @@ func TestWriter(t *testing.T) { } } +func TestWriterPaletted(t *testing.T) { + const width, height = 32, 16 + + testCases := []struct { + plen int + bitdepth uint8 + datalen int + }{ + + { + plen: 256, + bitdepth: 8, + datalen: (1 + width) * height, + }, + + { + plen: 128, + bitdepth: 8, + datalen: (1 + width) * height, + }, + + { + plen: 16, + bitdepth: 4, + datalen: (1 + width/2) * height, + }, + + { + plen: 4, + bitdepth: 2, + datalen: (1 + width/4) * height, + }, + + { + plen: 2, + bitdepth: 1, + datalen: (1 + width/8) * height, + }, + } + + for _, tc := range testCases { + t.Run(fmt.Sprintf("plen-%d", tc.plen), func(t *testing.T) { + // Create a paletted image with the correct palette length + palette := make(color.Palette, tc.plen) + for i := range palette { + palette[i] = color.NRGBA{ + R: uint8(i), + G: uint8(i), + B: uint8(i), + A: 255, + } + } + m0 := image.NewPaletted(image.Rect(0, 0, width, height), palette) + + i := 0 + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + m0.SetColorIndex(x, y, uint8(i%tc.plen)) + i++ + } + } + + // Encode the image + var b bytes.Buffer + if err := Encode(&b, m0); err != nil { + t.Error(err) + return + } + const chunkFieldsLength = 12 // 4 bytes for length, name and crc + data := b.Bytes() + i = len(pngHeader) + + for i < len(data)-chunkFieldsLength { + length := binary.BigEndian.Uint32(data[i : i+4]) + name := string(data[i+4 : i+8]) + + switch name { + case "IHDR": + bitdepth := data[i+8+8] + if bitdepth != tc.bitdepth { + t.Errorf("got bitdepth %d, want %d", bitdepth, tc.bitdepth) + } + case "IDAT": + // Uncompress the image data + r, err := zlib.NewReader(bytes.NewReader(data[i+8 : i+8+int(length)])) + if err != nil { + t.Error(err) + return + } + n, err := io.Copy(ioutil.Discard, r) + if err != nil { + t.Errorf("got error while reading image data: %v", err) + } + if n != int64(tc.datalen) { + t.Errorf("got uncompressed data length %d, want %d", n, tc.datalen) + } + } + + i += chunkFieldsLength + int(length) + } + }) + + } +} + func TestWriterLevels(t *testing.T) { m := image.NewNRGBA(image.Rect(0, 0, 100, 100)) |