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  }