111 lines
2.6 KiB
Go
111 lines
2.6 KiB
Go
|
// Copyright 2014 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 webp
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"image"
|
||
|
"image/png"
|
||
|
"os"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
// hex is like fmt.Sprintf("% x", x) but also inserts dots every 16 bytes, to
|
||
|
// delineate VP8 macroblock boundaries.
|
||
|
func hex(x []byte) string {
|
||
|
buf := new(bytes.Buffer)
|
||
|
for len(x) > 0 {
|
||
|
n := len(x)
|
||
|
if n > 16 {
|
||
|
n = 16
|
||
|
}
|
||
|
fmt.Fprintf(buf, " . % x", x[:n])
|
||
|
x = x[n:]
|
||
|
}
|
||
|
return buf.String()
|
||
|
}
|
||
|
|
||
|
func TestDecodeVP8(t *testing.T) {
|
||
|
// The original video-001.png image is 150x103.
|
||
|
const w, h = 150, 103
|
||
|
// w2 and h2 are the half-width and half-height, rounded up.
|
||
|
const w2, h2 = int((w + 1) / 2), int((h + 1) / 2)
|
||
|
|
||
|
f0, err := os.Open("../testdata/video-001.webp.ycbcr.png")
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
defer f0.Close()
|
||
|
img0, err := png.Decode(f0)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
// The split-into-YCbCr-planes golden image is a 2*w2 wide and h+h2 high
|
||
|
// gray image arranged in IMC4 format:
|
||
|
// YYYY
|
||
|
// YYYY
|
||
|
// BBRR
|
||
|
// See http://www.fourcc.org/yuv.php#IMC4
|
||
|
if got, want := img0.Bounds(), image.Rect(0, 0, 2*w2, h+h2); got != want {
|
||
|
t.Fatalf("bounds0: got %v, want %v", got, want)
|
||
|
}
|
||
|
m0, ok := img0.(*image.Gray)
|
||
|
if !ok {
|
||
|
t.Fatal("decoded PNG image is not a Gray")
|
||
|
}
|
||
|
|
||
|
f1, err := os.Open("../testdata/video-001.webp")
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
defer f1.Close()
|
||
|
img1, err := Decode(f1)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
if got, want := img1.Bounds(), image.Rect(0, 0, w, h); got != want {
|
||
|
t.Fatalf("bounds1: got %v, want %v", got, want)
|
||
|
}
|
||
|
m1, ok := img1.(*image.YCbCr)
|
||
|
if !ok || m1.SubsampleRatio != image.YCbCrSubsampleRatio420 {
|
||
|
t.Fatal("decoded WEBP image is not a 4:2:0 YCbCr")
|
||
|
}
|
||
|
|
||
|
planes := []struct {
|
||
|
name string
|
||
|
m1Pix []uint8
|
||
|
m1Stride int
|
||
|
m0Rect image.Rectangle
|
||
|
}{
|
||
|
{"Y", m1.Y, m1.YStride, image.Rect(0, 0, w, h)},
|
||
|
{"Cb", m1.Cb, m1.CStride, image.Rect(0*w2, h, 1*w2, h+h2)},
|
||
|
{"Cr", m1.Cr, m1.CStride, image.Rect(1*w2, h, 2*w2, h+h2)},
|
||
|
}
|
||
|
for _, plane := range planes {
|
||
|
dx := plane.m0Rect.Dx()
|
||
|
nDiff, diff := 0, make([]byte, dx)
|
||
|
for j, y := 0, plane.m0Rect.Min.Y; y < plane.m0Rect.Max.Y; j, y = j+1, y+1 {
|
||
|
got := plane.m1Pix[j*plane.m1Stride:][:dx]
|
||
|
want := m0.Pix[y*m0.Stride+plane.m0Rect.Min.X:][:dx]
|
||
|
if bytes.Equal(got, want) {
|
||
|
continue
|
||
|
}
|
||
|
nDiff++
|
||
|
if nDiff > 10 {
|
||
|
t.Errorf("%s plane: more rows differ", plane.name)
|
||
|
break
|
||
|
}
|
||
|
for i := range got {
|
||
|
diff[i] = got[i] - want[i]
|
||
|
}
|
||
|
t.Errorf("%s plane: m0 row %d, m1 row %d\ngot %s\nwant%s\ndiff%s",
|
||
|
plane.name, y, j, hex(got), hex(want), hex(diff))
|
||
|
}
|
||
|
}
|
||
|
}
|