// 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)) } } }