diff options
author | kawakami <kawakami.ozone@gmail.com> | 2019-05-16 03:11:44 +0900 |
---|---|---|
committer | Benny Siegert <bsiegert@gmail.com> | 2019-05-22 20:41:27 +0000 |
commit | 983986f23d81eae6ee202bd31383d04e73187536 (patch) | |
tree | e97b18c39102f28325171efe149e4f7245dc4a00 /src/image | |
parent | 94a9dad8fdcd7adf2036482391f715ea3ab35cd9 (diff) | |
download | go-983986f23d81eae6ee202bd31383d04e73187536.tar.gz go-983986f23d81eae6ee202bd31383d04e73187536.zip |
image/gif: fix transparency loss when encoding a wrapped *image.Paletted
This keeps transparency of a wrapped image.Image even after it is encoded.
Fixes #30995
Change-Id: I1f7ac98b1741f83ed740f6eda6c36b7e9b16e5af
Reviewed-on: https://go-review.googlesource.com/c/go/+/177377
Reviewed-by: Hayato Kawakami <kawakami.ozone@gmail.com>
Reviewed-by: Benny Siegert <bsiegert@gmail.com>
Run-TryBot: Benny Siegert <bsiegert@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/image')
-rw-r--r-- | src/image/gif/writer.go | 14 | ||||
-rw-r--r-- | src/image/gif/writer_test.go | 81 | ||||
-rw-r--r-- | src/image/testdata/triangle-001.gif | bin | 0 -> 1476 bytes |
3 files changed, 90 insertions, 5 deletions
diff --git a/src/image/gif/writer.go b/src/image/gif/writer.go index 5819df0dd0..7220446de5 100644 --- a/src/image/gif/writer.go +++ b/src/image/gif/writer.go @@ -433,8 +433,18 @@ func Encode(w io.Writer, m image.Image, o *Options) error { opts.Drawer = draw.FloydSteinberg } - pm, ok := m.(*image.Paletted) - if !ok || len(pm.Palette) > opts.NumColors { + pm, _ := m.(*image.Paletted) + if pm == nil { + if cp, ok := m.ColorModel().(color.Palette); ok { + pm = image.NewPaletted(b, cp) + for y := b.Min.Y; y < b.Max.Y; y++ { + for x := b.Min.X; x < b.Max.X; x++ { + pm.Set(x, y, cp.Convert(m.At(x, y))) + } + } + } + } + if pm == nil || len(pm.Palette) > opts.NumColors { // Set pm to be a palettedized copy of m, including its bounds, which // might not start at (0, 0). // diff --git a/src/image/gif/writer_test.go b/src/image/gif/writer_test.go index 91275bb907..0bc24d1bee 100644 --- a/src/image/gif/writer_test.go +++ b/src/image/gif/writer_test.go @@ -48,11 +48,17 @@ func delta(u0, u1 uint32) int64 { // have the same bounds. func averageDelta(m0, m1 image.Image) int64 { b := m0.Bounds() + return averageDeltaBound(m0, m1, b, b) +} + +// averageDeltaBounds returns the average delta in RGB space. The average delta is +// calulated in the specified bounds. +func averageDeltaBound(m0, m1 image.Image, b0, b1 image.Rectangle) int64 { var sum, n int64 - for y := b.Min.Y; y < b.Max.Y; y++ { - for x := b.Min.X; x < b.Max.X; x++ { + for y := b0.Min.Y; y < b0.Max.Y; y++ { + for x := b0.Min.X; x < b0.Max.X; x++ { c0 := m0.At(x, y) - c1 := m1.At(x, y) + c1 := m1.At(x-b0.Min.X+b1.Min.X, y-b0.Min.Y+b1.Min.Y) r0, g0, b0, _ := c0.RGBA() r1, g1, b1, _ := c1.RGBA() sum += delta(r0, r1) @@ -581,6 +587,75 @@ func TestEncodeCroppedSubImages(t *testing.T) { } } +type offsetImage struct { + image.Image + Rect image.Rectangle +} + +func (i offsetImage) Bounds() image.Rectangle { + return i.Rect +} + +func TestEncodeWrappedImage(t *testing.T) { + m0, err := readImg("../testdata/video-001.gif") + if err != nil { + t.Fatalf("readImg: %v", err) + } + + // Case 1: Enocde a wrapped image.Image + buf := new(bytes.Buffer) + w0 := offsetImage{m0, m0.Bounds()} + err = Encode(buf, w0, nil) + if err != nil { + t.Fatalf("Encode: %v", err) + } + w1, err := Decode(buf) + if err != nil { + t.Fatalf("Dencode: %v", err) + } + avgDelta := averageDelta(m0, w1) + if avgDelta > 0 { + t.Fatalf("Wrapped: average delta is too high. expected: 0, got %d", avgDelta) + } + + // Case 2: Enocde a wrapped image.Image with offset + b0 := image.Rectangle{ + Min: image.Point{ + X: 128, + Y: 64, + }, + Max: image.Point{ + X: 256, + Y: 128, + }, + } + w0 = offsetImage{m0, b0} + buf = new(bytes.Buffer) + err = Encode(buf, w0, nil) + if err != nil { + t.Fatalf("Encode: %v", err) + } + w1, err = Decode(buf) + if err != nil { + t.Fatalf("Dencode: %v", err) + } + + b1 := image.Rectangle{ + Min: image.Point{ + X: 0, + Y: 0, + }, + Max: image.Point{ + X: 128, + Y: 64, + }, + } + avgDelta = averageDeltaBound(m0, w1, b0, b1) + if avgDelta > 0 { + t.Fatalf("Wrapped and offset: average delta is too high. expected: 0, got %d", avgDelta) + } +} + func BenchmarkEncode(b *testing.B) { bo := image.Rect(0, 0, 640, 480) rnd := rand.New(rand.NewSource(123)) diff --git a/src/image/testdata/triangle-001.gif b/src/image/testdata/triangle-001.gif Binary files differnew file mode 100644 index 0000000000..f3d45bbfa4 --- /dev/null +++ b/src/image/testdata/triangle-001.gif |