summaryrefslogtreecommitdiff
path: root/libgo/go/image
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/image')
-rw-r--r--libgo/go/image/color/color.go2
-rw-r--r--libgo/go/image/color/palette/gen.go2
-rw-r--r--libgo/go/image/color/palette/palette.go2
-rw-r--r--libgo/go/image/color/ycbcr.go110
-rw-r--r--libgo/go/image/color/ycbcr_test.go44
-rw-r--r--libgo/go/image/decode_test.go1
-rw-r--r--libgo/go/image/draw/draw.go10
-rw-r--r--libgo/go/image/gif/reader.go27
-rw-r--r--libgo/go/image/gif/reader_test.go80
-rw-r--r--libgo/go/image/internal/imageutil/gen.go59
-rw-r--r--libgo/go/image/internal/imageutil/impl.go232
-rw-r--r--libgo/go/image/jpeg/reader.go6
-rw-r--r--libgo/go/image/jpeg/scan.go128
-rw-r--r--libgo/go/image/png/reader.go7
-rw-r--r--libgo/go/image/png/reader_test.go27
-rw-r--r--libgo/go/image/testdata/video-001.progressive.truncated.jpegbin0 -> 7456 bytes
-rw-r--r--libgo/go/image/testdata/video-001.progressive.truncated.pngbin0 -> 23616 bytes
17 files changed, 505 insertions, 232 deletions
diff --git a/libgo/go/image/color/color.go b/libgo/go/image/color/color.go
index cae059b6daa..104433974ea 100644
--- a/libgo/go/image/color/color.go
+++ b/libgo/go/image/color/color.go
@@ -147,7 +147,7 @@ type Model interface {
func ModelFunc(f func(Color) Color) Model {
// Note: using *modelFunc as the implementation
// means that callers can still use comparisons
- // like m == RGBAModel. This is not possible if
+ // like m == RGBAModel. This is not possible if
// we use the func value directly, because funcs
// are no longer comparable.
return &modelFunc{f}
diff --git a/libgo/go/image/color/palette/gen.go b/libgo/go/image/color/palette/gen.go
index 2b5fdaaf2b3..57718e6a0c5 100644
--- a/libgo/go/image/color/palette/gen.go
+++ b/libgo/go/image/color/palette/gen.go
@@ -89,7 +89,7 @@ func printPlan9(w io.Writer) {
fmt.Fprintln(w, "// of continuous tones.")
fmt.Fprintln(w, "//")
fmt.Fprintln(w, "// This palette was used in the Plan 9 Operating System, described at")
- fmt.Fprintln(w, "// http://plan9.bell-labs.com/magic/man2html/6/color")
+ fmt.Fprintln(w, "// https://9p.io/magic/man2html/6/color")
fmt.Fprintln(w, "var Plan9 = []color.Color{")
for _, line := range lines {
fmt.Fprintln(w, line)
diff --git a/libgo/go/image/color/palette/palette.go b/libgo/go/image/color/palette/palette.go
index 0bf2c8e1aa5..b6954145204 100644
--- a/libgo/go/image/color/palette/palette.go
+++ b/libgo/go/image/color/palette/palette.go
@@ -19,7 +19,7 @@ import "image/color"
// of continuous tones.
//
// This palette was used in the Plan 9 Operating System, described at
-// http://plan9.bell-labs.com/magic/man2html/6/color
+// https://9p.io/magic/man2html/6/color
var Plan9 = []color.Color{
color.RGBA{0x00, 0x00, 0x00, 0xff},
color.RGBA{0x00, 0x00, 0x44, 0xff},
diff --git a/libgo/go/image/color/ycbcr.go b/libgo/go/image/color/ycbcr.go
index 904434f6a3d..3df5d3675d6 100644
--- a/libgo/go/image/color/ycbcr.go
+++ b/libgo/go/image/color/ycbcr.go
@@ -15,24 +15,37 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
r1 := int32(r)
g1 := int32(g)
b1 := int32(b)
+
+ // yy is in range [0,0xff].
yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
- cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
- cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
- if yy < 0 {
- yy = 0
- } else if yy > 0xff {
- yy = 0xff
- }
- if cb < 0 {
- cb = 0
- } else if cb > 0xff {
- cb = 0xff
+
+ // The bit twiddling below is equivalent to
+ //
+ // cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
+ // if cb < 0 {
+ // cb = 0
+ // } else if cb > 0xff {
+ // cb = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute cr uses a similar pattern.
+ cb := -11056*r1 - 21712*g1 + 32768*b1 + 257<<15
+ if uint32(cb)&0xff000000 == 0 {
+ cb >>= 16
+ } else {
+ cb = ^(cb >> 31)
}
- if cr < 0 {
- cr = 0
- } else if cr > 0xff {
- cr = 0xff
+
+ cr := 32768*r1 - 27440*g1 - 5328*b1 + 257<<15
+ if uint32(cr)&0xff000000 == 0 {
+ cr >>= 16
+ } else {
+ cr = ^(cr >> 31)
}
+
return uint8(yy), uint8(cb), uint8(cr)
}
@@ -44,27 +57,44 @@ func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
// B = Y' + 1.77200*(Cb-128)
// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
- yy1 := int32(y) * 0x10100 // Convert 0x12 to 0x121200.
+ yy1 := int32(y) * 0x010100 // Convert 0x12 to 0x121200.
cb1 := int32(cb) - 128
cr1 := int32(cr) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 0xff {
- r = 0xff
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 16
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 16
+ } else {
+ r = ^(r >> 31)
}
- if g < 0 {
- g = 0
- } else if g > 0xff {
- g = 0xff
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 16
+ } else {
+ g = ^(g >> 31)
}
- if b < 0 {
- b = 0
- } else if b > 0xff {
- b = 0xff
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 16
+ } else {
+ b = ^(b >> 31)
}
+
return uint8(r), uint8(g), uint8(b)
}
@@ -220,10 +250,10 @@ func RGBToCMYK(r, g, b uint8) (uint8, uint8, uint8, uint8) {
// CMYKToRGB converts a CMYK quadruple to an RGB triple.
func CMYKToRGB(c, m, y, k uint8) (uint8, uint8, uint8) {
- w := uint32(0xffff - uint32(k)*0x101)
- r := uint32(0xffff-uint32(c)*0x101) * w / 0xffff
- g := uint32(0xffff-uint32(m)*0x101) * w / 0xffff
- b := uint32(0xffff-uint32(y)*0x101) * w / 0xffff
+ w := 0xffff - uint32(k)*0x101
+ r := (0xffff - uint32(c)*0x101) * w / 0xffff
+ g := (0xffff - uint32(m)*0x101) * w / 0xffff
+ b := (0xffff - uint32(y)*0x101) * w / 0xffff
return uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)
}
@@ -239,11 +269,11 @@ func (c CMYK) RGBA() (uint32, uint32, uint32, uint32) {
// This code is a copy of the CMYKToRGB function above, except that it
// returns values in the range [0, 0xffff] instead of [0, 0xff].
- w := uint32(0xffff - uint32(c.K)*0x101)
- r := uint32(0xffff-uint32(c.C)*0x101) * w / 0xffff
- g := uint32(0xffff-uint32(c.M)*0x101) * w / 0xffff
- b := uint32(0xffff-uint32(c.Y)*0x101) * w / 0xffff
- return uint32(r), uint32(g), uint32(b), 0xffff
+ w := 0xffff - uint32(c.K)*0x101
+ r := (0xffff - uint32(c.C)*0x101) * w / 0xffff
+ g := (0xffff - uint32(c.M)*0x101) * w / 0xffff
+ b := (0xffff - uint32(c.Y)*0x101) * w / 0xffff
+ return r, g, b, 0xffff
}
// CMYKModel is the Model for CMYK colors.
diff --git a/libgo/go/image/color/ycbcr_test.go b/libgo/go/image/color/ycbcr_test.go
index f5e7cbf3358..561699f4e0e 100644
--- a/libgo/go/image/color/ycbcr_test.go
+++ b/libgo/go/image/color/ycbcr_test.go
@@ -171,3 +171,47 @@ func TestPalette(t *testing.T) {
t.Errorf("got %v, want %v", got, want)
}
}
+
+var sink uint8
+
+func BenchmarkYCbCrToRGB(b *testing.B) {
+ // YCbCrToRGB does saturating arithmetic.
+ // Low, middle, and high values can take
+ // different paths through the generated code.
+ b.Run("0", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink, sink, sink = YCbCrToRGB(0, 0, 0)
+ }
+ })
+ b.Run("128", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink, sink, sink = YCbCrToRGB(128, 128, 128)
+ }
+ })
+ b.Run("255", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink, sink, sink = YCbCrToRGB(255, 255, 255)
+ }
+ })
+}
+
+func BenchmarkRGBToYCbCr(b *testing.B) {
+ // RGBToYCbCr does saturating arithmetic.
+ // Different values can take different paths
+ // through the generated code.
+ b.Run("0", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink, sink, sink = RGBToYCbCr(0, 0, 0)
+ }
+ })
+ b.Run("Cb", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink, sink, sink = RGBToYCbCr(0, 0, 255)
+ }
+ })
+ b.Run("Cr", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink, sink, sink = RGBToYCbCr(255, 0, 0)
+ }
+ })
+}
diff --git a/libgo/go/image/decode_test.go b/libgo/go/image/decode_test.go
index d16ef8a1a4d..85e235e729b 100644
--- a/libgo/go/image/decode_test.go
+++ b/libgo/go/image/decode_test.go
@@ -36,6 +36,7 @@ var imageTests = []imageTest{
{"testdata/video-001.221212.png", "testdata/video-001.221212.jpeg", 8 << 8},
{"testdata/video-001.cmyk.png", "testdata/video-001.cmyk.jpeg", 8 << 8},
{"testdata/video-001.rgb.png", "testdata/video-001.rgb.jpeg", 8 << 8},
+ {"testdata/video-001.progressive.truncated.png", "testdata/video-001.progressive.truncated.jpeg", 8 << 8},
// Grayscale images.
{"testdata/video-005.gray.png", "testdata/video-005.gray.jpeg", 8 << 8},
{"testdata/video-005.gray.png", "testdata/video-005.gray.png", 0},
diff --git a/libgo/go/image/draw/draw.go b/libgo/go/image/draw/draw.go
index e47c48d961e..6a16cd39cf8 100644
--- a/libgo/go/image/draw/draw.go
+++ b/libgo/go/image/draw/draw.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 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.
@@ -634,10 +634,10 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
if !floydSteinberg {
continue
}
- er -= int32(palette[bestIndex][0])
- eg -= int32(palette[bestIndex][1])
- eb -= int32(palette[bestIndex][2])
- ea -= int32(palette[bestIndex][3])
+ er -= palette[bestIndex][0]
+ eg -= palette[bestIndex][1]
+ eb -= palette[bestIndex][2]
+ ea -= palette[bestIndex][3]
} else {
out.R = uint16(er)
diff --git a/libgo/go/image/gif/reader.go b/libgo/go/image/gif/reader.go
index 6a133124ad5..6181a946fad 100644
--- a/libgo/go/image/gif/reader.go
+++ b/libgo/go/image/gif/reader.go
@@ -96,7 +96,7 @@ type decoder struct {
// blockReader parses the block structure of GIF image data, which
// comprises (n, (n bytes)) blocks, with 1 <= n <= 255. It is the
// reader given to the LZW decoder, which is thus immune to the
-// blocking. After the LZW decoder completes, there will be a 0-byte
+// blocking. After the LZW decoder completes, there will be a 0-byte
// block remaining (0, ()), which is consumed when checking that the
// blockReader is exhausted.
type blockReader struct {
@@ -178,12 +178,25 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
}
m.Palette = d.globalColorTable
}
- if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) {
+ if d.hasTransparentIndex {
if !useLocalColorTable {
// Clone the global color table.
m.Palette = append(color.Palette(nil), d.globalColorTable...)
}
- m.Palette[d.transparentIndex] = color.RGBA{}
+ if ti := int(d.transparentIndex); ti < len(m.Palette) {
+ m.Palette[ti] = color.RGBA{}
+ } else {
+ // The transparentIndex is out of range, which is an error
+ // according to the spec, but Firefox and Google Chrome
+ // seem OK with this, so we enlarge the palette with
+ // transparent colors. See golang.org/issue/15059.
+ p := make(color.Palette, ti+1)
+ copy(p, m.Palette)
+ for i := len(m.Palette); i < len(p); i++ {
+ p[i] = color.RGBA{}
+ }
+ m.Palette = p
+ }
}
litWidth, err := d.r.ReadByte()
if err != nil {
@@ -210,7 +223,7 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
// for an image". In practice, though, giflib (a widely used C
// library) does not enforce this, so we also accept lzwr returning
// io.ErrUnexpectedEOF (meaning that the encoded stream hit io.EOF
- // before the LZW decoder saw an explict end code), provided that
+ // before the LZW decoder saw an explicit end code), provided that
// the io.ReadFull call above successfully read len(m.Pix) bytes.
// See https://golang.org/issue/9856 for an example GIF.
if n, err := lzwr.Read(d.tmp[:1]); n != 0 || (err != io.EOF && err != io.ErrUnexpectedEOF) {
@@ -349,6 +362,9 @@ func (d *decoder) readGraphicControl() error {
if _, err := io.ReadFull(d.r, d.tmp[:6]); err != nil {
return fmt.Errorf("gif: can't read graphic control: %s", err)
}
+ if d.tmp[0] != 4 {
+ return fmt.Errorf("gif: invalid graphic control extension block size: %d", d.tmp[0])
+ }
flags := d.tmp[1]
d.disposalMethod = (flags & gcDisposalMethodMask) >> 2
d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8
@@ -356,6 +372,9 @@ func (d *decoder) readGraphicControl() error {
d.transparentIndex = d.tmp[4]
d.hasTransparentIndex = true
}
+ if d.tmp[5] != 0 {
+ return fmt.Errorf("gif: invalid graphic control extension block terminator: %d", d.tmp[5])
+ }
return nil
}
diff --git a/libgo/go/image/gif/reader_test.go b/libgo/go/image/gif/reader_test.go
index c294195b6f7..90c81493cba 100644
--- a/libgo/go/image/gif/reader_test.go
+++ b/libgo/go/image/gif/reader_test.go
@@ -22,12 +22,16 @@ const (
trailerStr = "\x3b"
)
-// lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
-func lzwEncode(n int) []byte {
+// lzwEncode returns an LZW encoding (with 2-bit literals) of in.
+func lzwEncode(in []byte) []byte {
b := &bytes.Buffer{}
w := lzw.NewWriter(b, lzw.LSB, 2)
- w.Write(make([]byte, n))
- w.Close()
+ if _, err := w.Write(in); err != nil {
+ panic(err)
+ }
+ if err := w.Close(); err != nil {
+ panic(err)
+ }
return b.Bytes()
}
@@ -53,7 +57,7 @@ func TestDecode(t *testing.T) {
// byte, and 2-bit LZW literals.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
if tc.nPix > 0 {
- enc := lzwEncode(tc.nPix)
+ enc := lzwEncode(make([]byte, tc.nPix))
if len(enc) > 0xff {
t.Errorf("nPix=%d, extra=%t: compressed length %d is too large", tc.nPix, tc.extra, len(enc))
continue
@@ -97,13 +101,13 @@ func TestTransparentIndex(t *testing.T) {
for transparentIndex := 0; transparentIndex < 3; transparentIndex++ {
if transparentIndex < 2 {
// Write the graphic control for the transparent index.
- b.WriteString("\x21\xf9\x00\x01\x00\x00")
+ b.WriteString("\x21\xf9\x04\x01\x00\x00")
b.WriteByte(byte(transparentIndex))
b.WriteByte(0)
}
// Write an image with bounds 2x1, as per TestDecode.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
- enc := lzwEncode(2)
+ enc := lzwEncode([]byte{0x00, 0x00})
if len(enc) > 0xff {
t.Fatalf("compressed length %d is too large", len(enc))
}
@@ -196,21 +200,13 @@ func TestNoPalette(t *testing.T) {
b.WriteString(headerStr[:len(headerStr)-3])
b.WriteString("\x00\x00\x00") // No global palette.
- // Image descriptor: 2x1, no local palette.
+ // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
// Encode the pixels: neither is in range, because there is no palette.
- pix := []byte{0, 3}
- enc := &bytes.Buffer{}
- w := lzw.NewWriter(enc, lzw.LSB, 2)
- if _, err := w.Write(pix); err != nil {
- t.Fatalf("Write: %v", err)
- }
- if err := w.Close(); err != nil {
- t.Fatalf("Close: %v", err)
- }
- b.WriteByte(byte(len(enc.Bytes())))
- b.Write(enc.Bytes())
+ enc := lzwEncode([]byte{0x00, 0x03})
+ b.WriteByte(byte(len(enc)))
+ b.Write(enc)
b.WriteByte(0x00) // An empty block signifies the end of the image data.
b.WriteString(trailerStr)
@@ -226,21 +222,13 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
b.WriteString(headerStr)
b.WriteString(paletteStr)
- // Image descriptor: 2x1, no local palette.
+ // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
// Encode the pixels; some pvals trigger the expected error.
- pix := []byte{pval, pval}
- enc := &bytes.Buffer{}
- w := lzw.NewWriter(enc, lzw.LSB, 2)
- if _, err := w.Write(pix); err != nil {
- t.Fatalf("Write: %v", err)
- }
- if err := w.Close(); err != nil {
- t.Fatalf("Close: %v", err)
- }
- b.WriteByte(byte(len(enc.Bytes())))
- b.Write(enc.Bytes())
+ enc := lzwEncode([]byte{pval, pval})
+ b.WriteByte(byte(len(enc)))
+ b.Write(enc)
b.WriteByte(0x00) // An empty block signifies the end of the image data.
b.WriteString(trailerStr)
@@ -254,6 +242,36 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
}
}
+func TestTransparentPixelOutsidePaletteRange(t *testing.T) {
+ b := &bytes.Buffer{}
+
+ // Manufacture a GIF with a 2 color palette.
+ b.WriteString(headerStr)
+ b.WriteString(paletteStr)
+
+ // Graphic Control Extension: transparency, transparent color index = 3.
+ //
+ // This index, 3, is out of range of the global palette and there is no
+ // local palette in the subsequent image descriptor. This is an error
+ // according to the spec, but Firefox and Google Chrome seem OK with this.
+ //
+ // See golang.org/issue/15059.
+ b.WriteString("\x21\xf9\x04\x01\x00\x00\x03\x00")
+
+ // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
+ b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
+
+ // Encode the pixels.
+ enc := lzwEncode([]byte{0x03, 0x03})
+ b.WriteByte(byte(len(enc)))
+ b.Write(enc)
+ b.WriteByte(0x00) // An empty block signifies the end of the image data.
+
+ b.WriteString(trailerStr)
+
+ try(t, b.Bytes(), "")
+}
+
func TestLoopCount(t *testing.T) {
data := []byte("GIF89a000\x00000,0\x00\x00\x00\n\x00" +
"\n\x00\x80000000\x02\b\xf01u\xb9\xfdal\x05\x00;")
diff --git a/libgo/go/image/internal/imageutil/gen.go b/libgo/go/image/internal/imageutil/gen.go
index fc1e707f0fd..6792b28a45b 100644
--- a/libgo/go/image/internal/imageutil/gen.go
+++ b/libgo/go/image/internal/imageutil/gen.go
@@ -95,32 +95,51 @@ const sratioCase = `
%s
// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
- yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+ yy1 := int32(src.Y[yi]) * 0x010100 // Convert 0x12 to 0x121200.
cb1 := int32(src.Cb[ci]) - 128
cr1 := int32(src.Cr[ci]) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 255 {
- r = 255
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 16
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 16
+ } else {
+ r = ^(r >> 31)
}
- if g < 0 {
- g = 0
- } else if g > 255 {
- g = 255
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 16
+ } else {
+ g = ^(g >> 31)
}
- if b < 0 {
- b = 0
- } else if b > 255 {
- b = 255
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 16
+ } else {
+ b = ^(b >> 31)
}
- dpix[x+0] = uint8(r)
- dpix[x+1] = uint8(g)
- dpix[x+2] = uint8(b)
- dpix[x+3] = 255
+
+ // use a temp slice to hint to the compiler that a single bounds check suffices
+ rgba := dpix[x : x+4 : len(dpix)]
+ rgba[0] = uint8(r)
+ rgba[1] = uint8(g)
+ rgba[2] = uint8(b)
+ rgba[3] = 255
}
}
`
diff --git a/libgo/go/image/internal/imageutil/impl.go b/libgo/go/image/internal/imageutil/impl.go
index fd7826d4a97..3696b08e419 100644
--- a/libgo/go/image/internal/imageutil/impl.go
+++ b/libgo/go/image/internal/imageutil/impl.go
@@ -44,32 +44,50 @@ func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
- yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+ yy1 := int32(src.Y[yi]) * 0x010100 // Convert 0x12 to 0x121200.
cb1 := int32(src.Cb[ci]) - 128
cr1 := int32(src.Cr[ci]) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 255 {
- r = 255
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 16
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 16
+ } else {
+ r = ^(r >> 31)
}
- if g < 0 {
- g = 0
- } else if g > 255 {
- g = 255
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 16
+ } else {
+ g = ^(g >> 31)
}
- if b < 0 {
- b = 0
- } else if b > 255 {
- b = 255
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 16
+ } else {
+ b = ^(b >> 31)
}
- dpix[x+0] = uint8(r)
- dpix[x+1] = uint8(g)
- dpix[x+2] = uint8(b)
- dpix[x+3] = 255
+ // use a temp slice to hint to the compiler that a single bounds check suffices
+ rgba := dpix[x : x+4 : len(dpix)]
+ rgba[0] = uint8(r)
+ rgba[1] = uint8(g)
+ rgba[2] = uint8(b)
+ rgba[3] = 255
}
}
@@ -83,32 +101,50 @@ func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
ci := ciBase + sx/2
// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
- yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+ yy1 := int32(src.Y[yi]) * 0x010100 // Convert 0x12 to 0x121200.
cb1 := int32(src.Cb[ci]) - 128
cr1 := int32(src.Cr[ci]) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 255 {
- r = 255
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 16
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 16
+ } else {
+ r = ^(r >> 31)
}
- if g < 0 {
- g = 0
- } else if g > 255 {
- g = 255
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 16
+ } else {
+ g = ^(g >> 31)
}
- if b < 0 {
- b = 0
- } else if b > 255 {
- b = 255
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 16
+ } else {
+ b = ^(b >> 31)
}
- dpix[x+0] = uint8(r)
- dpix[x+1] = uint8(g)
- dpix[x+2] = uint8(b)
- dpix[x+3] = 255
+ // use a temp slice to hint to the compiler that a single bounds check suffices
+ rgba := dpix[x : x+4 : len(dpix)]
+ rgba[0] = uint8(r)
+ rgba[1] = uint8(g)
+ rgba[2] = uint8(b)
+ rgba[3] = 255
}
}
@@ -122,32 +158,50 @@ func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
ci := ciBase + sx/2
// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
- yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+ yy1 := int32(src.Y[yi]) * 0x010100 // Convert 0x12 to 0x121200.
cb1 := int32(src.Cb[ci]) - 128
cr1 := int32(src.Cr[ci]) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 255 {
- r = 255
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 16
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 16
+ } else {
+ r = ^(r >> 31)
}
- if g < 0 {
- g = 0
- } else if g > 255 {
- g = 255
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 16
+ } else {
+ g = ^(g >> 31)
}
- if b < 0 {
- b = 0
- } else if b > 255 {
- b = 255
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 16
+ } else {
+ b = ^(b >> 31)
}
- dpix[x+0] = uint8(r)
- dpix[x+1] = uint8(g)
- dpix[x+2] = uint8(b)
- dpix[x+3] = 255
+ // use a temp slice to hint to the compiler that a single bounds check suffices
+ rgba := dpix[x : x+4 : len(dpix)]
+ rgba[0] = uint8(r)
+ rgba[1] = uint8(g)
+ rgba[2] = uint8(b)
+ rgba[3] = 255
}
}
@@ -160,32 +214,50 @@ func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
- yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+ yy1 := int32(src.Y[yi]) * 0x010100 // Convert 0x12 to 0x121200.
cb1 := int32(src.Cb[ci]) - 128
cr1 := int32(src.Cr[ci]) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 255 {
- r = 255
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 16
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 16
+ } else {
+ r = ^(r >> 31)
}
- if g < 0 {
- g = 0
- } else if g > 255 {
- g = 255
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 16
+ } else {
+ g = ^(g >> 31)
}
- if b < 0 {
- b = 0
- } else if b > 255 {
- b = 255
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 16
+ } else {
+ b = ^(b >> 31)
}
- dpix[x+0] = uint8(r)
- dpix[x+1] = uint8(g)
- dpix[x+2] = uint8(b)
- dpix[x+3] = 255
+ // use a temp slice to hint to the compiler that a single bounds check suffices
+ rgba := dpix[x : x+4 : len(dpix)]
+ rgba[0] = uint8(r)
+ rgba[1] = uint8(g)
+ rgba[2] = uint8(b)
+ rgba[3] = 255
}
}
diff --git a/libgo/go/image/jpeg/reader.go b/libgo/go/image/jpeg/reader.go
index adf97abbd1d..c5834219a3e 100644
--- a/libgo/go/image/jpeg/reader.go
+++ b/libgo/go/image/jpeg/reader.go
@@ -641,6 +641,12 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
return nil, err
}
}
+
+ if d.progressive {
+ if err := d.reconstructProgressiveImage(); err != nil {
+ return nil, err
+ }
+ }
if d.img1 != nil {
return d.img1, nil
}
diff --git a/libgo/go/image/jpeg/scan.go b/libgo/go/image/jpeg/scan.go
index 99734c01af0..e1104d27c23 100644
--- a/libgo/go/image/jpeg/scan.go
+++ b/libgo/go/image/jpeg/scan.go
@@ -173,7 +173,6 @@ func (d *decoder) processSOS(n int) error {
compIndex := scan[i].compIndex
hi := d.comp[compIndex].h
vi := d.comp[compIndex].v
- qt := &d.quant[d.comp[compIndex].tq]
for j := 0; j < hi*vi; j++ {
// The blocks are traversed one MCU at a time. For 4:2:0 chroma
// subsampling, there are four Y 8x8 blocks in every 16x16 MCU.
@@ -286,55 +285,19 @@ func (d *decoder) processSOS(n int) error {
}
if d.progressive {
- if zigEnd != blockSize-1 || al != 0 {
- // We haven't completely decoded this 8x8 block. Save the coefficients.
- d.progCoeffs[compIndex][by*mxx*hi+bx] = b
- // At this point, we could execute the rest of the loop body to dequantize and
- // perform the inverse DCT, to save early stages of a progressive image to the
- // *image.YCbCr buffers (the whole point of progressive encoding), but in Go,
- // the jpeg.Decode function does not return until the entire image is decoded,
- // so we "continue" here to avoid wasted computation.
- continue
- }
- }
-
- // Dequantize, perform the inverse DCT and store the block to the image.
- for zig := 0; zig < blockSize; zig++ {
- b[unzig[zig]] *= qt[zig]
+ // Save the coefficients.
+ d.progCoeffs[compIndex][by*mxx*hi+bx] = b
+ // At this point, we could call reconstructBlock to dequantize and perform the
+ // inverse DCT, to save early stages of a progressive image to the *image.YCbCr
+ // buffers (the whole point of progressive encoding), but in Go, the jpeg.Decode
+ // function does not return until the entire image is decoded, so we "continue"
+ // here to avoid wasted computation. Instead, reconstructBlock is called on each
+ // accumulated block by the reconstructProgressiveImage method after all of the
+ // SOS markers are processed.
+ continue
}
- idct(&b)
- dst, stride := []byte(nil), 0
- if d.nComp == 1 {
- dst, stride = d.img1.Pix[8*(by*d.img1.Stride+bx):], d.img1.Stride
- } else {
- switch compIndex {
- case 0:
- dst, stride = d.img3.Y[8*(by*d.img3.YStride+bx):], d.img3.YStride
- case 1:
- dst, stride = d.img3.Cb[8*(by*d.img3.CStride+bx):], d.img3.CStride
- case 2:
- dst, stride = d.img3.Cr[8*(by*d.img3.CStride+bx):], d.img3.CStride
- case 3:
- dst, stride = d.blackPix[8*(by*d.blackStride+bx):], d.blackStride
- default:
- return UnsupportedError("too many components")
- }
- }
- // Level shift by +128, clip to [0, 255], and write to dst.
- for y := 0; y < 8; y++ {
- y8 := y * 8
- yStride := y * stride
- for x := 0; x < 8; x++ {
- c := b[y8+x]
- if c < -128 {
- c = 0
- } else if c > 127 {
- c = 255
- } else {
- c += 128
- }
- dst[yStride+x] = uint8(c)
- }
+ if err := d.reconstructBlock(&b, bx, by, int(compIndex)); err != nil {
+ return err
}
} // for j
} // for i
@@ -470,3 +433,70 @@ func (d *decoder) refineNonZeroes(b *block, zig, zigEnd, nz, delta int32) (int32
}
return zig, nil
}
+
+func (d *decoder) reconstructProgressiveImage() error {
+ // The h0, mxx, by and bx variables have the same meaning as in the
+ // processSOS method.
+ h0 := d.comp[0].h
+ mxx := (d.width + 8*h0 - 1) / (8 * h0)
+ for i := 0; i < d.nComp; i++ {
+ if d.progCoeffs[i] == nil {
+ continue
+ }
+ v := 8 * d.comp[0].v / d.comp[i].v
+ h := 8 * d.comp[0].h / d.comp[i].h
+ stride := mxx * d.comp[i].h
+ for by := 0; by*v < d.height; by++ {
+ for bx := 0; bx*h < d.width; bx++ {
+ if err := d.reconstructBlock(&d.progCoeffs[i][by*stride+bx], bx, by, i); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ return nil
+}
+
+// reconstructBlock dequantizes, performs the inverse DCT and stores the block
+// to the image.
+func (d *decoder) reconstructBlock(b *block, bx, by, compIndex int) error {
+ qt := &d.quant[d.comp[compIndex].tq]
+ for zig := 0; zig < blockSize; zig++ {
+ b[unzig[zig]] *= qt[zig]
+ }
+ idct(b)
+ dst, stride := []byte(nil), 0
+ if d.nComp == 1 {
+ dst, stride = d.img1.Pix[8*(by*d.img1.Stride+bx):], d.img1.Stride
+ } else {
+ switch compIndex {
+ case 0:
+ dst, stride = d.img3.Y[8*(by*d.img3.YStride+bx):], d.img3.YStride
+ case 1:
+ dst, stride = d.img3.Cb[8*(by*d.img3.CStride+bx):], d.img3.CStride
+ case 2:
+ dst, stride = d.img3.Cr[8*(by*d.img3.CStride+bx):], d.img3.CStride
+ case 3:
+ dst, stride = d.blackPix[8*(by*d.blackStride+bx):], d.blackStride
+ default:
+ return UnsupportedError("too many components")
+ }
+ }
+ // Level shift by +128, clip to [0, 255], and write to dst.
+ for y := 0; y < 8; y++ {
+ y8 := y * 8
+ yStride := y * stride
+ for x := 0; x < 8; x++ {
+ c := b[y8+x]
+ if c < -128 {
+ c = 0
+ } else if c > 127 {
+ c = 255
+ } else {
+ c += 128
+ }
+ dst[yStride+x] = uint8(c)
+ }
+ }
+ return nil
+}
diff --git a/libgo/go/image/png/reader.go b/libgo/go/image/png/reader.go
index 9e6f985f7e2..2dd5ed80736 100644
--- a/libgo/go/image/png/reader.go
+++ b/libgo/go/image/png/reader.go
@@ -717,6 +717,13 @@ func (d *decoder) parseChunk() error {
case "IDAT":
if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.stage == dsSeenIHDR && cbPaletted(d.cb)) {
return chunkOrderError
+ } else if d.stage == dsSeenIDAT {
+ // Ignore trailing zero-length or garbage IDAT chunks.
+ //
+ // This does not affect valid PNG images that contain multiple IDAT
+ // chunks, since the first call to parseIDAT below will consume all
+ // consecutive IDAT chunks required for decoding the image.
+ break
}
d.stage = dsSeenIDAT
return d.parseIDAT(length)
diff --git a/libgo/go/image/png/reader_test.go b/libgo/go/image/png/reader_test.go
index f058f6b2275..0bc4203acbe 100644
--- a/libgo/go/image/png/reader_test.go
+++ b/libgo/go/image/png/reader_test.go
@@ -350,6 +350,33 @@ func TestIncompleteIDATOnRowBoundary(t *testing.T) {
}
}
+func TestTrailingIDATChunks(t *testing.T) {
+ // The following is a valid 1x1 PNG image containing color.Gray{255} and
+ // a trailing zero-length IDAT chunk (see PNG specification section 12.9):
+ const (
+ ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x00\x00\x00\x00\x3a\x7e\x9b\x55"
+ idatWhite = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\xfa\x0f\x08\x00\x00\xff\xff\x01\x05\x01\x02\x5a\xdd\x39\xcd"
+ idatZero = "\x00\x00\x00\x00IDAT\x35\xaf\x06\x1e"
+ iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
+ )
+ _, err := Decode(strings.NewReader(pngHeader + ihdr + idatWhite + idatZero + iend))
+ if err != nil {
+ t.Fatalf("decoding valid image: %v", err)
+ }
+
+ // Non-zero-length trailing IDAT chunks should be ignored (recoverable error).
+ // The following chunk contains a single pixel with color.Gray{0}.
+ const idatBlack = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
+
+ img, err := Decode(strings.NewReader(pngHeader + ihdr + idatWhite + idatBlack + iend))
+ if err != nil {
+ t.Fatalf("trailing IDAT not ignored: %v", err)
+ }
+ if img.At(0, 0) == (color.Gray{0}) {
+ t.Fatal("decoded image from trailing IDAT chunk")
+ }
+}
+
func TestMultipletRNSChunks(t *testing.T) {
/*
The following is a valid 1x1 paletted PNG image with a 1-element palette
diff --git a/libgo/go/image/testdata/video-001.progressive.truncated.jpeg b/libgo/go/image/testdata/video-001.progressive.truncated.jpeg
new file mode 100644
index 00000000000..b5be8bc7639
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.progressive.truncated.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-001.progressive.truncated.png b/libgo/go/image/testdata/video-001.progressive.truncated.png
new file mode 100644
index 00000000000..baf19812265
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.progressive.truncated.png
Binary files differ