summaryrefslogtreecommitdiffstats
path: root/llgo/third_party/gofrontend/libgo/go/image
diff options
context:
space:
mode:
Diffstat (limited to 'llgo/third_party/gofrontend/libgo/go/image')
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/color/color.go58
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/color/ycbcr.go140
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/color/ycbcr_test.go130
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/decode_example_test.go32
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/decode_test.go14
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/draw/bench_test.go55
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/draw/clip_test.go30
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/draw/draw.go219
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/draw/draw_test.go40
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/geom.go44
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/geom_test.go115
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/gif/reader.go159
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/gif/reader_test.go49
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/gif/writer.go127
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/gif/writer_test.go280
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/image.go94
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/internal/imageutil/gen.go154
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/internal/imageutil/imageutil.go8
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/internal/imageutil/impl.go196
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/jpeg/huffman.go4
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/jpeg/reader.go451
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/jpeg/reader_test.go78
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/jpeg/scan.go86
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/png/reader.go40
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/png/reader_test.go89
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/png/testdata/benchRGB-interlace.pngbin0 -> 47483 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/png/testdata/gray-gradient.interlaced.pngbin0 -> 247 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/png/testdata/gray-gradient.pngbin0 -> 77 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.pngbin0 -> 358 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.sng57
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.221212.jpegbin0 -> 19263 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.221212.pngbin0 -> 29820 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.cmyk.jpegbin0 -> 19477 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.cmyk.pngbin0 -> 25439 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.410.jpegbin0 -> 3259 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.410.progressive.jpegbin0 -> 3125 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.411.jpegbin0 -> 3362 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.411.progressive.jpegbin0 -> 3251 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.rgb.jpegbin0 -> 6237 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.rgb.pngbin0 -> 20414 bytes
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/ycbcr.go29
-rw-r--r--llgo/third_party/gofrontend/libgo/go/image/ycbcr_test.go26
42 files changed, 2369 insertions, 435 deletions
diff --git a/llgo/third_party/gofrontend/libgo/go/image/color/color.go b/llgo/third_party/gofrontend/libgo/go/image/color/color.go
index ff596a76a36..cae059b6daa 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/color/color.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/color/color.go
@@ -9,14 +9,20 @@ package color
// The conversion may be lossy.
type Color interface {
// RGBA returns the alpha-premultiplied red, green, blue and alpha values
- // for the color. Each value ranges within [0, 0xFFFF], but is represented
- // by a uint32 so that multiplying by a blend factor up to 0xFFFF will not
+ // for the color. Each value ranges within [0, 0xffff], but is represented
+ // by a uint32 so that multiplying by a blend factor up to 0xffff will not
// overflow.
+ //
+ // An alpha-premultiplied color component c has been scaled by alpha (a),
+ // so has valid values 0 <= c <= a.
RGBA() (r, g, b, a uint32)
}
-// RGBA represents a traditional 32-bit alpha-premultiplied color,
-// having 8 bits for each of red, green, blue and alpha.
+// RGBA represents a traditional 32-bit alpha-premultiplied color, having 8
+// bits for each of red, green, blue and alpha.
+//
+// An alpha-premultiplied color component C has been scaled by alpha (A), so
+// has valid values 0 <= C <= A.
type RGBA struct {
R, G, B, A uint8
}
@@ -33,8 +39,11 @@ func (c RGBA) RGBA() (r, g, b, a uint32) {
return
}
-// RGBA64 represents a 64-bit alpha-premultiplied color,
-// having 16 bits for each of red, green, blue and alpha.
+// RGBA64 represents a 64-bit alpha-premultiplied color, having 16 bits for
+// each of red, green, blue and alpha.
+//
+// An alpha-premultiplied color component C has been scaled by alpha (A), so
+// has valid values 0 <= C <= A.
type RGBA64 struct {
R, G, B, A uint16
}
@@ -262,32 +271,39 @@ func (p Palette) Convert(c Color) Color {
}
// Index returns the index of the palette color closest to c in Euclidean
-// R,G,B space.
+// R,G,B,A space.
func (p Palette) Index(c Color) int {
// A batch version of this computation is in image/draw/draw.go.
- cr, cg, cb, _ := c.RGBA()
- ret, bestSSD := 0, uint32(1<<32-1)
+ cr, cg, cb, ca := c.RGBA()
+ ret, bestSum := 0, uint32(1<<32-1)
for i, v := range p {
- vr, vg, vb, _ := v.RGBA()
- // We shift by 1 bit to avoid potential uint32 overflow in
- // sum-squared-difference.
- delta := (int32(cr) - int32(vr)) >> 1
- ssd := uint32(delta * delta)
- delta = (int32(cg) - int32(vg)) >> 1
- ssd += uint32(delta * delta)
- delta = (int32(cb) - int32(vb)) >> 1
- ssd += uint32(delta * delta)
- if ssd < bestSSD {
- if ssd == 0 {
+ vr, vg, vb, va := v.RGBA()
+ sum := sqDiff(cr, vr) + sqDiff(cg, vg) + sqDiff(cb, vb) + sqDiff(ca, va)
+ if sum < bestSum {
+ if sum == 0 {
return i
}
- ret, bestSSD = i, ssd
+ ret, bestSum = i, sum
}
}
return ret
}
+// sqDiff returns the squared-difference of x and y, shifted by 2 so that
+// adding four of those won't overflow a uint32.
+//
+// x and y are both assumed to be in the range [0, 0xffff].
+func sqDiff(x, y uint32) uint32 {
+ var d uint32
+ if x > y {
+ d = x - y
+ } else {
+ d = y - x
+ }
+ return (d * d) >> 2
+}
+
// Standard colors.
var (
Black = Gray16{0}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/color/ycbcr.go b/llgo/third_party/gofrontend/libgo/go/image/color/ycbcr.go
index 4c2f29ea021..4bcb07dce22 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/color/ycbcr.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/color/ycbcr.go
@@ -11,26 +11,27 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
// Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
// Cr = 0.5000*R - 0.4187*G - 0.0813*B + 128
// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
- r1 := int(r)
- g1 := int(g)
- b1 := int(b)
+
+ r1 := int32(r)
+ g1 := int32(g)
+ b1 := int32(b)
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 > 255 {
- yy = 255
+ } else if yy > 0xff {
+ yy = 0xff
}
if cb < 0 {
cb = 0
- } else if cb > 255 {
- cb = 255
+ } else if cb > 0xff {
+ cb = 0xff
}
if cr < 0 {
cr = 0
- } else if cr > 255 {
- cr = 255
+ } else if cr > 0xff {
+ cr = 0xff
}
return uint8(yy), uint8(cb), uint8(cr)
}
@@ -42,26 +43,27 @@ func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
// G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
// B = Y' + 1.77200*(Cb-128)
// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
- yy1 := int(y)<<16 + 1<<15
- cb1 := int(cb) - 128
- cr1 := int(cr) - 128
+
+ yy1 := int32(y) * 0x10100 // 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 > 255 {
- r = 255
+ } else if r > 0xff {
+ r = 0xff
}
if g < 0 {
g = 0
- } else if g > 255 {
- g = 255
+ } else if g > 0xff {
+ g = 0xff
}
if b < 0 {
b = 0
- } else if b > 255 {
- b = 255
+ } else if b > 0xff {
+ b = 0xff
}
return uint8(r), uint8(g), uint8(b)
}
@@ -82,8 +84,45 @@ type YCbCr struct {
}
func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) {
- r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr)
- return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
+ // This code is a copy of the YCbCrToRGB function above, except that it
+ // returns values in the range [0, 0xffff] instead of [0, 0xff]. There is a
+ // subtle difference between doing this and having YCbCr satisfy the Color
+ // interface by first converting to an RGBA. The latter loses some
+ // information by going to and from 8 bits per channel.
+ //
+ // For example, this code:
+ // const y, cb, cr = 0x7f, 0x7f, 0x7f
+ // r, g, b := color.YCbCrToRGB(y, cb, cr)
+ // r0, g0, b0, _ := color.YCbCr{y, cb, cr}.RGBA()
+ // r1, g1, b1, _ := color.RGBA{r, g, b, 0xff}.RGBA()
+ // fmt.Printf("0x%04x 0x%04x 0x%04x\n", r0, g0, b0)
+ // fmt.Printf("0x%04x 0x%04x 0x%04x\n", r1, g1, b1)
+ // prints:
+ // 0x7e18 0x808e 0x7db9
+ // 0x7e7e 0x8080 0x7d7d
+
+ yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
+ cb1 := int32(c.Cb) - 128
+ cr1 := int32(c.Cr) - 128
+ r := (yy1 + 91881*cr1) >> 8
+ g := (yy1 - 22554*cb1 - 46802*cr1) >> 8
+ b := (yy1 + 116130*cb1) >> 8
+ if r < 0 {
+ r = 0
+ } else if r > 0xffff {
+ r = 0xffff
+ }
+ if g < 0 {
+ g = 0
+ } else if g > 0xffff {
+ g = 0xffff
+ }
+ if b < 0 {
+ b = 0
+ } else if b > 0xffff {
+ b = 0xffff
+ }
+ return uint32(r), uint32(g), uint32(b), 0xffff
}
// YCbCrModel is the Model for Y'CbCr colors.
@@ -97,3 +136,64 @@ func yCbCrModel(c Color) Color {
y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
return YCbCr{y, u, v}
}
+
+// RGBToCMYK converts an RGB triple to a CMYK quadruple.
+func RGBToCMYK(r, g, b uint8) (uint8, uint8, uint8, uint8) {
+ rr := uint32(r)
+ gg := uint32(g)
+ bb := uint32(b)
+ w := rr
+ if w < gg {
+ w = gg
+ }
+ if w < bb {
+ w = bb
+ }
+ if w == 0 {
+ return 0, 0, 0, 0xff
+ }
+ c := (w - rr) * 0xff / w
+ m := (w - gg) * 0xff / w
+ y := (w - bb) * 0xff / w
+ return uint8(c), uint8(m), uint8(y), uint8(0xff - w)
+}
+
+// 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
+ return uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)
+}
+
+// CMYK represents a fully opaque CMYK color, having 8 bits for each of cyan,
+// magenta, yellow and black.
+//
+// It is not associated with any particular color profile.
+type CMYK struct {
+ C, M, Y, K uint8
+}
+
+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
+}
+
+// CMYKModel is the Model for CMYK colors.
+var CMYKModel Model = ModelFunc(cmykModel)
+
+func cmykModel(c Color) Color {
+ if _, ok := c.(CMYK); ok {
+ return c
+ }
+ r, g, b, _ := c.RGBA()
+ cc, mm, yy, kk := RGBToCMYK(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+ return CMYK{cc, mm, yy, kk}
+}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/color/ycbcr_test.go b/llgo/third_party/gofrontend/libgo/go/image/color/ycbcr_test.go
index 92a0e6ff1e7..5da49d379aa 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/color/ycbcr_test.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/color/ycbcr_test.go
@@ -5,6 +5,7 @@
package color
import (
+ "fmt"
"testing"
)
@@ -15,19 +16,134 @@ func delta(x, y uint8) uint8 {
return y - x
}
-// Test that a subset of RGB space can be converted to YCbCr and back to within
-// 1/256 tolerance.
-func TestRoundtrip(t *testing.T) {
- for r := 0; r < 255; r += 7 {
- for g := 0; g < 255; g += 5 {
- for b := 0; b < 255; b += 3 {
+func eq(c0, c1 Color) error {
+ r0, g0, b0, a0 := c0.RGBA()
+ r1, g1, b1, a1 := c1.RGBA()
+ if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
+ return fmt.Errorf("got 0x%04x 0x%04x 0x%04x 0x%04x\nwant 0x%04x 0x%04x 0x%04x 0x%04x",
+ r0, g0, b0, a0, r1, g1, b1, a1)
+ }
+ return nil
+}
+
+// TestYCbCrRoundtrip tests that a subset of RGB space can be converted to YCbCr
+// and back to within 2/256 tolerance.
+func TestYCbCrRoundtrip(t *testing.T) {
+ for r := 0; r < 256; r += 7 {
+ for g := 0; g < 256; g += 5 {
+ for b := 0; b < 256; b += 3 {
r0, g0, b0 := uint8(r), uint8(g), uint8(b)
y, cb, cr := RGBToYCbCr(r0, g0, b0)
r1, g1, b1 := YCbCrToRGB(y, cb, cr)
+ if delta(r0, r1) > 2 || delta(g0, g1) > 2 || delta(b0, b1) > 2 {
+ t.Fatalf("\nr0, g0, b0 = %d, %d, %d\ny, cb, cr = %d, %d, %d\nr1, g1, b1 = %d, %d, %d",
+ r0, g0, b0, y, cb, cr, r1, g1, b1)
+ }
+ }
+ }
+ }
+}
+
+// TestYCbCrToRGBConsistency tests that calling the RGBA method (16 bit color)
+// then truncating to 8 bits is equivalent to calling the YCbCrToRGB function (8
+// bit color).
+func TestYCbCrToRGBConsistency(t *testing.T) {
+ for y := 0; y < 256; y += 7 {
+ for cb := 0; cb < 256; cb += 5 {
+ for cr := 0; cr < 256; cr += 3 {
+ x := YCbCr{uint8(y), uint8(cb), uint8(cr)}
+ r0, g0, b0, _ := x.RGBA()
+ r1, g1, b1 := uint8(r0>>8), uint8(g0>>8), uint8(b0>>8)
+ r2, g2, b2 := YCbCrToRGB(x.Y, x.Cb, x.Cr)
+ if r1 != r2 || g1 != g2 || b1 != b2 {
+ t.Fatalf("y, cb, cr = %d, %d, %d\nr1, g1, b1 = %d, %d, %d\nr2, g2, b2 = %d, %d, %d",
+ y, cb, cr, r1, g1, b1, r2, g2, b2)
+ }
+ }
+ }
+ }
+}
+
+// TestYCbCrGray tests that YCbCr colors are a superset of Gray colors.
+func TestYCbCrGray(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ if err := eq(YCbCr{uint8(i), 0x80, 0x80}, Gray{uint8(i)}); err != nil {
+ t.Errorf("i=0x%02x:\n%v", i, err)
+ }
+ }
+}
+
+// TestCMYKRoundtrip tests that a subset of RGB space can be converted to CMYK
+// and back to within 1/256 tolerance.
+func TestCMYKRoundtrip(t *testing.T) {
+ for r := 0; r < 256; r += 7 {
+ for g := 0; g < 256; g += 5 {
+ for b := 0; b < 256; b += 3 {
+ r0, g0, b0 := uint8(r), uint8(g), uint8(b)
+ c, m, y, k := RGBToCMYK(r0, g0, b0)
+ r1, g1, b1 := CMYKToRGB(c, m, y, k)
if delta(r0, r1) > 1 || delta(g0, g1) > 1 || delta(b0, b1) > 1 {
- t.Fatalf("r0, g0, b0 = %d, %d, %d r1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1)
+ t.Fatalf("\nr0, g0, b0 = %d, %d, %d\nc, m, y, k = %d, %d, %d, %d\nr1, g1, b1 = %d, %d, %d",
+ r0, g0, b0, c, m, y, k, r1, g1, b1)
}
}
}
}
}
+
+// TestCMYKToRGBConsistency tests that calling the RGBA method (16 bit color)
+// then truncating to 8 bits is equivalent to calling the CMYKToRGB function (8
+// bit color).
+func TestCMYKToRGBConsistency(t *testing.T) {
+ for c := 0; c < 256; c += 7 {
+ for m := 0; m < 256; m += 5 {
+ for y := 0; y < 256; y += 3 {
+ for k := 0; k < 256; k += 11 {
+ x := CMYK{uint8(c), uint8(m), uint8(y), uint8(k)}
+ r0, g0, b0, _ := x.RGBA()
+ r1, g1, b1 := uint8(r0>>8), uint8(g0>>8), uint8(b0>>8)
+ r2, g2, b2 := CMYKToRGB(x.C, x.M, x.Y, x.K)
+ if r1 != r2 || g1 != g2 || b1 != b2 {
+ t.Fatalf("c, m, y, k = %d, %d, %d, %d\nr1, g1, b1 = %d, %d, %d\nr2, g2, b2 = %d, %d, %d",
+ c, m, y, k, r1, g1, b1, r2, g2, b2)
+ }
+ }
+ }
+ }
+ }
+}
+
+// TestCMYKGray tests that CMYK colors are a superset of Gray colors.
+func TestCMYKGray(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ if err := eq(CMYK{0x00, 0x00, 0x00, uint8(255 - i)}, Gray{uint8(i)}); err != nil {
+ t.Errorf("i=0x%02x:\n%v", i, err)
+ }
+ }
+}
+
+func TestPalette(t *testing.T) {
+ p := Palette{
+ RGBA{0xff, 0xff, 0xff, 0xff},
+ RGBA{0x80, 0x00, 0x00, 0xff},
+ RGBA{0x7f, 0x00, 0x00, 0x7f},
+ RGBA{0x00, 0x00, 0x00, 0x7f},
+ RGBA{0x00, 0x00, 0x00, 0x00},
+ RGBA{0x40, 0x40, 0x40, 0x40},
+ }
+ // Check that, for a Palette with no repeated colors, the closest color to
+ // each element is itself.
+ for i, c := range p {
+ j := p.Index(c)
+ if i != j {
+ t.Errorf("Index(%v): got %d (color = %v), want %d", c, j, p[j], i)
+ }
+ }
+ // Check that finding the closest color considers alpha, not just red,
+ // green and blue.
+ got := p.Convert(RGBA{0x80, 0x00, 0x00, 0x80})
+ want := RGBA{0x7f, 0x00, 0x00, 0x7f}
+ if got != want {
+ t.Errorf("got %v, want %v", got, want)
+ }
+}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/decode_example_test.go b/llgo/third_party/gofrontend/libgo/go/image/decode_example_test.go
index 21e90fea4f8..81fa0378e17 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/decode_example_test.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/decode_example_test.go
@@ -61,22 +61,22 @@ func Example() {
}
// Output:
// bin red green blue alpha
- // 0x0000-0x0fff: 353 759 7228 0
- // 0x1000-0x1fff: 629 2944 1036 0
- // 0x2000-0x2fff: 1075 2319 984 0
- // 0x3000-0x3fff: 838 2291 988 0
- // 0x4000-0x4fff: 540 1302 542 0
- // 0x5000-0x5fff: 319 971 263 0
- // 0x6000-0x6fff: 316 377 178 0
- // 0x7000-0x7fff: 581 280 216 0
- // 0x8000-0x8fff: 3457 228 274 0
- // 0x9000-0x9fff: 2294 237 334 0
- // 0xa000-0xafff: 938 283 370 0
- // 0xb000-0xbfff: 322 338 401 0
- // 0xc000-0xcfff: 229 386 295 0
- // 0xd000-0xdfff: 263 416 281 0
- // 0xe000-0xefff: 538 433 312 0
- // 0xf000-0xffff: 2758 1886 1748 15450
+ // 0x0000-0x0fff: 364 790 7242 0
+ // 0x1000-0x1fff: 645 2967 1039 0
+ // 0x2000-0x2fff: 1072 2299 979 0
+ // 0x3000-0x3fff: 820 2266 980 0
+ // 0x4000-0x4fff: 537 1305 541 0
+ // 0x5000-0x5fff: 319 962 261 0
+ // 0x6000-0x6fff: 322 375 177 0
+ // 0x7000-0x7fff: 601 279 214 0
+ // 0x8000-0x8fff: 3478 227 273 0
+ // 0x9000-0x9fff: 2260 234 329 0
+ // 0xa000-0xafff: 921 282 373 0
+ // 0xb000-0xbfff: 321 335 397 0
+ // 0xc000-0xcfff: 229 388 298 0
+ // 0xd000-0xdfff: 260 414 277 0
+ // 0xe000-0xefff: 516 428 298 0
+ // 0xf000-0xffff: 2785 1899 1772 15450
}
const data = `
diff --git a/llgo/third_party/gofrontend/libgo/go/image/decode_test.go b/llgo/third_party/gofrontend/libgo/go/image/decode_test.go
index 8dee57ee467..d16ef8a1a4d 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/decode_test.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/decode_test.go
@@ -6,6 +6,7 @@ package image_test
import (
"bufio"
+ "fmt"
"image"
"image/color"
"os"
@@ -32,6 +33,9 @@ var imageTests = []imageTest{
// JPEG is a lossy format and hence needs a non-zero tolerance.
{"testdata/video-001.png", "testdata/video-001.jpeg", 8 << 8},
{"testdata/video-001.png", "testdata/video-001.progressive.jpeg", 8 << 8},
+ {"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},
// 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},
@@ -74,6 +78,11 @@ func withinTolerance(c0, c1 color.Color, tolerance int) bool {
}
func TestDecode(t *testing.T) {
+ rgba := func(c color.Color) string {
+ r, g, b, a := c.RGBA()
+ return fmt.Sprintf("rgba = 0x%04x, 0x%04x, 0x%04x, 0x%04x for %T%v", r, g, b, a, c, c)
+ }
+
golden := make(map[string]image.Image)
loop:
for _, it := range imageTests {
@@ -94,13 +103,14 @@ loop:
}
b := g.Bounds()
if !b.Eq(m.Bounds()) {
- t.Errorf("%s: want bounds %v got %v", it.filename, b, m.Bounds())
+ t.Errorf("%s: got bounds %v want %v", it.filename, m.Bounds(), b)
continue loop
}
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
if !withinTolerance(g.At(x, y), m.At(x, y), it.tolerance) {
- t.Errorf("%s: at (%d, %d), want %v got %v", it.filename, x, y, g.At(x, y), m.At(x, y))
+ t.Errorf("%s: at (%d, %d):\ngot %v\nwant %v",
+ it.filename, x, y, rgba(m.At(x, y)), rgba(g.At(x, y)))
continue loop
}
}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/draw/bench_test.go b/llgo/third_party/gofrontend/libgo/go/image/draw/bench_test.go
index cc62e25f1bb..7b89f95d118 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/draw/bench_test.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/draw/bench_test.go
@@ -7,6 +7,7 @@ package draw
import (
"image"
"image/color"
+ "reflect"
"testing"
)
@@ -15,6 +16,11 @@ const (
srcw, srch = 400, 300
)
+var palette = color.Palette{
+ color.Black,
+ color.White,
+}
+
// bench benchmarks drawing src and mask images onto a dst image with the
// given op and the color models to create those images from.
// The created images' pixels are initialized to non-zero values.
@@ -50,13 +56,48 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
}
dst = dst1
default:
- b.Fatal("unknown destination color model", dcm)
+ // The == operator isn't defined on a color.Palette (a slice), so we
+ // use reflection.
+ if reflect.DeepEqual(dcm, palette) {
+ dst1 := image.NewPaletted(image.Rect(0, 0, dstw, dsth), palette)
+ for y := 0; y < dsth; y++ {
+ for x := 0; x < dstw; x++ {
+ dst1.SetColorIndex(x, y, uint8(x^y)&1)
+ }
+ }
+ dst = dst1
+ } else {
+ b.Fatal("unknown destination color model", dcm)
+ }
}
var src image.Image
switch scm {
case nil:
src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0xff}}
+ case color.CMYKModel:
+ src1 := image.NewCMYK(image.Rect(0, 0, srcw, srch))
+ for y := 0; y < srch; y++ {
+ for x := 0; x < srcw; x++ {
+ src1.SetCMYK(x, y, color.CMYK{
+ uint8(13 * x % 0x100),
+ uint8(11 * y % 0x100),
+ uint8((11*x + 13*y) % 0x100),
+ uint8((31*x + 37*y) % 0x100),
+ })
+ }
+ }
+ src = src1
+ case color.GrayModel:
+ src1 := image.NewGray(image.Rect(0, 0, srcw, srch))
+ for y := 0; y < srch; y++ {
+ for x := 0; x < srcw; x++ {
+ src1.SetGray(x, y, color.Gray{
+ uint8((11*x + 13*y) % 0x100),
+ })
+ }
+ }
+ src = src1
case color.RGBAModel:
src1 := image.NewRGBA(image.Rect(0, 0, srcw, srch))
for y := 0; y < srch; y++ {
@@ -179,6 +220,14 @@ func BenchmarkYCbCr(b *testing.B) {
bench(b, color.RGBAModel, color.YCbCrModel, nil, Over)
}
+func BenchmarkGray(b *testing.B) {
+ bench(b, color.RGBAModel, color.GrayModel, nil, Over)
+}
+
+func BenchmarkCMYK(b *testing.B) {
+ bench(b, color.RGBAModel, color.CMYKModel, nil, Over)
+}
+
func BenchmarkGlyphOver(b *testing.B) {
bench(b, color.RGBAModel, nil, color.AlphaModel, Over)
}
@@ -187,6 +236,10 @@ func BenchmarkRGBA(b *testing.B) {
bench(b, color.RGBAModel, color.RGBA64Model, nil, Src)
}
+func BenchmarkPaletted(b *testing.B) {
+ bench(b, palette, color.RGBAModel, nil, Src)
+}
+
// The BenchmarkGenericFoo functions exercise the generic, slow-path code.
func BenchmarkGenericOver(b *testing.B) {
diff --git a/llgo/third_party/gofrontend/libgo/go/image/draw/clip_test.go b/llgo/third_party/gofrontend/libgo/go/image/draw/clip_test.go
index 65381f72f65..0abf53e5c78 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/draw/clip_test.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/draw/clip_test.go
@@ -139,7 +139,19 @@ var clipTests = []clipTest{
image.Pt(20, 0),
image.Pt(20, 0),
},
- // TODO(nigeltao): write more tests.
+ {
+ "clip sr and mr",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 100, 100),
+ image.Rect(23, 23, 55, 86),
+ image.Rect(44, 44, 87, 58),
+ image.Pt(10, 10),
+ image.Pt(11, 11),
+ false,
+ image.Rect(33, 33, 45, 47),
+ image.Pt(43, 43),
+ image.Pt(44, 44),
+ },
}
func TestClip(t *testing.T) {
@@ -149,12 +161,12 @@ func TestClip(t *testing.T) {
for _, c := range clipTests {
dst := dst0.SubImage(c.dr).(*image.RGBA)
src := src0.SubImage(c.sr).(*image.RGBA)
- var mask image.Image
- if !c.nilMask {
- mask = mask0.SubImage(c.mr)
- }
r, sp, mp := c.r, c.sp, c.mp
- clip(dst, &r, src, &sp, mask, &mp)
+ if c.nilMask {
+ clip(dst, &r, src, &sp, nil, nil)
+ } else {
+ clip(dst, &r, src, &sp, mask0.SubImage(c.mr), &mp)
+ }
// Check that the actual results equal the expected results.
if !c.r0.Eq(r) {
@@ -173,17 +185,17 @@ func TestClip(t *testing.T) {
}
// Check that the clipped rectangle is contained by the dst / src / mask
- // rectangles, in their respective co-ordinate spaces.
+ // rectangles, in their respective coordinate spaces.
if !r.In(c.dr) {
t.Errorf("%s: c.dr %v does not contain r %v", c.desc, c.dr, r)
}
- // sr is r translated into src's co-ordinate space.
+ // sr is r translated into src's coordinate space.
sr := r.Add(c.sp.Sub(c.dr.Min))
if !sr.In(c.sr) {
t.Errorf("%s: c.sr %v does not contain sr %v", c.desc, c.sr, sr)
}
if !c.nilMask {
- // mr is r translated into mask's co-ordinate space.
+ // mr is r translated into mask's coordinate space.
mr := r.Add(c.mp.Sub(c.dr.Min))
if !mr.In(c.mr) {
t.Errorf("%s: c.mr %v does not contain mr %v", c.desc, c.mr, mr)
diff --git a/llgo/third_party/gofrontend/libgo/go/image/draw/draw.go b/llgo/third_party/gofrontend/libgo/go/image/draw/draw.go
index 661230e7c59..9419d5e72a7 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/draw/draw.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/draw/draw.go
@@ -5,12 +5,13 @@
// Package draw provides image composition functions.
//
// See "The Go image/draw package" for an introduction to this package:
-// http://golang.org/doc/articles/image_draw.html
+// https://golang.org/doc/articles/image_draw.html
package draw
import (
"image"
"image/color"
+ "image/internal/imageutil"
)
// m is the maximum color value returned by image.Color.RGBA.
@@ -67,7 +68,7 @@ func (floydSteinberg) Draw(dst Image, r image.Rectangle, src image.Image, sp ima
}
// clip clips r against each image's bounds (after translating into the
-// destination image's co-ordinate space) and shifts the points sp and mp by
+// destination image's coordinate space) and shifts the points sp and mp by
// the same amount as the change in r.Min.
func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) {
orig := r.Min
@@ -81,10 +82,12 @@ func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask
if dx == 0 && dy == 0 {
return
}
- (*sp).X += dx
- (*sp).Y += dy
- (*mp).X += dx
- (*mp).Y += dy
+ sp.X += dx
+ sp.Y += dy
+ if mp != nil {
+ mp.X += dx
+ mp.Y += dy
+ }
}
func processBackward(dst Image, r image.Rectangle, src image.Image, sp image.Point) bool {
@@ -122,9 +125,19 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
drawNRGBAOver(dst0, r, src0, sp)
return
case *image.YCbCr:
- if drawYCbCr(dst0, r, src0, sp) {
+ // An image.YCbCr is always fully opaque, and so if the
+ // mask is nil (i.e. fully opaque) then the op is
+ // effectively always Src. Similarly for image.Gray and
+ // image.CMYK.
+ if imageutil.DrawYCbCr(dst0, r, src0, sp) {
return
}
+ case *image.Gray:
+ drawGray(dst0, r, src0, sp)
+ return
+ case *image.CMYK:
+ drawCMYK(dst0, r, src0, sp)
+ return
}
} else if mask0, ok := mask.(*image.Alpha); ok {
switch src0 := src.(type) {
@@ -146,9 +159,15 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
drawNRGBASrc(dst0, r, src0, sp)
return
case *image.YCbCr:
- if drawYCbCr(dst0, r, src0, sp) {
+ if imageutil.DrawYCbCr(dst0, r, src0, sp) {
return
}
+ case *image.Gray:
+ drawGray(dst0, r, src0, sp)
+ return
+ case *image.CMYK:
+ drawCMYK(dst0, r, src0, sp)
+ return
}
}
}
@@ -157,6 +176,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
case *image.Paletted:
if op == Src && mask == nil && !processBackward(dst, r, src, sp) {
drawPaletted(dst0, r, src, sp, false)
+ return
}
}
@@ -237,16 +257,20 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
sr, sg, sb, sa := src.RGBA()
+ sr8 := uint8(sr >> 8)
+ sg8 := uint8(sg >> 8)
+ sb8 := uint8(sb >> 8)
+ sa8 := uint8(sa >> 8)
// The built-in copy function is faster than a straightforward for loop to fill the destination with
// the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
// then use the first row as the slice source for the remaining rows.
i0 := dst.PixOffset(r.Min.X, r.Min.Y)
i1 := i0 + r.Dx()*4
for i := i0; i < i1; i += 4 {
- dst.Pix[i+0] = uint8(sr >> 8)
- dst.Pix[i+1] = uint8(sg >> 8)
- dst.Pix[i+2] = uint8(sb >> 8)
- dst.Pix[i+3] = uint8(sa >> 8)
+ dst.Pix[i+0] = sr8
+ dst.Pix[i+1] = sg8
+ dst.Pix[i+2] = sb8
+ dst.Pix[i+3] = sa8
}
firstRow := dst.Pix[i0:i1]
for y := r.Min.Y + 1; y < r.Max.Y; y++ {
@@ -313,9 +337,11 @@ func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.P
ddelta = dst.Stride
sdelta = src.Stride
} else {
- // If the source start point is higher than the destination start point, then we compose the rows
- // in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to
- // check the x co-ordinates because the built-in copy function can handle overlapping slices.
+ // If the source start point is higher than the destination start
+ // point, then we compose the rows in bottom-up order instead of
+ // top-down. Unlike the drawCopyOver function, we don't have to check
+ // the x coordinates because the built-in copy function can handle
+ // overlapping slices.
d0 += (dy - 1) * dst.Stride
s0 += (dy - 1) * src.Stride
ddelta = -dst.Stride
@@ -390,72 +416,46 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
}
}
-func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
- // An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
- // (i.e. fully opaque) then the op is effectively always Src.
- x0 := (r.Min.X - dst.Rect.Min.X) * 4
- x1 := (r.Max.X - dst.Rect.Min.X) * 4
- y0 := r.Min.Y - dst.Rect.Min.Y
- y1 := r.Max.Y - dst.Rect.Min.Y
- switch src.SubsampleRatio {
- case image.YCbCrSubsampleRatio444:
- for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
- dpix := dst.Pix[y*dst.Stride:]
- yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
- ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
- for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
- rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
- dpix[x+0] = rr
- dpix[x+1] = gg
- dpix[x+2] = bb
- dpix[x+3] = 255
- }
- }
- case image.YCbCrSubsampleRatio422:
- for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
- dpix := dst.Pix[y*dst.Stride:]
- yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
- ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2
- for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
- ci := ciBase + sx/2
- rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
- dpix[x+0] = rr
- dpix[x+1] = gg
- dpix[x+2] = bb
- dpix[x+3] = 255
- }
- }
- case image.YCbCrSubsampleRatio420:
- for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
- dpix := dst.Pix[y*dst.Stride:]
- yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
- ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2
- for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
- ci := ciBase + sx/2
- rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
- dpix[x+0] = rr
- dpix[x+1] = gg
- dpix[x+2] = bb
- dpix[x+3] = 255
- }
+func drawGray(dst *image.RGBA, r image.Rectangle, src *image.Gray, sp image.Point) {
+ i0 := (r.Min.X - dst.Rect.Min.X) * 4
+ i1 := (r.Max.X - dst.Rect.Min.X) * 4
+ si0 := (sp.X - src.Rect.Min.X) * 1
+ yMax := r.Max.Y - dst.Rect.Min.Y
+
+ y := r.Min.Y - dst.Rect.Min.Y
+ sy := sp.Y - src.Rect.Min.Y
+ for ; y != yMax; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ spix := src.Pix[sy*src.Stride:]
+
+ 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
}
- case image.YCbCrSubsampleRatio440:
- for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
- dpix := dst.Pix[y*dst.Stride:]
- yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
- ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X)
- for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
- rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
- dpix[x+0] = rr
- dpix[x+1] = gg
- dpix[x+2] = bb
- dpix[x+3] = 255
- }
+ }
+}
+
+func drawCMYK(dst *image.RGBA, r image.Rectangle, src *image.CMYK, sp image.Point) {
+ i0 := (r.Min.X - dst.Rect.Min.X) * 4
+ i1 := (r.Max.X - dst.Rect.Min.X) * 4
+ si0 := (sp.X - src.Rect.Min.X) * 4
+ yMax := r.Max.Y - dst.Rect.Min.Y
+
+ y := r.Min.Y - dst.Rect.Min.Y
+ sy := sp.Y - src.Rect.Min.Y
+ for ; y != yMax; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ 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
}
- default:
- return false
}
- return true
}
func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
@@ -555,6 +555,20 @@ func clamp(i int32) int32 {
return i
}
+// sqDiff returns the squared-difference of x and y, shifted by 2 so that
+// adding four of those won't overflow a uint32.
+//
+// x and y are both assumed to be in the range [0, 0xffff].
+func sqDiff(x, y int32) uint32 {
+ var d uint32
+ if x > y {
+ d = uint32(x - y)
+ } else {
+ d = uint32(y - x)
+ }
+ return (d * d) >> 2
+}
+
func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, floydSteinberg bool) {
// TODO(nigeltao): handle the case where the dst and src overlap.
// Does it even make sense to try and do Floyd-Steinberg whilst
@@ -564,14 +578,15 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
// dst.At. The dst.Set equivalent is a batch version of the algorithm
// used by color.Palette's Index method in image/color/color.go, plus
// optional Floyd-Steinberg error diffusion.
- palette, pix, stride := [][3]int32(nil), []byte(nil), 0
+ palette, pix, stride := [][4]int32(nil), []byte(nil), 0
if p, ok := dst.(*image.Paletted); ok {
- palette = make([][3]int32, len(p.Palette))
+ palette = make([][4]int32, len(p.Palette))
for i, col := range p.Palette {
- r, g, b, _ := col.RGBA()
+ r, g, b, a := col.RGBA()
palette[i][0] = int32(r)
palette[i][1] = int32(g)
palette[i][2] = int32(b)
+ palette[i][3] = int32(a)
}
pix, stride = p.Pix[p.PixOffset(r.Min.X, r.Min.Y):], p.Stride
}
@@ -579,10 +594,10 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
// quantErrorCurr and quantErrorNext are the Floyd-Steinberg quantization
// errors that have been propagated to the pixels in the current and next
// rows. The +2 simplifies calculation near the edges.
- var quantErrorCurr, quantErrorNext [][3]int32
+ var quantErrorCurr, quantErrorNext [][4]int32
if floydSteinberg {
- quantErrorCurr = make([][3]int32, r.Dx()+2)
- quantErrorNext = make([][3]int32, r.Dx()+2)
+ quantErrorCurr = make([][4]int32, r.Dx()+2)
+ quantErrorNext = make([][4]int32, r.Dx()+2)
}
// Loop over each source pixel.
@@ -591,30 +606,25 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
for x := 0; x != r.Dx(); x++ {
// er, eg and eb are the pixel's R,G,B values plus the
// optional Floyd-Steinberg error.
- sr, sg, sb, _ := src.At(sp.X+x, sp.Y+y).RGBA()
- er, eg, eb := int32(sr), int32(sg), int32(sb)
+ sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA()
+ er, eg, eb, ea := int32(sr), int32(sg), int32(sb), int32(sa)
if floydSteinberg {
er = clamp(er + quantErrorCurr[x+1][0]/16)
eg = clamp(eg + quantErrorCurr[x+1][1]/16)
eb = clamp(eb + quantErrorCurr[x+1][2]/16)
+ ea = clamp(ea + quantErrorCurr[x+1][3]/16)
}
if palette != nil {
- // Find the closest palette color in Euclidean R,G,B space: the
- // one that minimizes sum-squared-difference. We shift by 1 bit
- // to avoid potential uint32 overflow in sum-squared-difference.
+ // Find the closest palette color in Euclidean R,G,B,A space:
+ // the one that minimizes sum-squared-difference.
// TODO(nigeltao): consider smarter algorithms.
- bestIndex, bestSSD := 0, uint32(1<<32-1)
+ bestIndex, bestSum := 0, uint32(1<<32-1)
for index, p := range palette {
- delta := (er - p[0]) >> 1
- ssd := uint32(delta * delta)
- delta = (eg - p[1]) >> 1
- ssd += uint32(delta * delta)
- delta = (eb - p[2]) >> 1
- ssd += uint32(delta * delta)
- if ssd < bestSSD {
- bestIndex, bestSSD = index, ssd
- if ssd == 0 {
+ sum := sqDiff(er, p[0]) + sqDiff(eg, p[1]) + sqDiff(eb, p[2]) + sqDiff(ea, p[3])
+ if sum < bestSum {
+ bestIndex, bestSum = index, sum
+ if sum == 0 {
break
}
}
@@ -627,11 +637,13 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
er -= int32(palette[bestIndex][0])
eg -= int32(palette[bestIndex][1])
eb -= int32(palette[bestIndex][2])
+ ea -= int32(palette[bestIndex][3])
} else {
out.R = uint16(er)
out.G = uint16(eg)
out.B = uint16(eb)
+ out.A = uint16(ea)
// The third argument is &out instead of out (and out is
// declared outside of the inner loop) to avoid the implicit
// conversion to color.Color here allocating memory in the
@@ -641,32 +653,37 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
if !floydSteinberg {
continue
}
- sr, sg, sb, _ = dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
+ sr, sg, sb, sa = dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
er -= int32(sr)
eg -= int32(sg)
eb -= int32(sb)
+ ea -= int32(sa)
}
// Propagate the Floyd-Steinberg quantization error.
quantErrorNext[x+0][0] += er * 3
quantErrorNext[x+0][1] += eg * 3
quantErrorNext[x+0][2] += eb * 3
+ quantErrorNext[x+0][3] += ea * 3
quantErrorNext[x+1][0] += er * 5
quantErrorNext[x+1][1] += eg * 5
quantErrorNext[x+1][2] += eb * 5
+ quantErrorNext[x+1][3] += ea * 5
quantErrorNext[x+2][0] += er * 1
quantErrorNext[x+2][1] += eg * 1
quantErrorNext[x+2][2] += eb * 1
+ quantErrorNext[x+2][3] += ea * 1
quantErrorCurr[x+2][0] += er * 7
quantErrorCurr[x+2][1] += eg * 7
quantErrorCurr[x+2][2] += eb * 7
+ quantErrorCurr[x+2][3] += ea * 7
}
// Recycle the quantization error buffers.
if floydSteinberg {
quantErrorCurr, quantErrorNext = quantErrorNext, quantErrorCurr
for i := range quantErrorNext {
- quantErrorNext[i] = [3]int32{}
+ quantErrorNext[i] = [4]int32{}
}
}
}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/draw/draw_test.go b/llgo/third_party/gofrontend/libgo/go/image/draw/draw_test.go
index 0dd7fbd479a..a58f0f49849 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/draw/draw_test.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/draw/draw_test.go
@@ -74,6 +74,26 @@ func vgradCr() image.Image {
return m
}
+func vgradGray() image.Image {
+ m := image.NewGray(image.Rect(0, 0, 16, 16))
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Set(x, y, color.Gray{uint8(y * 0x11)})
+ }
+ }
+ return m
+}
+
+func vgradMagenta() image.Image {
+ m := image.NewCMYK(image.Rect(0, 0, 16, 16))
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Set(x, y, color.CMYK{0, uint8(y * 0x11), 0, 0x3f})
+ }
+ }
+ return m
+}
+
func hgradRed(alpha int) Image {
m := image.NewRGBA(image.Rect(0, 0, 16, 16))
for y := 0; y < 16; y++ {
@@ -147,6 +167,26 @@ var drawTests = []drawTest{
{"ycbcrAlphaSrc", vgradCr(), fillAlpha(192), Src, color.RGBA{8, 28, 0, 192}},
{"ycbcrNil", vgradCr(), nil, Over, color.RGBA{11, 38, 0, 255}},
{"ycbcrNilSrc", vgradCr(), nil, Src, color.RGBA{11, 38, 0, 255}},
+ // Uniform mask (100%, 75%, nil) and variable Gray source.
+ // At (x, y) == (8, 8):
+ // The destination pixel is {136, 0, 0, 255}.
+ // The source pixel is {136} in Gray-space, which is {136, 136, 136, 255} in RGBA-space.
+ {"gray", vgradGray(), fillAlpha(255), Over, color.RGBA{136, 136, 136, 255}},
+ {"graySrc", vgradGray(), fillAlpha(255), Src, color.RGBA{136, 136, 136, 255}},
+ {"grayAlpha", vgradGray(), fillAlpha(192), Over, color.RGBA{136, 102, 102, 255}},
+ {"grayAlphaSrc", vgradGray(), fillAlpha(192), Src, color.RGBA{102, 102, 102, 192}},
+ {"grayNil", vgradGray(), nil, Over, color.RGBA{136, 136, 136, 255}},
+ {"grayNilSrc", vgradGray(), nil, Src, color.RGBA{136, 136, 136, 255}},
+ // Uniform mask (100%, 75%, nil) and variable CMYK source.
+ // At (x, y) == (8, 8):
+ // The destination pixel is {136, 0, 0, 255}.
+ // The source pixel is {0, 136, 0, 63} in CMYK-space, which is {192, 89, 192} in RGB-space.
+ {"cmyk", vgradMagenta(), fillAlpha(255), Over, color.RGBA{192, 89, 192, 255}},
+ {"cmykSrc", vgradMagenta(), fillAlpha(255), Src, color.RGBA{192, 89, 192, 255}},
+ {"cmykAlpha", vgradMagenta(), fillAlpha(192), Over, color.RGBA{178, 67, 145, 255}},
+ {"cmykAlphaSrc", vgradMagenta(), fillAlpha(192), Src, color.RGBA{145, 67, 145, 192}},
+ {"cmykNil", vgradMagenta(), nil, Over, color.RGBA{192, 89, 192, 255}},
+ {"cmykNilSrc", vgradMagenta(), nil, Src, color.RGBA{192, 89, 192, 255}},
// Variable mask and variable source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
diff --git a/llgo/third_party/gofrontend/libgo/go/image/geom.go b/llgo/third_party/gofrontend/libgo/go/image/geom.go
index 6ebaf67da84..e1cd4dc1e3e 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/geom.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/geom.go
@@ -5,6 +5,7 @@
package image
import (
+ "image/color"
"strconv"
)
@@ -62,7 +63,7 @@ func (p Point) Mod(r Rectangle) Point {
// Eq reports whether p and q are equal.
func (p Point) Eq(q Point) bool {
- return p.X == q.X && p.Y == q.Y
+ return p == q
}
// ZP is the zero Point.
@@ -77,6 +78,10 @@ func Pt(X, Y int) Point {
// It is well-formed if Min.X <= Max.X and likewise for Y. Points are always
// well-formed. A rectangle's methods always return well-formed outputs for
// well-formed inputs.
+//
+// A Rectangle is also an Image whose bounds are the rectangle itself. At
+// returns color.Opaque for points in the rectangle and color.Transparent
+// otherwise.
type Rectangle struct {
Min, Max Point
}
@@ -164,6 +169,12 @@ func (r Rectangle) Intersect(s Rectangle) Rectangle {
// Union returns the smallest rectangle that contains both r and s.
func (r Rectangle) Union(s Rectangle) Rectangle {
+ if r.Empty() {
+ return s
+ }
+ if s.Empty() {
+ return r
+ }
if r.Min.X > s.Min.X {
r.Min.X = s.Min.X
}
@@ -184,15 +195,16 @@ func (r Rectangle) Empty() bool {
return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
}
-// Eq reports whether r and s are equal.
+// Eq reports whether r and s contain the same set of points. All empty
+// rectangles are considered equal.
func (r Rectangle) Eq(s Rectangle) bool {
- return r.Min.X == s.Min.X && r.Min.Y == s.Min.Y &&
- r.Max.X == s.Max.X && r.Max.Y == s.Max.Y
+ return r == s || r.Empty() && s.Empty()
}
// Overlaps reports whether r and s have a non-empty intersection.
func (r Rectangle) Overlaps(s Rectangle) bool {
- return r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
+ return !r.Empty() && !s.Empty() &&
+ r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y
}
@@ -219,10 +231,30 @@ func (r Rectangle) Canon() Rectangle {
return r
}
+// At implements the Image interface.
+func (r Rectangle) At(x, y int) color.Color {
+ if (Point{x, y}).In(r) {
+ return color.Opaque
+ }
+ return color.Transparent
+}
+
+// Bounds implements the Image interface.
+func (r Rectangle) Bounds() Rectangle {
+ return r
+}
+
+// ColorModel implements the Image interface.
+func (r Rectangle) ColorModel() color.Model {
+ return color.Alpha16Model
+}
+
// ZR is the zero Rectangle.
var ZR Rectangle
-// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
+// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}. The returned
+// rectangle has minimum and maximum coordinates swapped if necessary so that
+// it is well-formed.
func Rect(x0, y0, x1, y1 int) Rectangle {
if x0 > x1 {
x0, x1 = x1, x0
diff --git a/llgo/third_party/gofrontend/libgo/go/image/geom_test.go b/llgo/third_party/gofrontend/libgo/go/image/geom_test.go
new file mode 100644
index 00000000000..6e9c6a13c2c
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/geom_test.go
@@ -0,0 +1,115 @@
+// Copyright 2015 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.
+
+package image
+
+import (
+ "fmt"
+ "testing"
+)
+
+func TestRectangle(t *testing.T) {
+ // in checks that every point in f is in g.
+ in := func(f, g Rectangle) error {
+ if !f.In(g) {
+ return fmt.Errorf("f=%s, f.In(%s): got false, want true", f, g)
+ }
+ for y := f.Min.Y; y < f.Max.Y; y++ {
+ for x := f.Min.X; x < f.Max.X; x++ {
+ p := Point{x, y}
+ if !p.In(g) {
+ return fmt.Errorf("p=%s, p.In(%s): got false, want true", p, g)
+ }
+ }
+ }
+ return nil
+ }
+
+ rects := []Rectangle{
+ Rect(0, 0, 10, 10),
+ Rect(1, 2, 3, 4),
+ Rect(4, 6, 10, 10),
+ Rect(2, 3, 12, 5),
+ Rect(-1, -2, 0, 0),
+ Rect(-1, -2, 4, 6),
+ Rect(-10, -20, 30, 40),
+ Rect(8, 8, 8, 8),
+ Rect(88, 88, 88, 88),
+ Rect(6, 5, 4, 3),
+ }
+
+ // r.Eq(s) should be equivalent to every point in r being in s, and every
+ // point in s being in r.
+ for _, r := range rects {
+ for _, s := range rects {
+ got := r.Eq(s)
+ want := in(r, s) == nil && in(s, r) == nil
+ if got != want {
+ t.Errorf("Eq: r=%s, s=%s: got %t, want %t", r, s, got, want)
+ }
+ }
+ }
+
+ // The intersection should be the largest rectangle a such that every point
+ // in a is both in r and in s.
+ for _, r := range rects {
+ for _, s := range rects {
+ a := r.Intersect(s)
+ if err := in(a, r); err != nil {
+ t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in r: %v", r, s, a, err)
+ }
+ if err := in(a, s); err != nil {
+ t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in s: %v", r, s, a, err)
+ }
+ if a.Empty() == r.Overlaps(s) {
+ t.Errorf("Intersect: r=%s, s=%s, a=%s: empty=%t same as overlaps=%t",
+ r, s, a, a.Empty(), r.Overlaps(s))
+ }
+ largerThanA := [4]Rectangle{a, a, a, a}
+ largerThanA[0].Min.X--
+ largerThanA[1].Min.Y--
+ largerThanA[2].Max.X++
+ largerThanA[3].Max.Y++
+ for i, b := range largerThanA {
+ if b.Empty() {
+ // b isn't actually larger than a.
+ continue
+ }
+ if in(b, r) == nil && in(b, s) == nil {
+ t.Errorf("Intersect: r=%s, s=%s, a=%s, b=%s, i=%d: intersection could be larger",
+ r, s, a, b, i)
+ }
+ }
+ }
+ }
+
+ // The union should be the smallest rectangle a such that every point in r
+ // is in a and every point in s is in a.
+ for _, r := range rects {
+ for _, s := range rects {
+ a := r.Union(s)
+ if err := in(r, a); err != nil {
+ t.Errorf("Union: r=%s, s=%s, a=%s, r not in a: %v", r, s, a, err)
+ }
+ if err := in(s, a); err != nil {
+ t.Errorf("Union: r=%s, s=%s, a=%s, s not in a: %v", r, s, a, err)
+ }
+ if a.Empty() {
+ // You can't get any smaller than a.
+ continue
+ }
+ smallerThanA := [4]Rectangle{a, a, a, a}
+ smallerThanA[0].Min.X++
+ smallerThanA[1].Min.Y++
+ smallerThanA[2].Max.X--
+ smallerThanA[3].Max.Y--
+ for i, b := range smallerThanA {
+ if in(r, b) == nil && in(s, b) == nil {
+ t.Errorf("Union: r=%s, s=%s, a=%s, b=%s, i=%d: union could be smaller",
+ r, s, a, b, i)
+ }
+ }
+ }
+ }
+}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/gif/reader.go b/llgo/third_party/gofrontend/libgo/go/image/gif/reader.go
index 5a863e204f3..6a133124ad5 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/gif/reader.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/gif/reader.go
@@ -32,15 +32,20 @@ type reader interface {
// Masks etc.
const (
// Fields.
- fColorMapFollows = 1 << 7
-
- // Image fields.
- ifLocalColorTable = 1 << 7
- ifInterlace = 1 << 6
- ifPixelSizeMask = 7
+ fColorTable = 1 << 7
+ fInterlace = 1 << 6
+ fColorTableBitsMask = 7
// Graphic control flags.
gcTransparentColorSet = 1 << 0
+ gcDisposalMethodMask = 7 << 2
+)
+
+// Disposal Methods.
+const (
+ DisposalNone = 0x01
+ DisposalBackground = 0x02
+ DisposalPrevious = 0x03
)
// Section indicators.
@@ -66,14 +71,10 @@ type decoder struct {
vers string
width int
height int
- flags byte
- headerFields byte
- backgroundIndex byte
loopCount int
delayTime int
-
- // Unused from header.
- aspect byte
+ backgroundIndex byte
+ disposalMethod byte
// From image descriptor.
imageFields byte
@@ -83,13 +84,13 @@ type decoder struct {
hasTransparentIndex bool
// Computed.
- pixelSize uint
- globalColorMap color.Palette
+ globalColorTable color.Palette
// Used when decoding.
- delay []int
- image []*image.Paletted
- tmp [1024]byte // must be at least 768 so we can read color map
+ delay []int
+ disposal []byte
+ image []*image.Paletted
+ tmp [1024]byte // must be at least 768 so we can read color table
}
// blockReader parses the block structure of GIF image data, which
@@ -122,7 +123,7 @@ func (b *blockReader) Read(p []byte) (int, error) {
b.err = io.EOF
return 0, b.err
}
- b.slice = b.tmp[0:blockLen]
+ b.slice = b.tmp[:blockLen]
if _, b.err = io.ReadFull(b.r, b.slice); b.err != nil {
return 0, b.err
}
@@ -149,12 +150,6 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
return nil
}
- if d.headerFields&fColorMapFollows != 0 {
- if d.globalColorMap, err = d.readColorMap(); err != nil {
- return err
- }
- }
-
for {
c, err := d.r.ReadByte()
if err != nil {
@@ -171,19 +166,22 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
if err != nil {
return err
}
- useLocalColorMap := d.imageFields&fColorMapFollows != 0
- if useLocalColorMap {
- m.Palette, err = d.readColorMap()
+ useLocalColorTable := d.imageFields&fColorTable != 0
+ if useLocalColorTable {
+ m.Palette, err = d.readColorTable(d.imageFields)
if err != nil {
return err
}
} else {
- m.Palette = d.globalColorMap
+ if d.globalColorTable == nil {
+ return errors.New("gif: no color table")
+ }
+ m.Palette = d.globalColorTable
}
if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) {
- if !useLocalColorMap {
- // Clone the global color map.
- m.Palette = append(color.Palette(nil), d.globalColorMap...)
+ if !useLocalColorTable {
+ // Clone the global color table.
+ m.Palette = append(color.Palette(nil), d.globalColorTable...)
}
m.Palette[d.transparentIndex] = color.RGBA{}
}
@@ -204,9 +202,18 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
}
return errNotEnough
}
- // Both lzwr and br should be exhausted. Reading from them
- // should yield (0, io.EOF).
- if n, err := lzwr.Read(d.tmp[:1]); n != 0 || err != io.EOF {
+ // Both lzwr and br should be exhausted. Reading from them should
+ // yield (0, io.EOF).
+ //
+ // The spec (Appendix F - Compression), says that "An End of
+ // Information code... must be the last code output by the encoder
+ // 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
+ // 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) {
if err != nil {
return err
}
@@ -229,12 +236,13 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
}
// Undo the interlacing if necessary.
- if d.imageFields&ifInterlace != 0 {
+ if d.imageFields&fInterlace != 0 {
uninterlace(m)
}
d.image = append(d.image, m)
d.delay = append(d.delay, d.delayTime)
+ d.disposal = append(d.disposal, d.disposalMethod)
// The GIF89a spec, Section 23 (Graphic Control Extension) says:
// "The scope of this extension is the first graphic rendering block
// to follow." We therefore reset the GCE fields to zero.
@@ -254,44 +262,39 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
}
func (d *decoder) readHeaderAndScreenDescriptor() error {
- _, err := io.ReadFull(d.r, d.tmp[0:13])
+ _, err := io.ReadFull(d.r, d.tmp[:13])
if err != nil {
return err
}
- d.vers = string(d.tmp[0:6])
+ d.vers = string(d.tmp[:6])
if d.vers != "GIF87a" && d.vers != "GIF89a" {
return fmt.Errorf("gif: can't recognize format %s", d.vers)
}
d.width = int(d.tmp[6]) + int(d.tmp[7])<<8
d.height = int(d.tmp[8]) + int(d.tmp[9])<<8
- d.headerFields = d.tmp[10]
- d.backgroundIndex = d.tmp[11]
- d.aspect = d.tmp[12]
- d.loopCount = -1
- d.pixelSize = uint(d.headerFields&7) + 1
+ if fields := d.tmp[10]; fields&fColorTable != 0 {
+ d.backgroundIndex = d.tmp[11]
+ // readColorTable overwrites the contents of d.tmp, but that's OK.
+ if d.globalColorTable, err = d.readColorTable(fields); err != nil {
+ return err
+ }
+ }
+ // d.tmp[12] is the Pixel Aspect Ratio, which is ignored.
return nil
}
-func (d *decoder) readColorMap() (color.Palette, error) {
- if d.pixelSize > 8 {
- return nil, fmt.Errorf("gif: can't handle %d bits per pixel", d.pixelSize)
- }
- numColors := 1 << d.pixelSize
- if d.imageFields&ifLocalColorTable != 0 {
- numColors = 1 << ((d.imageFields & ifPixelSizeMask) + 1)
- }
- numValues := 3 * numColors
- _, err := io.ReadFull(d.r, d.tmp[0:numValues])
+func (d *decoder) readColorTable(fields byte) (color.Palette, error) {
+ n := 1 << (1 + uint(fields&fColorTableBitsMask))
+ _, err := io.ReadFull(d.r, d.tmp[:3*n])
if err != nil {
- return nil, fmt.Errorf("gif: short read on color map: %s", err)
+ return nil, fmt.Errorf("gif: short read on color table: %s", err)
}
- colorMap := make(color.Palette, numColors)
- j := 0
- for i := range colorMap {
- colorMap[i] = color.RGBA{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF}
+ j, p := 0, make(color.Palette, n)
+ for i := range p {
+ p[i] = color.RGBA{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF}
j += 3
}
- return colorMap, nil
+ return p, nil
}
func (d *decoder) readExtension() error {
@@ -318,7 +321,7 @@ func (d *decoder) readExtension() error {
return fmt.Errorf("gif: unknown extension 0x%.2x", extension)
}
if size > 0 {
- if _, err := io.ReadFull(d.r, d.tmp[0:size]); err != nil {
+ if _, err := io.ReadFull(d.r, d.tmp[:size]); err != nil {
return err
}
}
@@ -343,12 +346,13 @@ func (d *decoder) readExtension() error {
}
func (d *decoder) readGraphicControl() error {
- if _, err := io.ReadFull(d.r, d.tmp[0:6]); err != nil {
+ if _, err := io.ReadFull(d.r, d.tmp[:6]); err != nil {
return fmt.Errorf("gif: can't read graphic control: %s", err)
}
- d.flags = d.tmp[1]
+ flags := d.tmp[1]
+ d.disposalMethod = (flags & gcDisposalMethodMask) >> 2
d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8
- if d.flags&gcTransparentColorSet != 0 {
+ if flags&gcTransparentColorSet != 0 {
d.transparentIndex = d.tmp[4]
d.hasTransparentIndex = true
}
@@ -356,7 +360,7 @@ func (d *decoder) readGraphicControl() error {
}
func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
- if _, err := io.ReadFull(d.r, d.tmp[0:9]); err != nil {
+ if _, err := io.ReadFull(d.r, d.tmp[:9]); err != nil {
return nil, fmt.Errorf("gif: can't read image descriptor: %s", err)
}
left := int(d.tmp[0]) + int(d.tmp[1])<<8
@@ -380,7 +384,7 @@ func (d *decoder) readBlock() (int, error) {
if n == 0 || err != nil {
return 0, err
}
- return io.ReadFull(d.r, d.tmp[0:n])
+ return io.ReadFull(d.r, d.tmp[:n])
}
// interlaceScan defines the ordering for a pass of the interlace algorithm.
@@ -429,6 +433,24 @@ type GIF struct {
Image []*image.Paletted // The successive images.
Delay []int // The successive delay times, one per frame, in 100ths of a second.
LoopCount int // The loop count.
+ // Disposal is the successive disposal methods, one per frame. For
+ // backwards compatibility, a nil Disposal is valid to pass to EncodeAll,
+ // and implies that each frame's disposal method is 0 (no disposal
+ // specified).
+ Disposal []byte
+ // Config is the global color table (palette), width and height. A nil or
+ // empty-color.Palette Config.ColorModel means that each frame has its own
+ // color table and there is no global color table. Each frame's bounds must
+ // be within the rectangle defined by the two points (0, 0) and
+ // (Config.Width, Config.Height).
+ //
+ // For backwards compatibility, a zero-valued Config is valid to pass to
+ // EncodeAll, and implies that the overall GIF's width and height equals
+ // the first frame's bounds' Rectangle.Max point.
+ Config image.Config
+ // BackgroundIndex is the background index in the global color table, for
+ // use with the DisposalBackground disposal method.
+ BackgroundIndex byte
}
// DecodeAll reads a GIF image from r and returns the sequential frames
@@ -442,6 +464,13 @@ func DecodeAll(r io.Reader) (*GIF, error) {
Image: d.image,
LoopCount: d.loopCount,
Delay: d.delay,
+ Disposal: d.disposal,
+ Config: image.Config{
+ ColorModel: d.globalColorTable,
+ Width: d.width,
+ Height: d.height,
+ },
+ BackgroundIndex: d.backgroundIndex,
}
return gif, nil
}
@@ -454,7 +483,7 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
return image.Config{}, err
}
return image.Config{
- ColorModel: d.globalColorMap,
+ ColorModel: d.globalColorTable,
Width: d.width,
Height: d.height,
}, nil
diff --git a/llgo/third_party/gofrontend/libgo/go/image/gif/reader_test.go b/llgo/third_party/gofrontend/libgo/go/image/gif/reader_test.go
index 7b6f504367c..c294195b6f7 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/gif/reader_test.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/gif/reader_test.go
@@ -17,8 +17,8 @@ import (
const (
headerStr = "GIF89a" +
"\x02\x00\x01\x00" + // width=2, height=1
- "\x80\x00\x00" // headerFields=(a color map of 2 pixels), backgroundIndex, aspect
- paletteStr = "\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette
+ "\x80\x00\x00" // headerFields=(a color table of 2 pixels), backgroundIndex, aspect
+ paletteStr = "\x10\x20\x30\x40\x50\x60" // the color table, also known as a palette
trailerStr = "\x3b"
)
@@ -141,7 +141,7 @@ var testGIF = []byte{
'G', 'I', 'F', '8', '9', 'a',
1, 0, 1, 0, // w=1, h=1 (6)
128, 0, 0, // headerFields, bg, aspect (10)
- 0, 0, 0, 1, 1, 1, // color map and graphics control (13)
+ 0, 0, 0, 1, 1, 1, // color table and graphics control (13)
0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19)
// frame 1 (0,0 - 1,1)
0x2c,
@@ -200,22 +200,26 @@ func TestNoPalette(t *testing.T) {
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, 128}
+ pix := []byte{0, 3}
enc := &bytes.Buffer{}
w := lzw.NewWriter(enc, lzw.LSB, 2)
- w.Write(pix)
- w.Close()
+ 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())
b.WriteByte(0x00) // An empty block signifies the end of the image data.
b.WriteString(trailerStr)
- try(t, b.Bytes(), "gif: invalid pixel value")
+ try(t, b.Bytes(), "gif: no color table")
}
func TestPixelOutsidePaletteRange(t *testing.T) {
- for _, pval := range []byte{0, 1, 2, 3, 255} {
+ for _, pval := range []byte{0, 1, 2, 3} {
b := &bytes.Buffer{}
// Manufacture a GIF with a 2 color palette.
@@ -229,8 +233,12 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
pix := []byte{pval, pval}
enc := &bytes.Buffer{}
w := lzw.NewWriter(enc, lzw.LSB, 2)
- w.Write(pix)
- w.Close()
+ 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())
b.WriteByte(0x00) // An empty block signifies the end of the image data.
@@ -245,3 +253,24 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
try(t, b.Bytes(), want)
}
}
+
+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;")
+ img, err := DecodeAll(bytes.NewReader(data))
+ if err != nil {
+ t.Fatal("DecodeAll:", err)
+ }
+ w := new(bytes.Buffer)
+ err = EncodeAll(w, img)
+ if err != nil {
+ t.Fatal("EncodeAll:", err)
+ }
+ img1, err := DecodeAll(w)
+ if err != nil {
+ t.Fatal("DecodeAll:", err)
+ }
+ if img.LoopCount != img1.LoopCount {
+ t.Errorf("loop count mismatch: %d vs %d", img.LoopCount, img1.LoopCount)
+ }
+}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/gif/writer.go b/llgo/third_party/gofrontend/libgo/go/image/gif/writer.go
index 49abde704c8..dd317901d48 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/gif/writer.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/gif/writer.go
@@ -6,6 +6,7 @@ package gif
import (
"bufio"
+ "bytes"
"compress/lzw"
"errors"
"image"
@@ -52,9 +53,13 @@ type encoder struct {
w writer
err error
// g is a reference to the data that is being encoded.
- g *GIF
- // buf is a scratch buffer. It must be at least 768 so we can write the color map.
- buf [1024]byte
+ g GIF
+ // globalCT is the size in bytes of the global color table.
+ globalCT int
+ // buf is a scratch buffer. It must be at least 256 for the blockWriter.
+ buf [256]byte
+ globalColorTable [3 * 256]byte
+ localColorTable [3 * 256]byte
}
// blockWriter writes the block structure of GIF image data, which
@@ -116,18 +121,27 @@ func (e *encoder) writeHeader() {
return
}
- pm := e.g.Image[0]
// Logical screen width and height.
- writeUint16(e.buf[0:2], uint16(pm.Bounds().Dx()))
- writeUint16(e.buf[2:4], uint16(pm.Bounds().Dy()))
+ writeUint16(e.buf[0:2], uint16(e.g.Config.Width))
+ writeUint16(e.buf[2:4], uint16(e.g.Config.Height))
e.write(e.buf[:4])
- // All frames have a local color table, so a global color table
- // is not needed.
- e.buf[0] = 0x00
- e.buf[1] = 0x00 // Background Color Index.
- e.buf[2] = 0x00 // Pixel Aspect Ratio.
- e.write(e.buf[:3])
+ if p, ok := e.g.Config.ColorModel.(color.Palette); ok && len(p) > 0 {
+ paddedSize := log2(len(p)) // Size of Global Color Table: 2^(1+n).
+ e.buf[0] = fColorTable | uint8(paddedSize)
+ e.buf[1] = e.g.BackgroundIndex
+ e.buf[2] = 0x00 // Pixel Aspect Ratio.
+ e.write(e.buf[:3])
+ e.globalCT = encodeColorTable(e.globalColorTable[:], p, paddedSize)
+ e.write(e.globalColorTable[:e.globalCT])
+ } else {
+ // All frames have a local color table, so a global color table
+ // is not needed.
+ e.buf[0] = 0x00
+ e.buf[1] = 0x00 // Background Color Index.
+ e.buf[2] = 0x00 // Pixel Aspect Ratio.
+ e.write(e.buf[:3])
+ }
// Add animation info if necessary.
if len(e.g.Image) > 1 {
@@ -147,28 +161,25 @@ func (e *encoder) writeHeader() {
}
}
-func (e *encoder) writeColorTable(p color.Palette, size int) {
- if e.err != nil {
- return
- }
-
- for i := 0; i < log2Lookup[size]; i++ {
+func encodeColorTable(dst []byte, p color.Palette, size int) int {
+ n := log2Lookup[size]
+ for i := 0; i < n; i++ {
if i < len(p) {
r, g, b, _ := p[i].RGBA()
- e.buf[3*i+0] = uint8(r >> 8)
- e.buf[3*i+1] = uint8(g >> 8)
- e.buf[3*i+2] = uint8(b >> 8)
+ dst[3*i+0] = uint8(r >> 8)
+ dst[3*i+1] = uint8(g >> 8)
+ dst[3*i+2] = uint8(b >> 8)
} else {
// Pad with black.
- e.buf[3*i+0] = 0x00
- e.buf[3*i+1] = 0x00
- e.buf[3*i+2] = 0x00
+ dst[3*i+0] = 0x00
+ dst[3*i+1] = 0x00
+ dst[3*i+2] = 0x00
}
}
- e.write(e.buf[:3*log2Lookup[size]])
+ return 3 * n
}
-func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) {
+func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) {
if e.err != nil {
return
}
@@ -179,10 +190,14 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) {
}
b := pm.Bounds()
- if b.Dx() >= 1<<16 || b.Dy() >= 1<<16 || b.Min.X < 0 || b.Min.X >= 1<<16 || b.Min.Y < 0 || b.Min.Y >= 1<<16 {
+ if b.Min.X < 0 || b.Max.X >= 1<<16 || b.Min.Y < 0 || b.Max.Y >= 1<<16 {
e.err = errors.New("gif: image block is too large to encode")
return
}
+ if !b.In(image.Rectangle{Max: image.Point{e.g.Config.Width, e.g.Config.Height}}) {
+ e.err = errors.New("gif: image block is out of bounds")
+ return
+ }
transparentIndex := -1
for i, c := range pm.Palette {
@@ -192,14 +207,14 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) {
}
}
- if delay > 0 || transparentIndex != -1 {
+ if delay > 0 || disposal != 0 || transparentIndex != -1 {
e.buf[0] = sExtension // Extension Introducer.
e.buf[1] = gcLabel // Graphic Control Label.
e.buf[2] = gcBlockSize // Block Size.
if transparentIndex != -1 {
- e.buf[3] = 0x01
+ e.buf[3] = 0x01 | disposal<<2
} else {
- e.buf[3] = 0x00
+ e.buf[3] = 0x00 | disposal<<2
}
writeUint16(e.buf[4:6], uint16(delay)) // Delay Time (1/100ths of a second)
@@ -220,11 +235,15 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) {
e.write(e.buf[:9])
paddedSize := log2(len(pm.Palette)) // Size of Local Color Table: 2^(1+n).
- // Interlacing is not supported.
- e.writeByte(0x80 | uint8(paddedSize))
-
- // Local Color Table.
- e.writeColorTable(pm.Palette, paddedSize)
+ ct := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize)
+ if ct != e.globalCT || !bytes.Equal(e.globalColorTable[:ct], e.localColorTable[:ct]) {
+ // Use a local color table.
+ e.writeByte(fColorTable | uint8(paddedSize))
+ e.write(e.localColorTable[:ct])
+ } else {
+ // Use the global color table.
+ e.writeByte(0)
+ }
litWidth := paddedSize + 1
if litWidth < 2 {
@@ -281,7 +300,23 @@ func EncodeAll(w io.Writer, g *GIF) error {
g.LoopCount = 0
}
- e := encoder{g: g}
+ e := encoder{g: *g}
+ // The GIF.Disposal, GIF.Config and GIF.BackgroundIndex fields were added
+ // in Go 1.5. Valid Go 1.4 code, such as when the Disposal field is omitted
+ // in a GIF struct literal, should still produce valid GIFs.
+ if e.g.Disposal != nil && len(e.g.Image) != len(e.g.Disposal) {
+ return errors.New("gif: mismatched image and disposal lengths")
+ }
+ if e.g.Config == (image.Config{}) {
+ p := g.Image[0].Bounds().Max
+ e.g.Config.Width = p.X
+ e.g.Config.Height = p.Y
+ } else if e.g.Config.ColorModel != nil {
+ if _, ok := e.g.Config.ColorModel.(color.Palette); !ok {
+ return errors.New("gif: GIF color model must be a color.Palette")
+ }
+ }
+
if ww, ok := w.(writer); ok {
e.w = ww
} else {
@@ -290,7 +325,11 @@ func EncodeAll(w io.Writer, g *GIF) error {
e.writeHeader()
for i, pm := range g.Image {
- e.writeImageBlock(pm, g.Delay[i])
+ disposal := uint8(0)
+ if g.Disposal != nil {
+ disposal = g.Disposal[i]
+ }
+ e.writeImageBlock(pm, g.Delay[i], disposal)
}
e.writeByte(sTrailer)
e.flush()
@@ -326,8 +365,22 @@ func Encode(w io.Writer, m image.Image, o *Options) error {
opts.Drawer.Draw(pm, b, m, image.ZP)
}
+ // When calling Encode instead of EncodeAll, the single-frame image is
+ // translated such that its top-left corner is (0, 0), so that the single
+ // frame completely fills the overall GIF's bounds.
+ if pm.Rect.Min != (image.Point{}) {
+ dup := *pm
+ dup.Rect = dup.Rect.Sub(dup.Rect.Min)
+ pm = &dup
+ }
+
return EncodeAll(w, &GIF{
Image: []*image.Paletted{pm},
Delay: []int{0},
+ Config: image.Config{
+ ColorModel: pm.Palette,
+ Width: b.Dx(),
+ Height: b.Dy(),
+ },
})
}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/gif/writer_test.go b/llgo/third_party/gofrontend/libgo/go/image/gif/writer_test.go
index 93306ffdb34..db61a5c3c2e 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/gif/writer_test.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/gif/writer_test.go
@@ -8,10 +8,12 @@ import (
"bytes"
"image"
"image/color"
+ "image/color/palette"
_ "image/png"
"io/ioutil"
"math/rand"
"os"
+ "reflect"
"testing"
)
@@ -125,55 +127,317 @@ func TestSubImage(t *testing.T) {
}
}
+// palettesEqual reports whether two color.Palette values are equal, ignoring
+// any trailing opaque-black palette entries.
+func palettesEqual(p, q color.Palette) bool {
+ n := len(p)
+ if n > len(q) {
+ n = len(q)
+ }
+ for i := 0; i < n; i++ {
+ if p[i] != q[i] {
+ return false
+ }
+ }
+ for i := n; i < len(p); i++ {
+ r, g, b, a := p[i].RGBA()
+ if r != 0 || g != 0 || b != 0 || a != 0xffff {
+ return false
+ }
+ }
+ for i := n; i < len(q); i++ {
+ r, g, b, a := q[i].RGBA()
+ if r != 0 || g != 0 || b != 0 || a != 0xffff {
+ return false
+ }
+ }
+ return true
+}
+
var frames = []string{
"../testdata/video-001.gif",
"../testdata/video-005.gray.gif",
}
-func TestEncodeAll(t *testing.T) {
+func testEncodeAll(t *testing.T, go1Dot5Fields bool, useGlobalColorModel bool) {
+ const width, height = 150, 103
+
g0 := &GIF{
Image: make([]*image.Paletted, len(frames)),
Delay: make([]int, len(frames)),
LoopCount: 5,
}
for i, f := range frames {
- m, err := readGIF(f)
+ g, err := readGIF(f)
if err != nil {
t.Fatal(f, err)
}
- g0.Image[i] = m.Image[0]
+ m := g.Image[0]
+ if m.Bounds().Dx() != width || m.Bounds().Dy() != height {
+ t.Fatalf("frame %d had unexpected bounds: got %v, want width/height = %d/%d",
+ i, m.Bounds(), width, height)
+ }
+ g0.Image[i] = m
}
+ // The GIF.Disposal, GIF.Config and GIF.BackgroundIndex fields were added
+ // in Go 1.5. Valid Go 1.4 or earlier code should still produce valid GIFs.
+ //
+ // On the following line, color.Model is an interface type, and
+ // color.Palette is a concrete (slice) type.
+ globalColorModel, backgroundIndex := color.Model(color.Palette(nil)), uint8(0)
+ if useGlobalColorModel {
+ globalColorModel, backgroundIndex = color.Palette(palette.WebSafe), uint8(1)
+ }
+ if go1Dot5Fields {
+ g0.Disposal = make([]byte, len(g0.Image))
+ for i := range g0.Disposal {
+ g0.Disposal[i] = DisposalNone
+ }
+ g0.Config = image.Config{
+ ColorModel: globalColorModel,
+ Width: width,
+ Height: height,
+ }
+ g0.BackgroundIndex = backgroundIndex
+ }
+
var buf bytes.Buffer
if err := EncodeAll(&buf, g0); err != nil {
t.Fatal("EncodeAll:", err)
}
- g1, err := DecodeAll(&buf)
+ encoded := buf.Bytes()
+ config, err := DecodeConfig(bytes.NewReader(encoded))
+ if err != nil {
+ t.Fatal("DecodeConfig:", err)
+ }
+ g1, err := DecodeAll(bytes.NewReader(encoded))
if err != nil {
t.Fatal("DecodeAll:", err)
}
+
+ if !reflect.DeepEqual(config, g1.Config) {
+ t.Errorf("DecodeConfig inconsistent with DecodeAll")
+ }
+ if !palettesEqual(g1.Config.ColorModel.(color.Palette), globalColorModel.(color.Palette)) {
+ t.Errorf("unexpected global color model")
+ }
+ if w, h := g1.Config.Width, g1.Config.Height; w != width || h != height {
+ t.Errorf("got config width * height = %d * %d, want %d * %d", w, h, width, height)
+ }
+
if g0.LoopCount != g1.LoopCount {
t.Errorf("loop counts differ: %d and %d", g0.LoopCount, g1.LoopCount)
}
+ if backgroundIndex != g1.BackgroundIndex {
+ t.Errorf("background indexes differ: %d and %d", backgroundIndex, g1.BackgroundIndex)
+ }
+ if len(g0.Image) != len(g1.Image) {
+ t.Fatalf("image lengths differ: %d and %d", len(g0.Image), len(g1.Image))
+ }
+ if len(g1.Image) != len(g1.Delay) {
+ t.Fatalf("image and delay lengths differ: %d and %d", len(g1.Image), len(g1.Delay))
+ }
+ if len(g1.Image) != len(g1.Disposal) {
+ t.Fatalf("image and disposal lengths differ: %d and %d", len(g1.Image), len(g1.Disposal))
+ }
+
for i := range g0.Image {
m0, m1 := g0.Image[i], g1.Image[i]
if m0.Bounds() != m1.Bounds() {
- t.Errorf("%s, bounds differ: %v and %v", frames[i], m0.Bounds(), m1.Bounds())
+ t.Errorf("frame %d: bounds differ: %v and %v", i, m0.Bounds(), m1.Bounds())
}
d0, d1 := g0.Delay[i], g1.Delay[i]
if d0 != d1 {
- t.Errorf("%s: delay values differ: %d and %d", frames[i], d0, d1)
+ t.Errorf("frame %d: delay values differ: %d and %d", i, d0, d1)
+ }
+ p0, p1 := uint8(0), g1.Disposal[i]
+ if go1Dot5Fields {
+ p0 = DisposalNone
+ }
+ if p0 != p1 {
+ t.Errorf("frame %d: disposal values differ: %d and %d", i, p0, p1)
}
}
+}
- g1.Delay = make([]int, 1)
- if err := EncodeAll(ioutil.Discard, g1); err == nil {
+func TestEncodeAllGo1Dot4(t *testing.T) { testEncodeAll(t, false, false) }
+func TestEncodeAllGo1Dot5(t *testing.T) { testEncodeAll(t, true, false) }
+func TestEncodeAllGo1Dot5GlobalColorModel(t *testing.T) { testEncodeAll(t, true, true) }
+
+func TestEncodeMismatchDelay(t *testing.T) {
+ images := make([]*image.Paletted, 2)
+ for i := range images {
+ images[i] = image.NewPaletted(image.Rect(0, 0, 5, 5), palette.Plan9)
+ }
+
+ g0 := &GIF{
+ Image: images,
+ Delay: make([]int, 1),
+ }
+ if err := EncodeAll(ioutil.Discard, g0); err == nil {
t.Error("expected error from mismatched delay and image slice lengths")
}
+
+ g1 := &GIF{
+ Image: images,
+ Delay: make([]int, len(images)),
+ Disposal: make([]byte, 1),
+ }
+ for i := range g1.Disposal {
+ g1.Disposal[i] = DisposalNone
+ }
+ if err := EncodeAll(ioutil.Discard, g1); err == nil {
+ t.Error("expected error from mismatched disposal and image slice lengths")
+ }
+}
+
+func TestEncodeZeroGIF(t *testing.T) {
if err := EncodeAll(ioutil.Discard, &GIF{}); err == nil {
t.Error("expected error from providing empty gif")
}
}
+func TestEncodeAllFramesOutOfBounds(t *testing.T) {
+ images := []*image.Paletted{
+ image.NewPaletted(image.Rect(0, 0, 5, 5), palette.Plan9),
+ image.NewPaletted(image.Rect(2, 2, 8, 8), palette.Plan9),
+ image.NewPaletted(image.Rect(3, 3, 4, 4), palette.Plan9),
+ }
+ for _, upperBound := range []int{6, 10} {
+ g := &GIF{
+ Image: images,
+ Delay: make([]int, len(images)),
+ Disposal: make([]byte, len(images)),
+ Config: image.Config{
+ Width: upperBound,
+ Height: upperBound,
+ },
+ }
+ err := EncodeAll(ioutil.Discard, g)
+ if upperBound >= 8 {
+ if err != nil {
+ t.Errorf("upperBound=%d: %v", upperBound, err)
+ }
+ } else {
+ if err == nil {
+ t.Errorf("upperBound=%d: got nil error, want non-nil", upperBound)
+ }
+ }
+ }
+}
+
+func TestEncodeNonZeroMinPoint(t *testing.T) {
+ points := []image.Point{
+ image.Point{-8, -9},
+ image.Point{-4, -4},
+ image.Point{-3, +3},
+ image.Point{+0, +0},
+ image.Point{+2, +2},
+ }
+ for _, p := range points {
+ src := image.NewPaletted(image.Rectangle{Min: p, Max: p.Add(image.Point{6, 6})}, palette.Plan9)
+ var buf bytes.Buffer
+ if err := Encode(&buf, src, nil); err != nil {
+ t.Errorf("p=%v: Encode: %v", p, err)
+ continue
+ }
+ m, err := Decode(&buf)
+ if err != nil {
+ t.Errorf("p=%v: Decode: %v", p, err)
+ continue
+ }
+ if got, want := m.Bounds(), image.Rect(0, 0, 6, 6); got != want {
+ t.Errorf("p=%v: got %v, want %v", p, got, want)
+ }
+ }
+}
+
+func TestEncodeImplicitConfigSize(t *testing.T) {
+ // For backwards compatibility for Go 1.4 and earlier code, the Config
+ // field is optional, and if zero, the width and height is implied by the
+ // first (and in this case only) frame's width and height.
+ //
+ // A Config only specifies a width and height (two integers) while an
+ // image.Image's Bounds method returns an image.Rectangle (four integers).
+ // For a gif.GIF, the overall bounds' top-left point is always implicitly
+ // (0, 0), and any frame whose bounds have a negative X or Y will be
+ // outside those overall bounds, so encoding should fail.
+ for _, lowerBound := range []int{-1, 0, 1} {
+ images := []*image.Paletted{
+ image.NewPaletted(image.Rect(lowerBound, lowerBound, 4, 4), palette.Plan9),
+ }
+ g := &GIF{
+ Image: images,
+ Delay: make([]int, len(images)),
+ }
+ err := EncodeAll(ioutil.Discard, g)
+ if lowerBound >= 0 {
+ if err != nil {
+ t.Errorf("lowerBound=%d: %v", lowerBound, err)
+ }
+ } else {
+ if err == nil {
+ t.Errorf("lowerBound=%d: got nil error, want non-nil", lowerBound)
+ }
+ }
+ }
+}
+
+func TestEncodePalettes(t *testing.T) {
+ const w, h = 5, 5
+ pals := []color.Palette{{
+ color.RGBA{0x00, 0x00, 0x00, 0xff},
+ color.RGBA{0x01, 0x00, 0x00, 0xff},
+ color.RGBA{0x02, 0x00, 0x00, 0xff},
+ }, {
+ color.RGBA{0x00, 0x00, 0x00, 0xff},
+ color.RGBA{0x00, 0x01, 0x00, 0xff},
+ }, {
+ color.RGBA{0x00, 0x00, 0x03, 0xff},
+ color.RGBA{0x00, 0x00, 0x02, 0xff},
+ color.RGBA{0x00, 0x00, 0x01, 0xff},
+ color.RGBA{0x00, 0x00, 0x00, 0xff},
+ }, {
+ color.RGBA{0x10, 0x07, 0xf0, 0xff},
+ color.RGBA{0x20, 0x07, 0xf0, 0xff},
+ color.RGBA{0x30, 0x07, 0xf0, 0xff},
+ color.RGBA{0x40, 0x07, 0xf0, 0xff},
+ color.RGBA{0x50, 0x07, 0xf0, 0xff},
+ }}
+ g0 := &GIF{
+ Image: []*image.Paletted{
+ image.NewPaletted(image.Rect(0, 0, w, h), pals[0]),
+ image.NewPaletted(image.Rect(0, 0, w, h), pals[1]),
+ image.NewPaletted(image.Rect(0, 0, w, h), pals[2]),
+ image.NewPaletted(image.Rect(0, 0, w, h), pals[3]),
+ },
+ Delay: make([]int, len(pals)),
+ Disposal: make([]byte, len(pals)),
+ Config: image.Config{
+ ColorModel: pals[2],
+ Width: w,
+ Height: h,
+ },
+ }
+
+ var buf bytes.Buffer
+ if err := EncodeAll(&buf, g0); err != nil {
+ t.Fatalf("EncodeAll: %v", err)
+ }
+ g1, err := DecodeAll(&buf)
+ if err != nil {
+ t.Fatalf("DecodeAll: %v", err)
+ }
+ if len(g0.Image) != len(g1.Image) {
+ t.Fatalf("image lengths differ: %d and %d", len(g0.Image), len(g1.Image))
+ }
+ for i, m := range g1.Image {
+ if got, want := m.Palette, pals[i]; !palettesEqual(got, want) {
+ t.Errorf("frame %d:\ngot %v\nwant %v", i, got, want)
+ }
+ }
+}
+
func BenchmarkEncode(b *testing.B) {
b.StopTimer()
diff --git a/llgo/third_party/gofrontend/libgo/go/image/image.go b/llgo/third_party/gofrontend/libgo/go/image/image.go
index 6b8e5c4877e..20b64d78e1a 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/image.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/image.go
@@ -18,7 +18,7 @@
// initialization side effects.
//
// See "The Go image package" for more details:
-// http://golang.org/doc/articles/image_package.html
+// https://golang.org/doc/articles/image_package.html
package image
import (
@@ -46,9 +46,9 @@ type Image interface {
}
// PalettedImage is an image whose colors may come from a limited palette.
-// If m is a PalettedImage and m.ColorModel() returns a PalettedColorModel p,
+// If m is a PalettedImage and m.ColorModel() returns a color.Palette p,
// then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's
-// color model is not a PalettedColorModel, then ColorIndexAt's behavior is
+// color model is not a color.Palette, then ColorIndexAt's behavior is
// undefined.
type PalettedImage interface {
// ColorIndexAt returns the palette index of the pixel at (x, y).
@@ -570,7 +570,7 @@ func NewAlpha(r Rectangle) *Alpha {
return &Alpha{pix, 1 * w, r}
}
-// Alpha16 is an in-memory image whose At method returns color.Alpha64 values.
+// Alpha16 is an in-memory image whose At method returns color.Alpha16 values.
type Alpha16 struct {
// Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
@@ -826,6 +826,92 @@ func NewGray16(r Rectangle) *Gray16 {
return &Gray16{pix, 2 * w, r}
}
+// CMYK is an in-memory image whose At method returns color.CMYK values.
+type CMYK struct {
+ // Pix holds the image's pixels, in C, M, Y, K order. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *CMYK) ColorModel() color.Model { return color.CMYKModel }
+
+func (p *CMYK) Bounds() Rectangle { return p.Rect }
+
+func (p *CMYK) At(x, y int) color.Color {
+ return p.CMYKAt(x, y)
+}
+
+func (p *CMYK) CMYKAt(x, y int) color.CMYK {
+ if !(Point{x, y}.In(p.Rect)) {
+ 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]}
+}
+
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *CMYK) PixOffset(x, y int) int {
+ return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+}
+
+func (p *CMYK) Set(x, y int, c color.Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ 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
+}
+
+func (p *CMYK) SetCMYK(x, y int, c color.CMYK) {
+ if !(Point{x, y}.In(p.Rect)) {
+ 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
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *CMYK) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &CMYK{}
+ }
+ i := p.PixOffset(r.Min.X, r.Min.Y)
+ return &CMYK{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
+}
+
+// Opaque scans the entire image and reports whether it is fully opaque.
+func (p *CMYK) Opaque() bool {
+ return true
+}
+
+// NewCMYK returns a new CMYK with the given bounds.
+func NewCMYK(r Rectangle) *CMYK {
+ w, h := r.Dx(), r.Dy()
+ buf := make([]uint8, 4*w*h)
+ return &CMYK{buf, 4 * w, r}
+}
+
// Paletted is an in-memory image of uint8 indices into a given palette.
type Paletted struct {
// Pix holds the image's pixels, as palette indices. The pixel at
diff --git a/llgo/third_party/gofrontend/libgo/go/image/internal/imageutil/gen.go b/llgo/third_party/gofrontend/libgo/go/image/internal/imageutil/gen.go
new file mode 100644
index 00000000000..fc1e707f0fd
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/internal/imageutil/gen.go
@@ -0,0 +1,154 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+ "os"
+)
+
+var debug = flag.Bool("debug", false, "")
+
+func main() {
+ flag.Parse()
+
+ w := new(bytes.Buffer)
+ w.WriteString(pre)
+ for _, sratio := range subsampleRatios {
+ fmt.Fprintf(w, sratioCase, sratio, sratioLines[sratio])
+ }
+ w.WriteString(post)
+
+ if *debug {
+ os.Stdout.Write(w.Bytes())
+ return
+ }
+ out, err := format.Source(w.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := ioutil.WriteFile("impl.go", out, 0660); err != nil {
+ log.Fatal(err)
+ }
+}
+
+const pre = `// generated by "go run gen.go". DO NOT EDIT.
+
+package imageutil
+
+import (
+ "image"
+)
+
+// DrawYCbCr draws the YCbCr source image on the RGBA destination image with
+// r.Min in dst aligned with sp in src. It reports whether the draw was
+// successful. If it returns false, no dst pixels were changed.
+//
+// This function assumes that r is entirely within dst's bounds and the
+// translation of r from dst coordinate space to src coordinate space is
+// entirely within src's bounds.
+func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
+ // This function exists in the image/internal/imageutil package because it
+ // is needed by both the image/draw and image/jpeg packages, but it doesn't
+ // seem right for one of those two to depend on the other.
+ //
+ // Another option is to have this code be exported in the image package,
+ // but we'd need to make sure we're totally happy with the API (for the
+ // rest of Go 1 compatibility), and decide if we want to have a more
+ // general purpose DrawToRGBA method for other image types. One possibility
+ // is:
+ //
+ // func (src *YCbCr) CopyToRGBA(dst *RGBA, dr, sr Rectangle) (effectiveDr, effectiveSr Rectangle)
+ //
+ // in the spirit of the built-in copy function for 1-dimensional slices,
+ // that also allowed a CopyFromRGBA method if needed.
+
+ x0 := (r.Min.X - dst.Rect.Min.X) * 4
+ x1 := (r.Max.X - dst.Rect.Min.X) * 4
+ y0 := r.Min.Y - dst.Rect.Min.Y
+ y1 := r.Max.Y - dst.Rect.Min.Y
+ switch src.SubsampleRatio {
+`
+
+const post = `
+ default:
+ return false
+ }
+ return true
+}
+`
+
+const sratioCase = `
+ case image.YCbCrSubsampleRatio%s:
+ for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+ %s
+
+ // This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
+ yy1 := int32(src.Y[yi]) * 0x10100 // 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
+ }
+ if g < 0 {
+ g = 0
+ } else if g > 255 {
+ g = 255
+ }
+ if b < 0 {
+ b = 0
+ } else if b > 255 {
+ b = 255
+ }
+
+ dpix[x+0] = uint8(r)
+ dpix[x+1] = uint8(g)
+ dpix[x+2] = uint8(b)
+ dpix[x+3] = 255
+ }
+ }
+`
+
+var subsampleRatios = []string{
+ "444",
+ "422",
+ "420",
+ "440",
+}
+
+var sratioLines = map[string]string{
+ "444": `
+ ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
+ for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
+ `,
+ "422": `
+ ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2
+ for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
+ ci := ciBase + sx/2
+ `,
+ "420": `
+ ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2
+ for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
+ ci := ciBase + sx/2
+ `,
+ "440": `
+ ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X)
+ for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
+ `,
+}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/internal/imageutil/imageutil.go b/llgo/third_party/gofrontend/libgo/go/image/internal/imageutil/imageutil.go
new file mode 100644
index 00000000000..10cef0c6650
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/internal/imageutil/imageutil.go
@@ -0,0 +1,8 @@
+// Copyright 2015 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.
+
+//go:generate go run gen.go
+
+// Package imageutil contains code shared by image-related packages.
+package imageutil
diff --git a/llgo/third_party/gofrontend/libgo/go/image/internal/imageutil/impl.go b/llgo/third_party/gofrontend/libgo/go/image/internal/imageutil/impl.go
new file mode 100644
index 00000000000..fd7826d4a97
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/internal/imageutil/impl.go
@@ -0,0 +1,196 @@
+// generated by "go run gen.go". DO NOT EDIT.
+
+package imageutil
+
+import (
+ "image"
+)
+
+// DrawYCbCr draws the YCbCr source image on the RGBA destination image with
+// r.Min in dst aligned with sp in src. It reports whether the draw was
+// successful. If it returns false, no dst pixels were changed.
+//
+// This function assumes that r is entirely within dst's bounds and the
+// translation of r from dst coordinate space to src coordinate space is
+// entirely within src's bounds.
+func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
+ // This function exists in the image/internal/imageutil package because it
+ // is needed by both the image/draw and image/jpeg packages, but it doesn't
+ // seem right for one of those two to depend on the other.
+ //
+ // Another option is to have this code be exported in the image package,
+ // but we'd need to make sure we're totally happy with the API (for the
+ // rest of Go 1 compatibility), and decide if we want to have a more
+ // general purpose DrawToRGBA method for other image types. One possibility
+ // is:
+ //
+ // func (src *YCbCr) CopyToRGBA(dst *RGBA, dr, sr Rectangle) (effectiveDr, effectiveSr Rectangle)
+ //
+ // in the spirit of the built-in copy function for 1-dimensional slices,
+ // that also allowed a CopyFromRGBA method if needed.
+
+ x0 := (r.Min.X - dst.Rect.Min.X) * 4
+ x1 := (r.Max.X - dst.Rect.Min.X) * 4
+ y0 := r.Min.Y - dst.Rect.Min.Y
+ y1 := r.Max.Y - dst.Rect.Min.Y
+ switch src.SubsampleRatio {
+
+ case image.YCbCrSubsampleRatio444:
+ for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+
+ ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
+ 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.
+ 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
+ }
+ if g < 0 {
+ g = 0
+ } else if g > 255 {
+ g = 255
+ }
+ if b < 0 {
+ b = 0
+ } else if b > 255 {
+ b = 255
+ }
+
+ dpix[x+0] = uint8(r)
+ dpix[x+1] = uint8(g)
+ dpix[x+2] = uint8(b)
+ dpix[x+3] = 255
+ }
+ }
+
+ case image.YCbCrSubsampleRatio422:
+ for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+
+ ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2
+ for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
+ 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.
+ 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
+ }
+ if g < 0 {
+ g = 0
+ } else if g > 255 {
+ g = 255
+ }
+ if b < 0 {
+ b = 0
+ } else if b > 255 {
+ b = 255
+ }
+
+ dpix[x+0] = uint8(r)
+ dpix[x+1] = uint8(g)
+ dpix[x+2] = uint8(b)
+ dpix[x+3] = 255
+ }
+ }
+
+ case image.YCbCrSubsampleRatio420:
+ for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+
+ ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2
+ for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
+ 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.
+ 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
+ }
+ if g < 0 {
+ g = 0
+ } else if g > 255 {
+ g = 255
+ }
+ if b < 0 {
+ b = 0
+ } else if b > 255 {
+ b = 255
+ }
+
+ dpix[x+0] = uint8(r)
+ dpix[x+1] = uint8(g)
+ dpix[x+2] = uint8(b)
+ dpix[x+3] = 255
+ }
+ }
+
+ case image.YCbCrSubsampleRatio440:
+ for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+
+ ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X)
+ 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.
+ 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
+ }
+ if g < 0 {
+ g = 0
+ } else if g > 255 {
+ g = 255
+ }
+ if b < 0 {
+ b = 0
+ } else if b > 255 {
+ b = 255
+ }
+
+ dpix[x+0] = uint8(r)
+ dpix[x+1] = uint8(g)
+ dpix[x+2] = uint8(b)
+ dpix[x+3] = 255
+ }
+ }
+
+ default:
+ return false
+ }
+ return true
+}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/jpeg/huffman.go b/llgo/third_party/gofrontend/libgo/go/image/jpeg/huffman.go
index d4ff4cfa0ce..4f8fe8eff32 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/jpeg/huffman.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/jpeg/huffman.go
@@ -187,7 +187,9 @@ func (d *decoder) decodeHuffman(h *huffman) (uint8, error) {
// There are no more bytes of data in this segment, but we may still
// be able to read the next symbol out of the previously read bits.
// First, undo the readByte that the ensureNBits call made.
- d.unreadByteStuffedByte()
+ if d.bytes.nUnreadable != 0 {
+ d.unreadByteStuffedByte()
+ }
goto slowPath
}
}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/jpeg/reader.go b/llgo/third_party/gofrontend/libgo/go/image/jpeg/reader.go
index 6d8b1d1d036..adf97abbd1d 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/jpeg/reader.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/jpeg/reader.go
@@ -10,6 +10,7 @@ package jpeg
import (
"image"
"image/color"
+ "image/internal/imageutil"
"io"
)
@@ -26,6 +27,8 @@ type UnsupportedError string
func (e UnsupportedError) Error() string { return "unsupported JPEG feature: " + string(e) }
+var errUnsupportedSubsamplingRatio = UnsupportedError("luma/chroma subsampling ratio")
+
// Component specification, specified in section B.2.2.
type component struct {
h int // Horizontal sampling factor.
@@ -41,32 +44,35 @@ const (
maxTh = 3
maxTq = 3
- // A grayscale JPEG image has only a Y component.
- nGrayComponent = 1
- // A color JPEG image has Y, Cb and Cr components.
- nColorComponent = 3
+ maxComponents = 4
+)
- // We only support 4:4:4, 4:4:0, 4:2:2 and 4:2:0 downsampling, and therefore the
- // number of luma samples per chroma sample is at most 2 in the horizontal
- // and 2 in the vertical direction.
- maxH = 2
- maxV = 2
+const (
+ sof0Marker = 0xc0 // Start Of Frame (Baseline).
+ sof1Marker = 0xc1 // Start Of Frame (Extended Sequential).
+ sof2Marker = 0xc2 // Start Of Frame (Progressive).
+ dhtMarker = 0xc4 // Define Huffman Table.
+ rst0Marker = 0xd0 // ReSTart (0).
+ rst7Marker = 0xd7 // ReSTart (7).
+ soiMarker = 0xd8 // Start Of Image.
+ eoiMarker = 0xd9 // End Of Image.
+ sosMarker = 0xda // Start Of Scan.
+ dqtMarker = 0xdb // Define Quantization Table.
+ driMarker = 0xdd // Define Restart Interval.
+ comMarker = 0xfe // COMment.
+ // "APPlication specific" markers aren't part of the JPEG spec per se,
+ // but in practice, their use is described at
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html
+ app0Marker = 0xe0
+ app14Marker = 0xee
+ app15Marker = 0xef
)
+// See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
const (
- soiMarker = 0xd8 // Start Of Image.
- eoiMarker = 0xd9 // End Of Image.
- sof0Marker = 0xc0 // Start Of Frame (Baseline).
- sof2Marker = 0xc2 // Start Of Frame (Progressive).
- dhtMarker = 0xc4 // Define Huffman Table.
- dqtMarker = 0xdb // Define Quantization Table.
- sosMarker = 0xda // Start Of Scan.
- driMarker = 0xdd // Define Restart Interval.
- rst0Marker = 0xd0 // ReSTart (0).
- rst7Marker = 0xd7 // ReSTart (7).
- app0Marker = 0xe0 // APPlication specific (0).
- app15Marker = 0xef // APPlication specific (15).
- comMarker = 0xfe // COMment.
+ adobeTransformUnknown = 0
+ adobeTransformYCbCr = 1
+ adobeTransformYCbCrK = 2
)
// unzig maps from the zig-zag ordering to the natural ordering. For example,
@@ -83,7 +89,7 @@ var unzig = [blockSize]int{
53, 60, 61, 54, 47, 55, 62, 63,
}
-// Reader is deprecated.
+// Deprecated: Reader is deprecated.
type Reader interface {
io.ByteReader
io.Reader
@@ -114,17 +120,25 @@ type decoder struct {
nUnreadable int
}
width, height int
- img1 *image.Gray
- img3 *image.YCbCr
- ri int // Restart Interval.
- nComp int
- progressive bool
- eobRun uint16 // End-of-Band run, specified in section G.1.2.2.
- comp [nColorComponent]component
- progCoeffs [nColorComponent][]block // Saved state between progressive-mode scans.
- huff [maxTc + 1][maxTh + 1]huffman
- quant [maxTq + 1]block // Quantization tables, in zig-zag order.
- tmp [blockSize + 1]byte
+
+ img1 *image.Gray
+ img3 *image.YCbCr
+ blackPix []byte
+ blackStride int
+
+ ri int // Restart Interval.
+ nComp int
+ progressive bool
+ jfif bool
+ adobeTransformValid bool
+ adobeTransform uint8
+ eobRun uint16 // End-of-Band run, specified in section G.1.2.2.
+
+ comp [maxComponents]component
+ progCoeffs [maxComponents][]block // Saved state between progressive-mode scans.
+ huff [maxTc + 1][maxTh + 1]huffman
+ quant [maxTq + 1]block // Quantization tables, in zig-zag order.
+ tmp [2 * blockSize]byte
}
// fill fills up the d.bytes.buf buffer from the underlying io.Reader. It
@@ -155,9 +169,6 @@ func (d *decoder) fill() error {
// sometimes overshoot and read one or two too many bytes. Two-byte overshoot
// can happen when expecting to read a 0xff 0x00 byte-stuffed byte.
func (d *decoder) unreadByteStuffedByte() {
- if d.bytes.nUnreadable == 0 {
- panic("jpeg: unreadByteStuffedByte call cannot be fulfilled")
- }
d.bytes.i -= d.bytes.nUnreadable
d.bytes.nUnreadable = 0
if d.bits.n >= 8 {
@@ -203,18 +214,19 @@ func (d *decoder) readByteStuffedByte() (x byte, err error) {
return 0xff, nil
}
+ d.bytes.nUnreadable = 0
+
x, err = d.readByte()
if err != nil {
return 0, err
}
+ d.bytes.nUnreadable = 1
if x != 0xff {
- d.bytes.nUnreadable = 1
return x, nil
}
x, err = d.readByte()
if err != nil {
- d.bytes.nUnreadable = 1
return 0, err
}
d.bytes.nUnreadable = 2
@@ -284,13 +296,18 @@ func (d *decoder) ignore(n int) error {
// Specified in section B.2.2.
func (d *decoder) processSOF(n int) error {
+ if d.nComp != 0 {
+ return FormatError("multiple SOF markers")
+ }
switch n {
- case 6 + 3*nGrayComponent:
- d.nComp = nGrayComponent
- case 6 + 3*nColorComponent:
- d.nComp = nColorComponent
+ case 6 + 3*1: // Grayscale image.
+ d.nComp = 1
+ case 6 + 3*3: // YCbCr or RGB image.
+ d.nComp = 3
+ case 6 + 3*4: // YCbCrK or CMYK image.
+ d.nComp = 4
default:
- return UnsupportedError("SOF has wrong length")
+ return UnsupportedError("number of components")
}
if err := d.readFull(d.tmp[:n]); err != nil {
return err
@@ -302,12 +319,34 @@ func (d *decoder) processSOF(n int) error {
d.height = int(d.tmp[1])<<8 + int(d.tmp[2])
d.width = int(d.tmp[3])<<8 + int(d.tmp[4])
if int(d.tmp[5]) != d.nComp {
- return UnsupportedError("SOF has wrong number of image components")
+ return FormatError("SOF has wrong length")
}
+
for i := 0; i < d.nComp; i++ {
d.comp[i].c = d.tmp[6+3*i]
+ // Section B.2.2 states that "the value of C_i shall be different from
+ // the values of C_1 through C_(i-1)".
+ for j := 0; j < i; j++ {
+ if d.comp[i].c == d.comp[j].c {
+ return FormatError("repeated component identifier")
+ }
+ }
+
d.comp[i].tq = d.tmp[8+3*i]
- if d.nComp == nGrayComponent {
+ if d.comp[i].tq > maxTq {
+ return FormatError("bad Tq value")
+ }
+
+ hv := d.tmp[7+3*i]
+ h, v := int(hv>>4), int(hv&0x0f)
+ if h < 1 || 4 < h || v < 1 || 4 < v {
+ return FormatError("luma/chroma subsampling ratio")
+ }
+ if h == 3 || v == 3 {
+ return errUnsupportedSubsamplingRatio
+ }
+ switch d.nComp {
+ case 1:
// If a JPEG image has only one component, section A.2 says "this data
// is non-interleaved by definition" and section A.2.2 says "[in this
// case...] the order of data units within a scan shall be left-to-right
@@ -319,45 +358,104 @@ func (d *decoder) processSOF(n int) error {
// always 1. The component's (h, v) is effectively always (1, 1): even if
// the nominal (h, v) is (2, 1), a 20x5 image is encoded in three 8x8
// MCUs, not two 16x8 MCUs.
- d.comp[i].h = 1
- d.comp[i].v = 1
- continue
- }
- hv := d.tmp[7+3*i]
- d.comp[i].h = int(hv >> 4)
- d.comp[i].v = int(hv & 0x0f)
- // For color images, we only support 4:4:4, 4:4:0, 4:2:2 or 4:2:0 chroma
- // downsampling ratios. This implies that the (h, v) values for the Y
- // component are either (1, 1), (1, 2), (2, 1) or (2, 2), and the (h, v)
- // values for the Cr and Cb components must be (1, 1).
- if i == 0 {
- if hv != 0x11 && hv != 0x21 && hv != 0x22 && hv != 0x12 {
- return UnsupportedError("luma/chroma downsample ratio")
+ h, v = 1, 1
+
+ case 3:
+ // For YCbCr images, we only support 4:4:4, 4:4:0, 4:2:2, 4:2:0,
+ // 4:1:1 or 4:1:0 chroma subsampling ratios. This implies that the
+ // (h, v) values for the Y component are either (1, 1), (1, 2),
+ // (2, 1), (2, 2), (4, 1) or (4, 2), and the Y component's values
+ // must be a multiple of the Cb and Cr component's values. We also
+ // assume that the two chroma components have the same subsampling
+ // ratio.
+ switch i {
+ case 0: // Y.
+ // We have already verified, above, that h and v are both
+ // either 1, 2 or 4, so invalid (h, v) combinations are those
+ // with v == 4.
+ if v == 4 {
+ return errUnsupportedSubsamplingRatio
+ }
+ case 1: // Cb.
+ if d.comp[0].h%h != 0 || d.comp[0].v%v != 0 {
+ return errUnsupportedSubsamplingRatio
+ }
+ case 2: // Cr.
+ if d.comp[1].h != h || d.comp[1].v != v {
+ return errUnsupportedSubsamplingRatio
+ }
+ }
+
+ case 4:
+ // For 4-component images (either CMYK or YCbCrK), we only support two
+ // hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22].
+ // Theoretically, 4-component JPEG images could mix and match hv values
+ // but in practice, those two combinations are the only ones in use,
+ // and it simplifies the applyBlack code below if we can assume that:
+ // - for CMYK, the C and K channels have full samples, and if the M
+ // and Y channels subsample, they subsample both horizontally and
+ // vertically.
+ // - for YCbCrK, the Y and K channels have full samples.
+ switch i {
+ case 0:
+ if hv != 0x11 && hv != 0x22 {
+ return errUnsupportedSubsamplingRatio
+ }
+ case 1, 2:
+ if hv != 0x11 {
+ return errUnsupportedSubsamplingRatio
+ }
+ case 3:
+ if d.comp[0].h != h || d.comp[0].v != v {
+ return errUnsupportedSubsamplingRatio
+ }
}
- } else if hv != 0x11 {
- return UnsupportedError("luma/chroma downsample ratio")
}
+
+ d.comp[i].h = h
+ d.comp[i].v = v
}
return nil
}
// Specified in section B.2.4.1.
func (d *decoder) processDQT(n int) error {
- const qtLength = 1 + blockSize
- for ; n >= qtLength; n -= qtLength {
- if err := d.readFull(d.tmp[:qtLength]); err != nil {
+loop:
+ for n > 0 {
+ n--
+ x, err := d.readByte()
+ if err != nil {
return err
}
- pq := d.tmp[0] >> 4
- if pq != 0 {
- return UnsupportedError("bad Pq value")
- }
- tq := d.tmp[0] & 0x0f
+ tq := x & 0x0f
if tq > maxTq {
return FormatError("bad Tq value")
}
- for i := range d.quant[tq] {
- d.quant[tq][i] = int32(d.tmp[i+1])
+ switch x >> 4 {
+ default:
+ return FormatError("bad Pq value")
+ case 0:
+ if n < blockSize {
+ break loop
+ }
+ n -= blockSize
+ if err := d.readFull(d.tmp[:blockSize]); err != nil {
+ return err
+ }
+ for i := range d.quant[tq] {
+ d.quant[tq][i] = int32(d.tmp[i])
+ }
+ case 1:
+ if n < 2*blockSize {
+ break loop
+ }
+ n -= 2 * blockSize
+ if err := d.readFull(d.tmp[:2*blockSize]); err != nil {
+ return err
+ }
+ for i := range d.quant[tq] {
+ d.quant[tq][i] = int32(d.tmp[2*i])<<8 | int32(d.tmp[2*i+1])
+ }
}
}
if n != 0 {
@@ -378,6 +476,43 @@ func (d *decoder) processDRI(n int) error {
return nil
}
+func (d *decoder) processApp0Marker(n int) error {
+ if n < 5 {
+ return d.ignore(n)
+ }
+ if err := d.readFull(d.tmp[:5]); err != nil {
+ return err
+ }
+ n -= 5
+
+ d.jfif = d.tmp[0] == 'J' && d.tmp[1] == 'F' && d.tmp[2] == 'I' && d.tmp[3] == 'F' && d.tmp[4] == '\x00'
+
+ if n > 0 {
+ return d.ignore(n)
+ }
+ return nil
+}
+
+func (d *decoder) processApp14Marker(n int) error {
+ if n < 12 {
+ return d.ignore(n)
+ }
+ if err := d.readFull(d.tmp[:12]); err != nil {
+ return err
+ }
+ n -= 12
+
+ if d.tmp[0] == 'A' && d.tmp[1] == 'd' && d.tmp[2] == 'o' && d.tmp[3] == 'b' && d.tmp[4] == 'e' {
+ d.adobeTransformValid = true
+ d.adobeTransform = d.tmp[11]
+ }
+
+ if n > 0 {
+ return d.ignore(n)
+ }
+ return nil
+}
+
// decode reads a JPEG image from r and returns it as an image.Image.
func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
d.r = r
@@ -459,25 +594,48 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
return nil, FormatError("short segment length")
}
- switch {
- case marker == sof0Marker || marker == sof2Marker: // Start Of Frame.
+ switch marker {
+ case sof0Marker, sof1Marker, sof2Marker:
d.progressive = marker == sof2Marker
err = d.processSOF(n)
- if configOnly {
+ if configOnly && d.jfif {
return nil, err
}
- case marker == dhtMarker: // Define Huffman Table.
- err = d.processDHT(n)
- case marker == dqtMarker: // Define Quantization Table.
- err = d.processDQT(n)
- case marker == sosMarker: // Start Of Scan.
+ case dhtMarker:
+ if configOnly {
+ err = d.ignore(n)
+ } else {
+ err = d.processDHT(n)
+ }
+ case dqtMarker:
+ if configOnly {
+ err = d.ignore(n)
+ } else {
+ err = d.processDQT(n)
+ }
+ case sosMarker:
+ if configOnly {
+ return nil, nil
+ }
err = d.processSOS(n)
- case marker == driMarker: // Define Restart Interval.
- err = d.processDRI(n)
- case app0Marker <= marker && marker <= app15Marker || marker == comMarker: // APPlication specific, or COMment.
- err = d.ignore(n)
+ case driMarker:
+ if configOnly {
+ err = d.ignore(n)
+ } else {
+ err = d.processDRI(n)
+ }
+ case app0Marker:
+ err = d.processApp0Marker(n)
+ case app14Marker:
+ err = d.processApp14Marker(n)
default:
- err = UnsupportedError("unknown marker")
+ if app0Marker <= marker && marker <= app15Marker || marker == comMarker {
+ err = d.ignore(n)
+ } else if marker < 0xc0 { // See Table B.1 "Marker code assignments".
+ err = FormatError("unknown marker")
+ } else {
+ err = UnsupportedError("unknown marker")
+ }
}
if err != nil {
return nil, err
@@ -487,11 +645,118 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
return d.img1, nil
}
if d.img3 != nil {
+ if d.blackPix != nil {
+ return d.applyBlack()
+ } else if d.isRGB() {
+ return d.convertToRGB()
+ }
return d.img3, nil
}
return nil, FormatError("missing SOS marker")
}
+// applyBlack combines d.img3 and d.blackPix into a CMYK image. The formula
+// used depends on whether the JPEG image is stored as CMYK or YCbCrK,
+// indicated by the APP14 (Adobe) metadata.
+//
+// Adobe CMYK JPEG images are inverted, where 255 means no ink instead of full
+// ink, so we apply "v = 255 - v" at various points. Note that a double
+// inversion is a no-op, so inversions might be implicit in the code below.
+func (d *decoder) applyBlack() (image.Image, error) {
+ if !d.adobeTransformValid {
+ return nil, UnsupportedError("unknown color model: 4-component JPEG doesn't have Adobe APP14 metadata")
+ }
+
+ // If the 4-component JPEG image isn't explicitly marked as "Unknown (RGB
+ // or CMYK)" as per
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
+ // we assume that it is YCbCrK. This matches libjpeg's jdapimin.c.
+ if d.adobeTransform != adobeTransformUnknown {
+ // Convert the YCbCr part of the YCbCrK to RGB, invert the RGB to get
+ // CMY, and patch in the original K. The RGB to CMY inversion cancels
+ // out the 'Adobe inversion' described in the applyBlack doc comment
+ // above, so in practice, only the fourth channel (black) is inverted.
+ bounds := d.img3.Bounds()
+ img := image.NewRGBA(bounds)
+ imageutil.DrawYCbCr(img, bounds, d.img3, bounds.Min)
+ for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 {
+ for i, x := iBase+3, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 {
+ img.Pix[i] = 255 - d.blackPix[(y-bounds.Min.Y)*d.blackStride+(x-bounds.Min.X)]
+ }
+ }
+ return &image.CMYK{
+ Pix: img.Pix,
+ Stride: img.Stride,
+ Rect: img.Rect,
+ }, nil
+ }
+
+ // The first three channels (cyan, magenta, yellow) of the CMYK
+ // were decoded into d.img3, but each channel was decoded into a separate
+ // []byte slice, and some channels may be subsampled. We interleave the
+ // separate channels into an image.CMYK's single []byte slice containing 4
+ // contiguous bytes per pixel.
+ bounds := d.img3.Bounds()
+ img := image.NewCMYK(bounds)
+
+ translations := [4]struct {
+ src []byte
+ stride int
+ }{
+ {d.img3.Y, d.img3.YStride},
+ {d.img3.Cb, d.img3.CStride},
+ {d.img3.Cr, d.img3.CStride},
+ {d.blackPix, d.blackStride},
+ }
+ for t, translation := range translations {
+ subsample := d.comp[t].h != d.comp[0].h || d.comp[t].v != d.comp[0].v
+ for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 {
+ sy := y - bounds.Min.Y
+ if subsample {
+ sy /= 2
+ }
+ for i, x := iBase+t, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 {
+ sx := x - bounds.Min.X
+ if subsample {
+ sx /= 2
+ }
+ img.Pix[i] = 255 - translation.src[sy*translation.stride+sx]
+ }
+ }
+ }
+ return img, nil
+}
+
+func (d *decoder) isRGB() bool {
+ if d.jfif {
+ return false
+ }
+ if d.adobeTransformValid && d.adobeTransform == adobeTransformUnknown {
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
+ // says that 0 means Unknown (and in practice RGB) and 1 means YCbCr.
+ return true
+ }
+ return d.comp[0].c == 'R' && d.comp[1].c == 'G' && d.comp[2].c == 'B'
+}
+
+func (d *decoder) convertToRGB() (image.Image, error) {
+ cScale := d.comp[0].h / d.comp[1].h
+ bounds := d.img3.Bounds()
+ img := image.NewRGBA(bounds)
+ for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+ po := img.PixOffset(bounds.Min.X, y)
+ yo := d.img3.YOffset(bounds.Min.X, y)
+ co := d.img3.COffset(bounds.Min.X, y)
+ for i, iMax := 0, bounds.Max.X-bounds.Min.X; i < iMax; i++ {
+ img.Pix[po+4*i+0] = d.img3.Y[yo+i]
+ img.Pix[po+4*i+1] = d.img3.Cb[co+i/cScale]
+ img.Pix[po+4*i+2] = d.img3.Cr[co+i/cScale]
+ img.Pix[po+4*i+3] = 255
+ }
+ }
+ return img, nil
+}
+
// Decode reads a JPEG image from r and returns it as an image.Image.
func Decode(r io.Reader) (image.Image, error) {
var d decoder
@@ -506,15 +771,25 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
return image.Config{}, err
}
switch d.nComp {
- case nGrayComponent:
+ case 1:
return image.Config{
ColorModel: color.GrayModel,
Width: d.width,
Height: d.height,
}, nil
- case nColorComponent:
+ case 3:
+ cm := color.YCbCrModel
+ if d.isRGB() {
+ cm = color.RGBAModel
+ }
+ return image.Config{
+ ColorModel: cm,
+ Width: d.width,
+ Height: d.height,
+ }, nil
+ case 4:
return image.Config{
- ColorModel: color.YCbCrModel,
+ ColorModel: color.CMYKModel,
Width: d.width,
Height: d.height,
}, nil
diff --git a/llgo/third_party/gofrontend/libgo/go/image/jpeg/reader_test.go b/llgo/third_party/gofrontend/libgo/go/image/jpeg/reader_test.go
index 4de2e8ee737..77376152bc0 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/jpeg/reader_test.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/jpeg/reader_test.go
@@ -15,6 +15,7 @@ import (
"os"
"strings"
"testing"
+ "time"
)
// TestDecodeProgressive tests that decoding the baseline and progressive
@@ -23,6 +24,8 @@ import (
func TestDecodeProgressive(t *testing.T) {
testCases := []string{
"../testdata/video-001",
+ "../testdata/video-001.q50.410",
+ "../testdata/video-001.q50.411",
"../testdata/video-001.q50.420",
"../testdata/video-001.q50.422",
"../testdata/video-001.q50.440",
@@ -184,6 +187,81 @@ func pixString(pix []byte, stride, x, y int) string {
return s.String()
}
+func TestTruncatedSOSDataDoesntPanic(t *testing.T) {
+ b, err := ioutil.ReadFile("../testdata/video-005.gray.q50.jpeg")
+ if err != nil {
+ t.Fatal(err)
+ }
+ sosMarker := []byte{0xff, 0xda}
+ i := bytes.Index(b, sosMarker)
+ if i < 0 {
+ t.Fatal("SOS marker not found")
+ }
+ i += len(sosMarker)
+ j := i + 10
+ if j > len(b) {
+ j = len(b)
+ }
+ for ; i < j; i++ {
+ Decode(bytes.NewReader(b[:i]))
+ }
+}
+
+func TestLargeImageWithShortData(t *testing.T) {
+ // This input is an invalid JPEG image, based on the fuzzer-generated image
+ // in issue 10413. It is only 504 bytes, and shouldn't take long for Decode
+ // to return an error. The Start Of Frame marker gives the image dimensions
+ // as 8192 wide and 8192 high, so even if an unreadByteStuffedByte bug
+ // doesn't technically lead to an infinite loop, such a bug can still cause
+ // an unreasonably long loop for such a short input.
+ const input = "" +
+ "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01" +
+ "\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10" +
+ "\x0e\x89\x0e\x12\x11\x10\x13\x18\xff\xd8\xff\xe0\x00\x10\x4a\x46" +
+ "\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43" +
+ "\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10\x13\x18" +
+ "\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\x28\x3a\x33\x3d\x3c\x39" +
+ "\x33\x38\x37\x40\x48\x5c\x4e\x40\x44\x57\x45\x37\x38\x50\x6d\x51" +
+ "\x57\x5f\x62\x67\x68\x67\x3e\x4d\x71\x79\x70\x64\x78\x5c\x65\x67" +
+ "\x63\xff\xc0\x00\x0b\x08\x20\x00\x20\x00\x01\x01\x11\x00\xff\xc4" +
+ "\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00" +
+ "\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xff" +
+ "\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04" +
+ "\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x01\x06" +
+ "\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\xd8\xff\xdd" +
+ "\x42\xb1\xc1\x15\x52\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17" +
+ "\x18\x19\x1a\x25\x26\x27\x28\x29\x2a\x34\x35\x36\x37\x38\x39\x3a" +
+ "\x43\x44\x45\x46\x47\x48\x49\x4a\x53\x54\x55\x56\x57\x58\x59\x5a" +
+ "\x00\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75\x76\x77\x78\x79" +
+ "\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98" +
+ "\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6" +
+ "\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xff\xd8\xff\xe0\x00\x10" +
+ "\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb" +
+ "\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10" +
+ "\x13\x18\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\xc8\xc9\xca\xd2" +
+ "\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8" +
+ "\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x08" +
+ "\x01\x01\x00\x00\x3f\x00\xb9\xeb\x50\xb0\xdb\xc8\xa8\xe4\x63\x80" +
+ "\xdd\x31\xd6\x9d\xbb\xf2\xc5\x42\x1f\x6c\x6f\xf4\x34\xdd\x3c\xfc" +
+ "\xac\xe7\x3d\x80\xa9\xcc\x87\x34\xb3\x37\xfa\x2b\x9f\x6a\xad\x63" +
+ "\x20\x36\x9f\x78\x64\x75\xe6\xab\x7d\xb2\xde\x29\x70\xd3\x20\x27" +
+ "\xde\xaf\xa4\xf0\xca\x9f\x24\xa8\xdf\x46\xa8\x24\x84\x96\xe3\x77" +
+ "\xf9\x2e\xe0\x0a\x62\x7f\xdf\xd9"
+ c := make(chan error, 1)
+ go func() {
+ _, err := Decode(strings.NewReader(input))
+ c <- err
+ }()
+ select {
+ case err := <-c:
+ if err == nil {
+ t.Fatalf("got nil error, want non-nil")
+ }
+ case <-time.After(3 * time.Second):
+ t.Fatalf("timed out")
+ }
+}
+
func TestExtraneousData(t *testing.T) {
// Encode a 1x1 red image.
src := image.NewRGBA(image.Rect(0, 0, 1, 1))
diff --git a/llgo/third_party/gofrontend/libgo/go/image/jpeg/scan.go b/llgo/third_party/gofrontend/libgo/go/image/jpeg/scan.go
index 2bd1d9d531d..99734c01af0 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/jpeg/scan.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/jpeg/scan.go
@@ -9,27 +9,42 @@ import (
)
// makeImg allocates and initializes the destination image.
-func (d *decoder) makeImg(h0, v0, mxx, myy int) {
- if d.nComp == nGrayComponent {
+func (d *decoder) makeImg(mxx, myy int) {
+ if d.nComp == 1 {
m := image.NewGray(image.Rect(0, 0, 8*mxx, 8*myy))
d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
return
}
+
+ h0 := d.comp[0].h
+ v0 := d.comp[0].v
+ hRatio := h0 / d.comp[1].h
+ vRatio := v0 / d.comp[1].v
var subsampleRatio image.YCbCrSubsampleRatio
- switch {
- case h0 == 1 && v0 == 1:
+ switch hRatio<<4 | vRatio {
+ case 0x11:
subsampleRatio = image.YCbCrSubsampleRatio444
- case h0 == 1 && v0 == 2:
+ case 0x12:
subsampleRatio = image.YCbCrSubsampleRatio440
- case h0 == 2 && v0 == 1:
+ case 0x21:
subsampleRatio = image.YCbCrSubsampleRatio422
- case h0 == 2 && v0 == 2:
+ case 0x22:
subsampleRatio = image.YCbCrSubsampleRatio420
+ case 0x41:
+ subsampleRatio = image.YCbCrSubsampleRatio411
+ case 0x42:
+ subsampleRatio = image.YCbCrSubsampleRatio410
default:
panic("unreachable")
}
m := image.NewYCbCr(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy), subsampleRatio)
d.img3 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.YCbCr)
+
+ if d.nComp == 4 {
+ h3, v3 := d.comp[3].h, d.comp[3].v
+ d.blackPix = make([]byte, 8*h3*mxx*8*v3*myy)
+ d.blackStride = 8 * h3 * mxx
+ }
}
// Specified in section B.2.3.
@@ -47,15 +62,16 @@ func (d *decoder) processSOS(n int) error {
if n != 4+2*nComp {
return FormatError("SOS length inconsistent with number of components")
}
- var scan [nColorComponent]struct {
+ var scan [maxComponents]struct {
compIndex uint8
td uint8 // DC table selector.
ta uint8 // AC table selector.
}
+ totalHV := 0
for i := 0; i < nComp; i++ {
cs := d.tmp[1+2*i] // Component selector.
compIndex := -1
- for j, comp := range d.comp {
+ for j, comp := range d.comp[:d.nComp] {
if cs == comp.c {
compIndex = j
}
@@ -64,6 +80,18 @@ func (d *decoder) processSOS(n int) error {
return FormatError("unknown component selector")
}
scan[i].compIndex = uint8(compIndex)
+ // Section B.2.3 states that "the value of Cs_j shall be different from
+ // the values of Cs_1 through Cs_(j-1)". Since we have previously
+ // verified that a frame's component identifiers (C_i values in section
+ // B.2.2) are unique, it suffices to check that the implicit indexes
+ // into d.comp are unique.
+ for j := 0; j < i; j++ {
+ if scan[i].compIndex == scan[j].compIndex {
+ return FormatError("repeated component selector")
+ }
+ }
+ totalHV += d.comp[compIndex].h * d.comp[compIndex].v
+
scan[i].td = d.tmp[2+2*i] >> 4
if scan[i].td > maxTh {
return FormatError("bad Td value")
@@ -73,6 +101,11 @@ func (d *decoder) processSOS(n int) error {
return FormatError("bad Ta value")
}
}
+ // Section B.2.3 states that if there is more than one component then the
+ // total H*V values in a scan must be <= 10.
+ if d.nComp > 1 && totalHV > 10 {
+ return FormatError("total sampling factors too large")
+ }
// zigStart and zigEnd are the spectral selection bounds.
// ah and al are the successive approximation high and low values.
@@ -112,7 +145,7 @@ func (d *decoder) processSOS(n int) error {
mxx := (d.width + 8*h0 - 1) / (8 * h0)
myy := (d.height + 8*v0 - 1) / (8 * v0)
if d.img1 == nil && d.img3 == nil {
- d.makeImg(h0, v0, mxx, myy)
+ d.makeImg(mxx, myy)
}
if d.progressive {
for i := 0; i < nComp; i++ {
@@ -128,11 +161,9 @@ func (d *decoder) processSOS(n int) error {
var (
// b is the decoded coefficients, in natural (not zig-zag) order.
b block
- dc [nColorComponent]int32
- // bx and by are the location of the current (in terms of 8x8 blocks).
- // For example, with 4:2:0 chroma subsampling, the block whose top left
- // pixel co-ordinates are (16, 8) is the third block in the first row:
- // bx is 2 and by is 0, even though the pixel is in the second MCU.
+ dc [maxComponents]int32
+ // bx and by are the location of the current block, in units of 8x8
+ // blocks: the third block in the first row has (bx, by) = (2, 0).
bx, by int
blockCount int
)
@@ -140,8 +171,10 @@ func (d *decoder) processSOS(n int) error {
for mx := 0; mx < mxx; mx++ {
for i := 0; i < nComp; i++ {
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 < d.comp[compIndex].h*d.comp[compIndex].v; j++ {
+ 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.
//
@@ -168,15 +201,10 @@ func (d *decoder) processSOS(n int) error {
// 0 1 2
// 3 4 5
if nComp != 1 {
- bx, by = d.comp[compIndex].h*mx, d.comp[compIndex].v*my
- if h0 == 1 {
- by += j
- } else {
- bx += j % 2
- by += j / 2
- }
+ bx = hi*mx + j%hi
+ by = vi*my + j/hi
} else {
- q := mxx * d.comp[compIndex].h
+ q := mxx * hi
bx = blockCount % q
by = blockCount / q
blockCount++
@@ -187,7 +215,7 @@ func (d *decoder) processSOS(n int) error {
// Load the previous partially decoded coefficients, if applicable.
if d.progressive {
- b = d.progCoeffs[compIndex][by*mxx*d.comp[compIndex].h+bx]
+ b = d.progCoeffs[compIndex][by*mxx*hi+bx]
} else {
b = block{}
}
@@ -260,7 +288,7 @@ 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*d.comp[compIndex].h+bx] = b
+ 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,
@@ -276,7 +304,7 @@ func (d *decoder) processSOS(n int) error {
}
idct(&b)
dst, stride := []byte(nil), 0
- if d.nComp == nGrayComponent {
+ if d.nComp == 1 {
dst, stride = d.img1.Pix[8*(by*d.img1.Stride+bx):], d.img1.Stride
} else {
switch compIndex {
@@ -286,6 +314,8 @@ func (d *decoder) processSOS(n int) error {
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")
}
@@ -325,7 +355,7 @@ func (d *decoder) processSOS(n int) error {
// Reset the Huffman decoder.
d.bits = bits{}
// Reset the DC components, as per section F.2.1.3.1.
- dc = [nColorComponent]int32{}
+ dc = [maxComponents]int32{}
// Reset the progressive decoder state, as per section G.1.2.2.
d.eobRun = 0
}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/png/reader.go b/llgo/third_party/gofrontend/libgo/go/image/png/reader.go
index 0a40ca161d9..bbd6f753fad 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/png/reader.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/png/reader.go
@@ -47,6 +47,10 @@ const (
cbTCA16
)
+func cbPaletted(cb int) bool {
+ return cbP1 <= cb && cb <= cbP8
+}
+
// Filter type, as per the PNG spec.
const (
ftNone = 0
@@ -81,15 +85,16 @@ var interlacing = []interlaceScan{
}
// Decoding stage.
-// The PNG specification says that the IHDR, PLTE (if present), IDAT and IEND
-// chunks must appear in that order. There may be multiple IDAT chunks, and
-// IDAT chunks must be sequential (i.e. they may not have any other chunks
-// between them).
+// The PNG specification says that the IHDR, PLTE (if present), tRNS (if
+// present), IDAT and IEND chunks must appear in that order. There may be
+// multiple IDAT chunks, and IDAT chunks must be sequential (i.e. they may not
+// have any other chunks between them).
// http://www.w3.org/TR/PNG/#5ChunkOrdering
const (
dsStart = iota
dsSeenIHDR
dsSeenPLTE
+ dsSeentRNS
dsSeenIDAT
dsSeenIEND
)
@@ -321,15 +326,23 @@ func (d *decoder) decode() (image.Image, error) {
var img image.Image
if d.interlace == itNone {
img, err = d.readImagePass(r, 0, false)
+ if err != nil {
+ return nil, err
+ }
} else if d.interlace == itAdam7 {
// Allocate a blank image of the full size.
img, err = d.readImagePass(nil, 0, true)
+ if err != nil {
+ return nil, err
+ }
for pass := 0; pass < 7; pass++ {
imagePass, err := d.readImagePass(r, pass, false)
if err != nil {
return nil, err
}
- d.mergePassInto(img, imagePass, pass)
+ if imagePass != nil {
+ d.mergePassInto(img, imagePass, pass)
+ }
}
}
@@ -371,6 +384,12 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
// Add the multiplication factor and subtract one, effectively rounding up.
width = (width - p.xOffset + p.xFactor - 1) / p.xFactor
height = (height - p.yOffset + p.yFactor - 1) / p.yFactor
+ // A PNG image can't have zero width or height, but for an interlaced
+ // image, an individual pass might have zero width or height. If so, we
+ // shouldn't even read a per-row filter type byte, so return early.
+ if width == 0 || height == 0 {
+ return nil, nil
+ }
}
switch d.cb {
case cbG1, cbG2, cbG4, cbG8:
@@ -425,6 +444,9 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
// Read the decompressed bytes.
_, err := io.ReadFull(r, cr)
if err != nil {
+ if err == io.EOF || err == io.ErrUnexpectedEOF {
+ return nil, FormatError("not enough pixel data")
+ }
return nil, err
}
@@ -443,6 +465,9 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
cdat[i] += p
}
case ftAverage:
+ // The first column has no column to the left of it, so it is a
+ // special case. We know that the first column exists because we
+ // check above that width != 0, and so len(cdat) != 0.
for i := 0; i < bytesPerPixel; i++ {
cdat[i] += pdat[i] / 2
}
@@ -687,9 +712,10 @@ func (d *decoder) parseChunk() error {
if d.stage != dsSeenPLTE {
return chunkOrderError
}
+ d.stage = dsSeentRNS
return d.parsetRNS(length)
case "IDAT":
- if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) {
+ if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.stage == dsSeenIHDR && cbPaletted(d.cb)) {
return chunkOrderError
}
d.stage = dsSeenIDAT
@@ -779,7 +805,7 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
}
return image.Config{}, err
}
- paletted := d.cb == cbP8 || d.cb == cbP4 || d.cb == cbP2 || d.cb == cbP1
+ paletted := cbPaletted(d.cb)
if d.stage == dsSeenIHDR && !paletted {
break
}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/png/reader_test.go b/llgo/third_party/gofrontend/libgo/go/image/png/reader_test.go
index ce772eb6f09..f89e7efe7fe 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/png/reader_test.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/png/reader_test.go
@@ -6,12 +6,14 @@ package png
import (
"bufio"
+ "bytes"
"fmt"
"image"
"image/color"
"io"
"io/ioutil"
"os"
+ "reflect"
"strings"
"testing"
)
@@ -319,6 +321,93 @@ func TestPalettedDecodeConfig(t *testing.T) {
}
}
+func TestInterlaced(t *testing.T) {
+ a, err := readPNG("testdata/gray-gradient.png")
+ if err != nil {
+ t.Fatal(err)
+ }
+ b, err := readPNG("testdata/gray-gradient.interlaced.png")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(a, b) {
+ t.Fatalf("decodings differ:\nnon-interlaced:\n%#v\ninterlaced:\n%#v", a, b)
+ }
+}
+
+func TestIncompleteIDATOnRowBoundary(t *testing.T) {
+ // The following is an invalid 1x2 grayscale PNG image. The header is OK,
+ // but the zlib-compressed IDAT payload contains two bytes "\x02\x00",
+ // which is only one row of data (the leading "\x02" is a row filter).
+ const (
+ ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x02\x08\x00\x00\x00\x00\xbc\xea\xe9\xfb"
+ idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
+ iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
+ )
+ _, err := Decode(strings.NewReader(pngHeader + ihdr + idat + iend))
+ if err == nil {
+ t.Fatal("got nil error, want non-nil")
+ }
+}
+
+func TestMultipletRNSChunks(t *testing.T) {
+ /*
+ The following is a valid 1x1 paletted PNG image with a 1-element palette
+ containing color.NRGBA{0xff, 0x00, 0x00, 0x7f}:
+ 0000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR
+ 0000010: 0000 0001 0000 0001 0803 0000 0028 cb34 .............(.4
+ 0000020: bb00 0000 0350 4c54 45ff 0000 19e2 0937 .....PLTE......7
+ 0000030: 0000 0001 7452 4e53 7f80 5cb4 cb00 0000 ....tRNS..\.....
+ 0000040: 0e49 4441 5478 9c62 6200 0400 00ff ff00 .IDATx.bb.......
+ 0000050: 0600 03fa d059 ae00 0000 0049 454e 44ae .....Y.....IEND.
+ 0000060: 4260 82 B`.
+ Dropping the tRNS chunk makes that color's alpha 0xff instead of 0x7f.
+ */
+ const (
+ ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x03\x00\x00\x00\x28\xcb\x34\xbb"
+ plte = "\x00\x00\x00\x03PLTE\xff\x00\x00\x19\xe2\x09\x37"
+ trns = "\x00\x00\x00\x01tRNS\x7f\x80\x5c\xb4\xcb"
+ idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
+ iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
+ )
+ for i := 0; i < 4; i++ {
+ var b []byte
+ b = append(b, pngHeader...)
+ b = append(b, ihdr...)
+ b = append(b, plte...)
+ for j := 0; j < i; j++ {
+ b = append(b, trns...)
+ }
+ b = append(b, idat...)
+ b = append(b, iend...)
+
+ var want color.Color
+ m, err := Decode(bytes.NewReader(b))
+ switch i {
+ case 0:
+ if err != nil {
+ t.Errorf("%d tRNS chunks: %v", i, err)
+ continue
+ }
+ want = color.RGBA{0xff, 0x00, 0x00, 0xff}
+ case 1:
+ if err != nil {
+ t.Errorf("%d tRNS chunks: %v", i, err)
+ continue
+ }
+ want = color.NRGBA{0xff, 0x00, 0x00, 0x7f}
+ default:
+ if err == nil {
+ t.Errorf("%d tRNS chunks: got nil error, want non-nil", i)
+ }
+ continue
+ }
+ if got := m.At(0, 0); got != want {
+ t.Errorf("%d tRNS chunks: got %T %v, want %T %v", i, got, got, want, want)
+ }
+ }
+}
+
func benchmarkDecode(b *testing.B, filename string, bytesPerPixel int) {
b.StopTimer()
data, err := ioutil.ReadFile(filename)
diff --git a/llgo/third_party/gofrontend/libgo/go/image/png/testdata/benchRGB-interlace.png b/llgo/third_party/gofrontend/libgo/go/image/png/testdata/benchRGB-interlace.png
new file mode 100644
index 00000000000..b4b5daba3c6
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/png/testdata/benchRGB-interlace.png
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/png/testdata/gray-gradient.interlaced.png b/llgo/third_party/gofrontend/libgo/go/image/png/testdata/gray-gradient.interlaced.png
new file mode 100644
index 00000000000..01f657ae86d
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/png/testdata/gray-gradient.interlaced.png
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/png/testdata/gray-gradient.png b/llgo/third_party/gofrontend/libgo/go/image/png/testdata/gray-gradient.png
new file mode 100644
index 00000000000..6de1cd36f4a
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/png/testdata/gray-gradient.png
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.png b/llgo/third_party/gofrontend/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.png
new file mode 100644
index 00000000000..540137cb556
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.png
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.sng b/llgo/third_party/gofrontend/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.sng
new file mode 100644
index 00000000000..31b87c72d12
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.sng
@@ -0,0 +1,57 @@
+#SNG: from basn3p04-31i.png
+IHDR {
+ width: 31; height: 31; bitdepth: 4;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ ( 34, 0,255) # rgb = (0x22,0x00,0xff)
+ ( 0,255,255) # rgb = (0x00,0xff,0xff)
+ (136, 0,255) # rgb = (0x88,0x00,0xff)
+ ( 34,255, 0) # rgb = (0x22,0xff,0x00)
+ ( 0,153,255) # rgb = (0x00,0x99,0xff)
+ (255,102, 0) # rgb = (0xff,0x66,0x00)
+ (221, 0,255) # rgb = (0xdd,0x00,0xff)
+ (119,255, 0) # rgb = (0x77,0xff,0x00)
+ (255, 0, 0) # rgb = (0xff,0x00,0x00)
+ ( 0,255,153) # rgb = (0x00,0xff,0x99)
+ (221,255, 0) # rgb = (0xdd,0xff,0x00)
+ (255, 0,187) # rgb = (0xff,0x00,0xbb)
+ (255,187, 0) # rgb = (0xff,0xbb,0x00)
+ ( 0, 68,255) # rgb = (0x00,0x44,0xff)
+ ( 0,255, 68) # rgb = (0x00,0xff,0x44)
+}
+IMAGE {
+ pixels hex
+88885555ccccaaaa77773333eeee9990
+88885555ccccaaaa77773333eeee9990
+88885555ccccaaaa77773333eeee9990
+88885555ccccaaaa77773333eeee9990
+5555ccccaaaa77773333eeee99991110
+5555ccccaaaa77773333eeee99991110
+5555ccccaaaa77773333eeee99991110
+5555ccccaaaa77773333eeee99991110
+ccccaaaa77773333eeee999911114440
+ccccaaaa77773333eeee999911114440
+ccccaaaa77773333eeee999911114440
+ccccaaaa77773333eeee999911114440
+aaaa77773333eeee999911114444ddd0
+aaaa77773333eeee999911114444ddd0
+aaaa77773333eeee999911114444ddd0
+aaaa77773333eeee999911114444ddd0
+77773333eeee999911114444dddd0000
+77773333eeee999911114444dddd0000
+77773333eeee999911114444dddd0000
+77773333eeee999911114444dddd0000
+3333eeee999911114444dddd00002220
+3333eeee999911114444dddd00002220
+3333eeee999911114444dddd00002220
+3333eeee999911114444dddd00002220
+eeee999911114444dddd000022226660
+eeee999911114444dddd000022226660
+eeee999911114444dddd000022226660
+eeee999911114444dddd000022226660
+999911114444dddd000022226666bbb0
+999911114444dddd000022226666bbb0
+999911114444dddd000022226666bbb0
+}
diff --git a/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.221212.jpeg b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.221212.jpeg
new file mode 100644
index 00000000000..f069c76af9c
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.221212.jpeg
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.221212.png b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.221212.png
new file mode 100644
index 00000000000..d619a6286bc
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.221212.png
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.cmyk.jpeg b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.cmyk.jpeg
new file mode 100644
index 00000000000..507df843b5a
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.cmyk.jpeg
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.cmyk.png b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.cmyk.png
new file mode 100644
index 00000000000..ef7b2b88d87
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.cmyk.png
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.410.jpeg b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.410.jpeg
new file mode 100644
index 00000000000..4cebd1eb25c
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.410.jpeg
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.410.progressive.jpeg b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.410.progressive.jpeg
new file mode 100644
index 00000000000..fb7140217e2
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.410.progressive.jpeg
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.411.jpeg b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.411.jpeg
new file mode 100644
index 00000000000..b90de18721d
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.411.jpeg
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.411.progressive.jpeg b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.411.progressive.jpeg
new file mode 100644
index 00000000000..1ddb22b8b0e
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.q50.411.progressive.jpeg
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.rgb.jpeg b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.rgb.jpeg
new file mode 100644
index 00000000000..fc2ce3ca91f
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.rgb.jpeg
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.rgb.png b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.rgb.png
new file mode 100644
index 00000000000..edb716d3415
--- /dev/null
+++ b/llgo/third_party/gofrontend/libgo/go/image/testdata/video-001.rgb.png
Binary files differ
diff --git a/llgo/third_party/gofrontend/libgo/go/image/ycbcr.go b/llgo/third_party/gofrontend/libgo/go/image/ycbcr.go
index 7c773f2f0a4..93c354b33b4 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/ycbcr.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/ycbcr.go
@@ -16,6 +16,8 @@ const (
YCbCrSubsampleRatio422
YCbCrSubsampleRatio420
YCbCrSubsampleRatio440
+ YCbCrSubsampleRatio411
+ YCbCrSubsampleRatio410
)
func (s YCbCrSubsampleRatio) String() string {
@@ -28,6 +30,10 @@ func (s YCbCrSubsampleRatio) String() string {
return "YCbCrSubsampleRatio420"
case YCbCrSubsampleRatio440:
return "YCbCrSubsampleRatio440"
+ case YCbCrSubsampleRatio411:
+ return "YCbCrSubsampleRatio411"
+ case YCbCrSubsampleRatio410:
+ return "YCbCrSubsampleRatio410"
}
return "YCbCrSubsampleRatioUnknown"
}
@@ -43,6 +49,8 @@ func (s YCbCrSubsampleRatio) String() string {
// For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
// For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
// For 4:4:0, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/2.
+// For 4:1:1, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/4.
+// For 4:1:0, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/8.
type YCbCr struct {
Y, Cb, Cr []uint8
YStride int
@@ -92,6 +100,10 @@ func (p *YCbCr) COffset(x, y int) int {
return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/2 - p.Rect.Min.X/2)
case YCbCrSubsampleRatio440:
return (y/2-p.Rect.Min.Y/2)*p.CStride + (x - p.Rect.Min.X)
+ case YCbCrSubsampleRatio411:
+ return (y-p.Rect.Min.Y)*p.CStride + (x/4 - p.Rect.Min.X/4)
+ case YCbCrSubsampleRatio410:
+ return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/4 - p.Rect.Min.X/4)
}
// Default to 4:4:4 subsampling.
return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X)
@@ -139,16 +151,25 @@ func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
case YCbCrSubsampleRatio440:
cw = w
ch = (r.Max.Y+1)/2 - r.Min.Y/2
+ case YCbCrSubsampleRatio411:
+ cw = (r.Max.X+3)/4 - r.Min.X/4
+ ch = h
+ case YCbCrSubsampleRatio410:
+ cw = (r.Max.X+3)/4 - r.Min.X/4
+ ch = (r.Max.Y+1)/2 - r.Min.Y/2
default:
// Default to 4:4:4 subsampling.
cw = w
ch = h
}
- b := make([]byte, w*h+2*cw*ch)
+ i0 := w*h + 0*cw*ch
+ i1 := w*h + 1*cw*ch
+ i2 := w*h + 2*cw*ch
+ b := make([]byte, i2)
return &YCbCr{
- Y: b[:w*h],
- Cb: b[w*h+0*cw*ch : w*h+1*cw*ch],
- Cr: b[w*h+1*cw*ch : w*h+2*cw*ch],
+ Y: b[:i0:i0],
+ Cb: b[i0:i1:i1],
+ Cr: b[i1:i2:i2],
SubsampleRatio: subsampleRatio,
YStride: w,
CStride: cw,
diff --git a/llgo/third_party/gofrontend/libgo/go/image/ycbcr_test.go b/llgo/third_party/gofrontend/libgo/go/image/ycbcr_test.go
index a5f4482654f..4996bc8dcae 100644
--- a/llgo/third_party/gofrontend/libgo/go/image/ycbcr_test.go
+++ b/llgo/third_party/gofrontend/libgo/go/image/ycbcr_test.go
@@ -37,6 +37,8 @@ func TestYCbCr(t *testing.T) {
YCbCrSubsampleRatio422,
YCbCrSubsampleRatio420,
YCbCrSubsampleRatio440,
+ YCbCrSubsampleRatio411,
+ YCbCrSubsampleRatio410,
}
deltas := []Point{
Pt(0, 0),
@@ -105,3 +107,27 @@ func testYCbCr(t *testing.T, r Rectangle, subsampleRatio YCbCrSubsampleRatio, de
}
}
}
+
+func TestYCbCrSlicesDontOverlap(t *testing.T) {
+ m := NewYCbCr(Rect(0, 0, 8, 8), YCbCrSubsampleRatio420)
+ names := []string{"Y", "Cb", "Cr"}
+ slices := [][]byte{
+ m.Y[:cap(m.Y)],
+ m.Cb[:cap(m.Cb)],
+ m.Cr[:cap(m.Cr)],
+ }
+ for i, slice := range slices {
+ want := uint8(10 + i)
+ for j := range slice {
+ slice[j] = want
+ }
+ }
+ for i, slice := range slices {
+ want := uint8(10 + i)
+ for j, got := range slice {
+ if got != want {
+ t.Fatalf("m.%s[%d]: got %d, want %d", names[i], j, got, want)
+ }
+ }
+ }
+}
OpenPOWER on IntegriCloud