Commit 983986f2 authored by kawakami's avatar kawakami Committed by Benny Siegert

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/+/177377Reviewed-by: 's avatarHayato Kawakami <kawakami.ozone@gmail.com>
Reviewed-by: 's avatarBenny Siegert <bsiegert@gmail.com>
Run-TryBot: Benny Siegert <bsiegert@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 94a9dad8
......@@ -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).
//
......
......@@ -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))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment