OLD | NEW |
1 // Program webp-manual-test checks that the Go WEBP library's decodings match | 1 // Program webp-manual-test checks that the Go WEBP library's decodings match |
2 // the C WEBP library's. | 2 // the C WEBP library's. |
3 package main | 3 package main |
4 | 4 |
5 import ( | 5 import ( |
6 "bytes" | 6 "bytes" |
7 "encoding/hex" | 7 "encoding/hex" |
8 "flag" | 8 "flag" |
9 "fmt" | 9 "fmt" |
10 "image" | 10 "image" |
11 "io" | 11 "io" |
12 "log" | 12 "log" |
13 "os" | 13 "os" |
14 "os/exec" | 14 "os/exec" |
15 "path/filepath" | 15 "path/filepath" |
16 "sort" | 16 "sort" |
17 "strings" | 17 "strings" |
18 | 18 |
19 "code.google.com/p/go.image/webp" | 19 "code.google.com/p/go.image/webp" |
| 20 "code.google.com/p/go.image/webp/nycbcra" |
20 ) | 21 ) |
21 | 22 |
22 var ( | 23 var ( |
23 » dwebp = flag.String("dwebp", "", "path to the dwebp program "+ | 24 » dwebp = flag.String("dwebp", "/usr/bin/dwebp", "path to the dwebp progra
m "+ |
24 "installed from https://developers.google.com/speed/webp/downloa
d") | 25 "installed from https://developers.google.com/speed/webp/downloa
d") |
25 testdata = flag.String("testdata", "", "path to the libwebp-test-data di
rectory "+ | 26 testdata = flag.String("testdata", "", "path to the libwebp-test-data di
rectory "+ |
26 "checked out from https://chromium.googlesource.com/webm/libwebp
-test-data") | 27 "checked out from https://chromium.googlesource.com/webm/libwebp
-test-data") |
27 ) | 28 ) |
28 | 29 |
29 func main() { | 30 func main() { |
30 flag.Parse() | 31 flag.Parse() |
31 if *dwebp == "" { | 32 if *dwebp == "" { |
32 flag.Usage() | 33 flag.Usage() |
33 log.Fatal("dwebp flag was not specified") | 34 log.Fatal("dwebp flag was not specified") |
34 } | 35 } |
| 36 if _, err := os.Stat(*dwebp); err != nil { |
| 37 flag.Usage() |
| 38 log.Fatalf("could not find dwebp program at %q", *dwebp) |
| 39 } |
35 if *testdata == "" { | 40 if *testdata == "" { |
36 flag.Usage() | 41 flag.Usage() |
37 log.Fatal("testdata flag was not specified") | 42 log.Fatal("testdata flag was not specified") |
38 } | 43 } |
39 | 44 |
40 f, err := os.Open(*testdata) | 45 f, err := os.Open(*testdata) |
41 if err != nil { | 46 if err != nil { |
42 log.Fatalf("Open: %v", err) | 47 log.Fatalf("Open: %v", err) |
43 } | 48 } |
44 defer f.Close() | 49 defer f.Close() |
(...skipping 28 matching lines...) Expand all Loading... |
73 f, err := os.Open(filename) | 78 f, err := os.Open(filename) |
74 if err != nil { | 79 if err != nil { |
75 return fmt.Errorf("Open: %v", err) | 80 return fmt.Errorf("Open: %v", err) |
76 } | 81 } |
77 defer f.Close() | 82 defer f.Close() |
78 | 83 |
79 gotImage, err := webp.Decode(f) | 84 gotImage, err := webp.Decode(f) |
80 if err != nil { | 85 if err != nil { |
81 return fmt.Errorf("Decode: %v", err) | 86 return fmt.Errorf("Decode: %v", err) |
82 } | 87 } |
83 » format, encode := "-pam", encodePAM | 88 » format, encode := "-pgm", encodePGM |
84 » if _, lossy := gotImage.(*image.YCbCr); lossy { | 89 » if _, lossless := gotImage.(*image.NRGBA); lossless { |
85 » » format, encode = "-pgm", encodePGM | 90 » » format, encode = "-pam", encodePAM |
86 } | 91 } |
87 got, err := encode(gotImage) | 92 got, err := encode(gotImage) |
88 if err != nil { | 93 if err != nil { |
89 return fmt.Errorf("encode: %v", err) | 94 return fmt.Errorf("encode: %v", err) |
90 } | 95 } |
91 | 96 |
92 stdout := new(bytes.Buffer) | 97 stdout := new(bytes.Buffer) |
93 stderr := new(bytes.Buffer) | 98 stderr := new(bytes.Buffer) |
94 c := exec.Command(*dwebp, filename, format, "-o", "/dev/stdout") | 99 c := exec.Command(*dwebp, filename, format, "-o", "/dev/stdout") |
95 c.Stdout = stdout | 100 c.Stdout = stdout |
(...skipping 27 matching lines...) Expand all Loading... |
123 fmt.Fprintf(buf, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\nTUPLTYPE
RGB_ALPHA\nENDHDR\n", w, h) | 128 fmt.Fprintf(buf, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\nTUPLTYPE
RGB_ALPHA\nENDHDR\n", w, h) |
124 for y := b.Min.Y; y < b.Max.Y; y++ { | 129 for y := b.Min.Y; y < b.Max.Y; y++ { |
125 o := m.PixOffset(b.Min.X, y) | 130 o := m.PixOffset(b.Min.X, y) |
126 buf.Write(m.Pix[o : o+4*w]) | 131 buf.Write(m.Pix[o : o+4*w]) |
127 } | 132 } |
128 return buf.Bytes(), nil | 133 return buf.Bytes(), nil |
129 } | 134 } |
130 | 135 |
131 // encodePGM encodes gotImage in the PGM format in the IMC4 layout. | 136 // encodePGM encodes gotImage in the PGM format in the IMC4 layout. |
132 func encodePGM(gotImage image.Image) ([]byte, error) { | 137 func encodePGM(gotImage image.Image) ([]byte, error) { |
133 » m, ok := gotImage.(*image.YCbCr) | 138 » var ( |
134 » if !ok { | 139 » » m *image.YCbCr |
| 140 » » ma *nycbcra.Image |
| 141 » ) |
| 142 » switch g := gotImage.(type) { |
| 143 » case *image.YCbCr: |
| 144 » » m = g |
| 145 » case *nycbcra.Image: |
| 146 » » m = &g.YCbCr |
| 147 » » ma = g |
| 148 » default: |
135 return nil, fmt.Errorf("lossy image did not decode to an *image.
YCbCr") | 149 return nil, fmt.Errorf("lossy image did not decode to an *image.
YCbCr") |
136 } | 150 } |
137 if m.SubsampleRatio != image.YCbCrSubsampleRatio420 { | 151 if m.SubsampleRatio != image.YCbCrSubsampleRatio420 { |
138 return nil, fmt.Errorf("lossy image did not decode to a 4:2:0 YC
bCr") | 152 return nil, fmt.Errorf("lossy image did not decode to a 4:2:0 YC
bCr") |
139 } | 153 } |
140 b := m.Bounds() | 154 b := m.Bounds() |
141 w, h := b.Dx(), b.Dy() | 155 w, h := b.Dx(), b.Dy() |
142 w2, h2 := (w+1)/2, (h+1)/2 | 156 w2, h2 := (w+1)/2, (h+1)/2 |
| 157 outW, outH := 2*w2, h+h2 |
| 158 if ma != nil { |
| 159 outH += h |
| 160 } |
143 buf := new(bytes.Buffer) | 161 buf := new(bytes.Buffer) |
144 » fmt.Fprintf(buf, "P5\n%d %d\n255\n", 2*w2, h+h2) | 162 » fmt.Fprintf(buf, "P5\n%d %d\n255\n", outW, outH) |
145 for y := b.Min.Y; y < b.Max.Y; y++ { | 163 for y := b.Min.Y; y < b.Max.Y; y++ { |
146 o := m.YOffset(b.Min.X, y) | 164 o := m.YOffset(b.Min.X, y) |
147 buf.Write(m.Y[o : o+w]) | 165 buf.Write(m.Y[o : o+w]) |
148 if w&1 != 0 { | 166 if w&1 != 0 { |
149 buf.WriteByte(0x00) | 167 buf.WriteByte(0x00) |
150 } | 168 } |
151 } | 169 } |
152 for y := b.Min.Y; y < b.Max.Y; y += 2 { | 170 for y := b.Min.Y; y < b.Max.Y; y += 2 { |
153 o := m.COffset(b.Min.X, y) | 171 o := m.COffset(b.Min.X, y) |
154 buf.Write(m.Cb[o : o+w2]) | 172 buf.Write(m.Cb[o : o+w2]) |
155 buf.Write(m.Cr[o : o+w2]) | 173 buf.Write(m.Cr[o : o+w2]) |
156 } | 174 } |
| 175 if ma != nil { |
| 176 for y := b.Min.Y; y < b.Max.Y; y++ { |
| 177 o := ma.AOffset(b.Min.X, y) |
| 178 buf.Write(ma.A[o : o+w]) |
| 179 if w&1 != 0 { |
| 180 buf.WriteByte(0x00) |
| 181 } |
| 182 } |
| 183 } |
157 return buf.Bytes(), nil | 184 return buf.Bytes(), nil |
158 } | 185 } |
159 | 186 |
160 // dump can be useful for debugging. | 187 // dump can be useful for debugging. |
161 func dump(w io.Writer, b []byte) { | 188 func dump(w io.Writer, b []byte) { |
162 h := hex.Dumper(w) | 189 h := hex.Dumper(w) |
163 h.Write(b) | 190 h.Write(b) |
164 h.Close() | 191 h.Close() |
165 } | 192 } |
OLD | NEW |