github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/image/cmd/webp-manual-test/main.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build ignore 6 // 7 // This build tag means that "go install golang.org/x/image/..." doesn't 8 // install this manual test. Use "go run main.go" to explicitly run it. 9 10 // Program webp-manual-test checks that the Go WEBP library's decodings match 11 // the C WEBP library's. 12 package main // import "golang.org/x/image/cmd/webp-manual-test" 13 14 import ( 15 "bytes" 16 "encoding/hex" 17 "flag" 18 "fmt" 19 "image" 20 "io" 21 "log" 22 "os" 23 "os/exec" 24 "path/filepath" 25 "sort" 26 "strings" 27 28 "golang.org/x/image/webp" 29 "golang.org/x/image/webp/nycbcra" 30 ) 31 32 var ( 33 dwebp = flag.String("dwebp", "/usr/bin/dwebp", "path to the dwebp program "+ 34 "installed from https://developers.google.com/speed/webp/download") 35 testdata = flag.String("testdata", "", "path to the libwebp-test-data directory "+ 36 "checked out from https://chromium.googlesource.com/webm/libwebp-test-data") 37 ) 38 39 func main() { 40 flag.Parse() 41 if *dwebp == "" { 42 flag.Usage() 43 log.Fatal("dwebp flag was not specified") 44 } 45 if _, err := os.Stat(*dwebp); err != nil { 46 flag.Usage() 47 log.Fatalf("could not find dwebp program at %q", *dwebp) 48 } 49 if *testdata == "" { 50 flag.Usage() 51 log.Fatal("testdata flag was not specified") 52 } 53 54 f, err := os.Open(*testdata) 55 if err != nil { 56 log.Fatalf("Open: %v", err) 57 } 58 defer f.Close() 59 names, err := f.Readdirnames(-1) 60 if err != nil { 61 log.Fatalf("Readdirnames: %v", err) 62 } 63 sort.Strings(names) 64 65 nFail, nPass := 0, 0 66 for _, name := range names { 67 if !strings.HasSuffix(name, "webp") { 68 continue 69 } 70 if err := test(name); err != nil { 71 fmt.Printf("FAIL\t%s\t%v\n", name, err) 72 nFail++ 73 } else { 74 fmt.Printf("PASS\t%s\n", name) 75 nPass++ 76 } 77 } 78 fmt.Printf("%d PASS, %d FAIL, %d TOTAL\n", nPass, nFail, nPass+nFail) 79 if nFail != 0 { 80 os.Exit(1) 81 } 82 } 83 84 // test tests a single WEBP image. 85 func test(name string) error { 86 filename := filepath.Join(*testdata, name) 87 f, err := os.Open(filename) 88 if err != nil { 89 return fmt.Errorf("Open: %v", err) 90 } 91 defer f.Close() 92 93 gotImage, err := webp.Decode(f) 94 if err != nil { 95 return fmt.Errorf("Decode: %v", err) 96 } 97 format, encode := "-pgm", encodePGM 98 if _, lossless := gotImage.(*image.NRGBA); lossless { 99 format, encode = "-pam", encodePAM 100 } 101 got, err := encode(gotImage) 102 if err != nil { 103 return fmt.Errorf("encode: %v", err) 104 } 105 106 stdout := new(bytes.Buffer) 107 stderr := new(bytes.Buffer) 108 c := exec.Command(*dwebp, filename, format, "-o", "/dev/stdout") 109 c.Stdout = stdout 110 c.Stderr = stderr 111 if err := c.Run(); err != nil { 112 os.Stderr.Write(stderr.Bytes()) 113 return fmt.Errorf("executing dwebp: %v", err) 114 } 115 want := stdout.Bytes() 116 117 if len(got) != len(want) { 118 return fmt.Errorf("encodings have different length: got %d, want %d", len(got), len(want)) 119 } 120 for i, g := range got { 121 if w := want[i]; g != w { 122 return fmt.Errorf("encodings differ at position 0x%x: got 0x%02x, want 0x%02x", i, g, w) 123 } 124 } 125 return nil 126 } 127 128 // encodePAM encodes gotImage in the PAM format. 129 func encodePAM(gotImage image.Image) ([]byte, error) { 130 m, ok := gotImage.(*image.NRGBA) 131 if !ok { 132 return nil, fmt.Errorf("lossless image did not decode to an *image.NRGBA") 133 } 134 b := m.Bounds() 135 w, h := b.Dx(), b.Dy() 136 buf := new(bytes.Buffer) 137 fmt.Fprintf(buf, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n", w, h) 138 for y := b.Min.Y; y < b.Max.Y; y++ { 139 o := m.PixOffset(b.Min.X, y) 140 buf.Write(m.Pix[o : o+4*w]) 141 } 142 return buf.Bytes(), nil 143 } 144 145 // encodePGM encodes gotImage in the PGM format in the IMC4 layout. 146 func encodePGM(gotImage image.Image) ([]byte, error) { 147 var ( 148 m *image.YCbCr 149 ma *nycbcra.Image 150 ) 151 switch g := gotImage.(type) { 152 case *image.YCbCr: 153 m = g 154 case *nycbcra.Image: 155 m = &g.YCbCr 156 ma = g 157 default: 158 return nil, fmt.Errorf("lossy image did not decode to an *image.YCbCr") 159 } 160 if m.SubsampleRatio != image.YCbCrSubsampleRatio420 { 161 return nil, fmt.Errorf("lossy image did not decode to a 4:2:0 YCbCr") 162 } 163 b := m.Bounds() 164 w, h := b.Dx(), b.Dy() 165 w2, h2 := (w+1)/2, (h+1)/2 166 outW, outH := 2*w2, h+h2 167 if ma != nil { 168 outH += h 169 } 170 buf := new(bytes.Buffer) 171 fmt.Fprintf(buf, "P5\n%d %d\n255\n", outW, outH) 172 for y := b.Min.Y; y < b.Max.Y; y++ { 173 o := m.YOffset(b.Min.X, y) 174 buf.Write(m.Y[o : o+w]) 175 if w&1 != 0 { 176 buf.WriteByte(0x00) 177 } 178 } 179 for y := b.Min.Y; y < b.Max.Y; y += 2 { 180 o := m.COffset(b.Min.X, y) 181 buf.Write(m.Cb[o : o+w2]) 182 buf.Write(m.Cr[o : o+w2]) 183 } 184 if ma != nil { 185 for y := b.Min.Y; y < b.Max.Y; y++ { 186 o := ma.AOffset(b.Min.X, y) 187 buf.Write(ma.A[o : o+w]) 188 if w&1 != 0 { 189 buf.WriteByte(0x00) 190 } 191 } 192 } 193 return buf.Bytes(), nil 194 } 195 196 // dump can be useful for debugging. 197 func dump(w io.Writer, b []byte) { 198 h := hex.Dumper(w) 199 h.Write(b) 200 h.Close() 201 }