summaryrefslogtreecommitdiff
path: root/libgo/go/image
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2019-01-18 19:04:36 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-01-18 19:04:36 +0000
commit4f4a855d82a889cebcfca150a7a43909bcb6a346 (patch)
treef12bae0781920fa34669fe30b6f4615a86d9fb80 /libgo/go/image
parent225220d668dafb8262db7012bced688acbe63b33 (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.go126
-rw-r--r--libgo/go/image/format.go13
-rw-r--r--libgo/go/image/image.go149
-rw-r--r--libgo/go/image/image_test.go214
-rw-r--r--libgo/go/image/jpeg/fdct.go32
-rw-r--r--libgo/go/image/png/reader_test.go4
-rw-r--r--libgo/go/image/png/writer.go90
-rw-r--r--libgo/go/image/png/writer_test.go112
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))