libgo: update to go1.9
[official-gcc.git] / libgo / go / image / png / reader_test.go
blobcabf533adcd68821cc1613303c0e724adaceba9e
1 // Copyright 2009 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.
5 package png
7 import (
8 "bufio"
9 "bytes"
10 "fmt"
11 "image"
12 "image/color"
13 "io"
14 "io/ioutil"
15 "os"
16 "reflect"
17 "strings"
18 "testing"
21 var filenames = []string{
22 "basn0g01",
23 "basn0g01-30",
24 "basn0g02",
25 "basn0g02-29",
26 "basn0g04",
27 "basn0g04-31",
28 "basn0g08",
29 "basn0g16",
30 "basn2c08",
31 "basn2c16",
32 "basn3p01",
33 "basn3p02",
34 "basn3p04",
35 "basn3p04-31i",
36 "basn3p08",
37 "basn3p08-trns",
38 "basn4a08",
39 "basn4a16",
40 "basn6a08",
41 "basn6a16",
42 "ftbbn0g01",
43 "ftbbn0g02",
44 "ftbbn0g04",
45 "ftbbn2c16",
46 "ftbbn3p08",
47 "ftbgn2c16",
48 "ftbgn3p08",
49 "ftbrn2c08",
50 "ftbwn0g16",
51 "ftbwn3p08",
52 "ftbyn3p08",
53 "ftp0n0g08",
54 "ftp0n2c08",
55 "ftp0n3p08",
56 "ftp1n3p08",
59 var filenamesPaletted = []string{
60 "basn3p01",
61 "basn3p02",
62 "basn3p04",
63 "basn3p08",
64 "basn3p08-trns",
67 var filenamesShort = []string{
68 "basn0g01",
69 "basn0g04-31",
70 "basn6a16",
73 func readPNG(filename string) (image.Image, error) {
74 f, err := os.Open(filename)
75 if err != nil {
76 return nil, err
78 defer f.Close()
79 return Decode(f)
82 // fakebKGDs maps from filenames to fake bKGD chunks for our approximation to
83 // the sng command-line tool. Package png doesn't keep that metadata when
84 // png.Decode returns an image.Image.
85 var fakebKGDs = map[string]string{
86 "ftbbn0g01": "bKGD {gray: 0;}\n",
87 "ftbbn0g02": "bKGD {gray: 0;}\n",
88 "ftbbn0g04": "bKGD {gray: 0;}\n",
89 "ftbbn2c16": "bKGD {red: 0; green: 0; blue: 65535;}\n",
90 "ftbbn3p08": "bKGD {index: 245}\n",
91 "ftbgn2c16": "bKGD {red: 0; green: 65535; blue: 0;}\n",
92 "ftbgn3p08": "bKGD {index: 245}\n",
93 "ftbrn2c08": "bKGD {red: 255; green: 0; blue: 0;}\n",
94 "ftbwn0g16": "bKGD {gray: 65535;}\n",
95 "ftbwn3p08": "bKGD {index: 0}\n",
96 "ftbyn3p08": "bKGD {index: 245}\n",
99 // fakegAMAs maps from filenames to fake gAMA chunks for our approximation to
100 // the sng command-line tool. Package png doesn't keep that metadata when
101 // png.Decode returns an image.Image.
102 var fakegAMAs = map[string]string{
103 "ftbbn0g01": "",
104 "ftbbn0g02": "gAMA {0.45455}\n",
107 // fakeIHDRUsings maps from filenames to fake IHDR "using" lines for our
108 // approximation to the sng command-line tool. The PNG model is that
109 // transparency (in the tRNS chunk) is separate to the color/grayscale/palette
110 // color model (in the IHDR chunk). The Go model is that the concrete
111 // image.Image type returned by png.Decode, such as image.RGBA (with all pixels
112 // having 100% alpha) or image.NRGBA, encapsulates whether or not the image has
113 // transparency. This map is a hack to work around the fact that the Go model
114 // can't otherwise discriminate PNG's "IHDR says color (with no alpha) but tRNS
115 // says alpha" and "IHDR says color with alpha".
116 var fakeIHDRUsings = map[string]string{
117 "ftbbn0g01": " using grayscale;\n",
118 "ftbbn0g02": " using grayscale;\n",
119 "ftbbn0g04": " using grayscale;\n",
120 "ftbbn2c16": " using color;\n",
121 "ftbgn2c16": " using color;\n",
122 "ftbrn2c08": " using color;\n",
123 "ftbwn0g16": " using grayscale;\n",
126 // An approximation of the sng command-line tool.
127 func sng(w io.WriteCloser, filename string, png image.Image) {
128 defer w.Close()
129 bounds := png.Bounds()
130 cm := png.ColorModel()
131 var bitdepth int
132 switch cm {
133 case color.RGBAModel, color.NRGBAModel, color.AlphaModel, color.GrayModel:
134 bitdepth = 8
135 default:
136 bitdepth = 16
138 cpm, _ := cm.(color.Palette)
139 var paletted *image.Paletted
140 if cpm != nil {
141 switch {
142 case len(cpm) <= 2:
143 bitdepth = 1
144 case len(cpm) <= 4:
145 bitdepth = 2
146 case len(cpm) <= 16:
147 bitdepth = 4
148 default:
149 bitdepth = 8
151 paletted = png.(*image.Paletted)
154 // Write the filename and IHDR.
155 io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n")
156 fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth)
157 if s, ok := fakeIHDRUsings[filename]; ok {
158 io.WriteString(w, s)
159 } else {
160 switch {
161 case cm == color.RGBAModel, cm == color.RGBA64Model:
162 io.WriteString(w, " using color;\n")
163 case cm == color.NRGBAModel, cm == color.NRGBA64Model:
164 io.WriteString(w, " using color alpha;\n")
165 case cm == color.GrayModel, cm == color.Gray16Model:
166 io.WriteString(w, " using grayscale;\n")
167 case cpm != nil:
168 io.WriteString(w, " using color palette;\n")
169 default:
170 io.WriteString(w, "unknown PNG decoder color model\n")
173 io.WriteString(w, "}\n")
175 // We fake a gAMA chunk. The test files have a gAMA chunk but the go PNG
176 // parser ignores it (the PNG spec section 11.3 says "Ancillary chunks may
177 // be ignored by a decoder").
178 if s, ok := fakegAMAs[filename]; ok {
179 io.WriteString(w, s)
180 } else {
181 io.WriteString(w, "gAMA {1.0000}\n")
184 // Write the PLTE and tRNS (if applicable).
185 useTransparent := false
186 if cpm != nil {
187 lastAlpha := -1
188 io.WriteString(w, "PLTE {\n")
189 for i, c := range cpm {
190 var r, g, b, a uint8
191 switch c := c.(type) {
192 case color.RGBA:
193 r, g, b, a = c.R, c.G, c.B, 0xff
194 case color.NRGBA:
195 r, g, b, a = c.R, c.G, c.B, c.A
196 default:
197 panic("unknown palette color type")
199 if a != 0xff {
200 lastAlpha = i
202 fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b)
204 io.WriteString(w, "}\n")
205 if s, ok := fakebKGDs[filename]; ok {
206 io.WriteString(w, s)
208 if lastAlpha != -1 {
209 io.WriteString(w, "tRNS {\n")
210 for i := 0; i <= lastAlpha; i++ {
211 _, _, _, a := cpm[i].RGBA()
212 a >>= 8
213 fmt.Fprintf(w, " %d", a)
215 io.WriteString(w, "}\n")
217 } else if strings.HasPrefix(filename, "ft") {
218 if s, ok := fakebKGDs[filename]; ok {
219 io.WriteString(w, s)
221 // We fake a tRNS chunk. The test files' grayscale and truecolor
222 // transparent images all have their top left corner transparent.
223 switch c := png.At(0, 0).(type) {
224 case color.NRGBA:
225 if c.A == 0 {
226 useTransparent = true
227 io.WriteString(w, "tRNS {\n")
228 switch filename {
229 case "ftbbn0g01", "ftbbn0g02", "ftbbn0g04":
230 // The standard image package doesn't have a "gray with
231 // alpha" type. Instead, we use an image.NRGBA.
232 fmt.Fprintf(w, " gray: %d;\n", c.R)
233 default:
234 fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B)
236 io.WriteString(w, "}\n")
238 case color.NRGBA64:
239 if c.A == 0 {
240 useTransparent = true
241 io.WriteString(w, "tRNS {\n")
242 switch filename {
243 case "ftbwn0g16":
244 // The standard image package doesn't have a "gray16 with
245 // alpha" type. Instead, we use an image.NRGBA64.
246 fmt.Fprintf(w, " gray: %d;\n", c.R)
247 default:
248 fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B)
250 io.WriteString(w, "}\n")
255 // Write the IMAGE.
256 io.WriteString(w, "IMAGE {\n pixels hex\n")
257 for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
258 switch {
259 case cm == color.GrayModel:
260 for x := bounds.Min.X; x < bounds.Max.X; x++ {
261 gray := png.At(x, y).(color.Gray)
262 fmt.Fprintf(w, "%02x", gray.Y)
264 case cm == color.Gray16Model:
265 for x := bounds.Min.X; x < bounds.Max.X; x++ {
266 gray16 := png.At(x, y).(color.Gray16)
267 fmt.Fprintf(w, "%04x ", gray16.Y)
269 case cm == color.RGBAModel:
270 for x := bounds.Min.X; x < bounds.Max.X; x++ {
271 rgba := png.At(x, y).(color.RGBA)
272 fmt.Fprintf(w, "%02x%02x%02x ", rgba.R, rgba.G, rgba.B)
274 case cm == color.RGBA64Model:
275 for x := bounds.Min.X; x < bounds.Max.X; x++ {
276 rgba64 := png.At(x, y).(color.RGBA64)
277 fmt.Fprintf(w, "%04x%04x%04x ", rgba64.R, rgba64.G, rgba64.B)
279 case cm == color.NRGBAModel:
280 for x := bounds.Min.X; x < bounds.Max.X; x++ {
281 nrgba := png.At(x, y).(color.NRGBA)
282 switch filename {
283 case "ftbbn0g01", "ftbbn0g02", "ftbbn0g04":
284 fmt.Fprintf(w, "%02x", nrgba.R)
285 default:
286 if useTransparent {
287 fmt.Fprintf(w, "%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B)
288 } else {
289 fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
293 case cm == color.NRGBA64Model:
294 for x := bounds.Min.X; x < bounds.Max.X; x++ {
295 nrgba64 := png.At(x, y).(color.NRGBA64)
296 switch filename {
297 case "ftbwn0g16":
298 fmt.Fprintf(w, "%04x ", nrgba64.R)
299 default:
300 if useTransparent {
301 fmt.Fprintf(w, "%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B)
302 } else {
303 fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
307 case cpm != nil:
308 var b, c int
309 for x := bounds.Min.X; x < bounds.Max.X; x++ {
310 b = b<<uint(bitdepth) | int(paletted.ColorIndexAt(x, y))
312 if c == 8/bitdepth {
313 fmt.Fprintf(w, "%02x", b)
314 b = 0
315 c = 0
318 if c != 0 {
319 for c != 8/bitdepth {
320 b = b << uint(bitdepth)
323 fmt.Fprintf(w, "%02x", b)
326 io.WriteString(w, "\n")
328 io.WriteString(w, "}\n")
331 func TestReader(t *testing.T) {
332 names := filenames
333 if testing.Short() {
334 names = filenamesShort
336 for _, fn := range names {
337 // Read the .png file.
338 img, err := readPNG("testdata/pngsuite/" + fn + ".png")
339 if err != nil {
340 t.Error(fn, err)
341 continue
344 if fn == "basn4a16" {
345 // basn4a16.sng is gray + alpha but sng() will produce true color + alpha
346 // so we just check a single random pixel.
347 c := img.At(2, 1).(color.NRGBA64)
348 if c.R != 0x11a7 || c.G != 0x11a7 || c.B != 0x11a7 || c.A != 0x1085 {
349 t.Error(fn, fmt.Errorf("wrong pixel value at (2, 1): %x", c))
351 continue
354 piper, pipew := io.Pipe()
355 pb := bufio.NewScanner(piper)
356 go sng(pipew, fn, img)
357 defer piper.Close()
359 // Read the .sng file.
360 sf, err := os.Open("testdata/pngsuite/" + fn + ".sng")
361 if err != nil {
362 t.Error(fn, err)
363 continue
365 defer sf.Close()
366 sb := bufio.NewScanner(sf)
367 if err != nil {
368 t.Error(fn, err)
369 continue
372 // Compare the two, in SNG format, line by line.
373 for {
374 pdone := !pb.Scan()
375 sdone := !sb.Scan()
376 if pdone && sdone {
377 break
379 if pdone || sdone {
380 t.Errorf("%s: Different sizes", fn)
381 break
383 ps := pb.Text()
384 ss := sb.Text()
386 // Newer versions of the sng command line tool append an optional
387 // color name to the RGB tuple. For example:
388 // # rgb = (0xff,0xff,0xff) grey100
389 // # rgb = (0x00,0x00,0xff) blue1
390 // instead of the older version's plainer:
391 // # rgb = (0xff,0xff,0xff)
392 // # rgb = (0x00,0x00,0xff)
393 // We strip any such name.
394 if strings.Contains(ss, "# rgb = (") && !strings.HasSuffix(ss, ")") {
395 if i := strings.LastIndex(ss, ") "); i >= 0 {
396 ss = ss[:i+1]
400 if ps != ss {
401 t.Errorf("%s: Mismatch\n%s\nversus\n%s\n", fn, ps, ss)
402 break
405 if pb.Err() != nil {
406 t.Error(fn, pb.Err())
408 if sb.Err() != nil {
409 t.Error(fn, sb.Err())
414 var readerErrors = []struct {
415 file string
416 err string
418 {"invalid-zlib.png", "zlib: invalid checksum"},
419 {"invalid-crc32.png", "invalid checksum"},
420 {"invalid-noend.png", "unexpected EOF"},
421 {"invalid-trunc.png", "unexpected EOF"},
424 func TestReaderError(t *testing.T) {
425 for _, tt := range readerErrors {
426 img, err := readPNG("testdata/" + tt.file)
427 if err == nil {
428 t.Errorf("decoding %s: missing error", tt.file)
429 continue
431 if !strings.Contains(err.Error(), tt.err) {
432 t.Errorf("decoding %s: %s, want %s", tt.file, err, tt.err)
434 if img != nil {
435 t.Errorf("decoding %s: have image + error", tt.file)
440 func TestPalettedDecodeConfig(t *testing.T) {
441 for _, fn := range filenamesPaletted {
442 f, err := os.Open("testdata/pngsuite/" + fn + ".png")
443 if err != nil {
444 t.Errorf("%s: open failed: %v", fn, err)
445 continue
447 defer f.Close()
448 cfg, err := DecodeConfig(f)
449 if err != nil {
450 t.Errorf("%s: %v", fn, err)
451 continue
453 pal, ok := cfg.ColorModel.(color.Palette)
454 if !ok {
455 t.Errorf("%s: expected paletted color model", fn)
456 continue
458 if pal == nil {
459 t.Errorf("%s: palette not initialized", fn)
460 continue
465 func TestInterlaced(t *testing.T) {
466 a, err := readPNG("testdata/gray-gradient.png")
467 if err != nil {
468 t.Fatal(err)
470 b, err := readPNG("testdata/gray-gradient.interlaced.png")
471 if err != nil {
472 t.Fatal(err)
474 if !reflect.DeepEqual(a, b) {
475 t.Fatalf("decodings differ:\nnon-interlaced:\n%#v\ninterlaced:\n%#v", a, b)
479 func TestIncompleteIDATOnRowBoundary(t *testing.T) {
480 // The following is an invalid 1x2 grayscale PNG image. The header is OK,
481 // but the zlib-compressed IDAT payload contains two bytes "\x02\x00",
482 // which is only one row of data (the leading "\x02" is a row filter).
483 const (
484 ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x02\x08\x00\x00\x00\x00\xbc\xea\xe9\xfb"
485 idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
486 iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
488 _, err := Decode(strings.NewReader(pngHeader + ihdr + idat + iend))
489 if err == nil {
490 t.Fatal("got nil error, want non-nil")
494 func TestTrailingIDATChunks(t *testing.T) {
495 // The following is a valid 1x1 PNG image containing color.Gray{255} and
496 // a trailing zero-length IDAT chunk (see PNG specification section 12.9):
497 const (
498 ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x00\x00\x00\x00\x3a\x7e\x9b\x55"
499 idatWhite = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\xfa\x0f\x08\x00\x00\xff\xff\x01\x05\x01\x02\x5a\xdd\x39\xcd"
500 idatZero = "\x00\x00\x00\x00IDAT\x35\xaf\x06\x1e"
501 iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
503 _, err := Decode(strings.NewReader(pngHeader + ihdr + idatWhite + idatZero + iend))
504 if err != nil {
505 t.Fatalf("decoding valid image: %v", err)
508 // Non-zero-length trailing IDAT chunks should be ignored (recoverable error).
509 // The following chunk contains a single pixel with color.Gray{0}.
510 const idatBlack = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
512 img, err := Decode(strings.NewReader(pngHeader + ihdr + idatWhite + idatBlack + iend))
513 if err != nil {
514 t.Fatalf("trailing IDAT not ignored: %v", err)
516 if img.At(0, 0) == (color.Gray{0}) {
517 t.Fatal("decoded image from trailing IDAT chunk")
521 func TestMultipletRNSChunks(t *testing.T) {
523 The following is a valid 1x1 paletted PNG image with a 1-element palette
524 containing color.NRGBA{0xff, 0x00, 0x00, 0x7f}:
525 0000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR
526 0000010: 0000 0001 0000 0001 0803 0000 0028 cb34 .............(.4
527 0000020: bb00 0000 0350 4c54 45ff 0000 19e2 0937 .....PLTE......7
528 0000030: 0000 0001 7452 4e53 7f80 5cb4 cb00 0000 ....tRNS..\.....
529 0000040: 0e49 4441 5478 9c62 6200 0400 00ff ff00 .IDATx.bb.......
530 0000050: 0600 03fa d059 ae00 0000 0049 454e 44ae .....Y.....IEND.
531 0000060: 4260 82 B`.
532 Dropping the tRNS chunk makes that color's alpha 0xff instead of 0x7f.
534 const (
535 ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x03\x00\x00\x00\x28\xcb\x34\xbb"
536 plte = "\x00\x00\x00\x03PLTE\xff\x00\x00\x19\xe2\x09\x37"
537 trns = "\x00\x00\x00\x01tRNS\x7f\x80\x5c\xb4\xcb"
538 idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
539 iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
541 for i := 0; i < 4; i++ {
542 var b []byte
543 b = append(b, pngHeader...)
544 b = append(b, ihdr...)
545 b = append(b, plte...)
546 for j := 0; j < i; j++ {
547 b = append(b, trns...)
549 b = append(b, idat...)
550 b = append(b, iend...)
552 var want color.Color
553 m, err := Decode(bytes.NewReader(b))
554 switch i {
555 case 0:
556 if err != nil {
557 t.Errorf("%d tRNS chunks: %v", i, err)
558 continue
560 want = color.RGBA{0xff, 0x00, 0x00, 0xff}
561 case 1:
562 if err != nil {
563 t.Errorf("%d tRNS chunks: %v", i, err)
564 continue
566 want = color.NRGBA{0xff, 0x00, 0x00, 0x7f}
567 default:
568 if err == nil {
569 t.Errorf("%d tRNS chunks: got nil error, want non-nil", i)
571 continue
573 if got := m.At(0, 0); got != want {
574 t.Errorf("%d tRNS chunks: got %T %v, want %T %v", i, got, got, want, want)
579 func TestUnknownChunkLengthUnderflow(t *testing.T) {
580 data := []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0xff, 0xff,
581 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0xf4, 0x7c, 0x55, 0x04, 0x1a,
582 0xd3, 0x11, 0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e, 0x00, 0x00,
583 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf4, 0x7c, 0x55, 0x04, 0x1a,
584 0xd3}
585 _, err := Decode(bytes.NewReader(data))
586 if err == nil {
587 t.Errorf("Didn't fail reading an unknown chunk with length 0xffffffff")
591 func TestGray8Transparent(t *testing.T) {
592 // These bytes come from https://github.com/golang/go/issues/19553
593 m, err := Decode(bytes.NewReader([]byte{
594 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
595 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x85, 0x2c, 0x88,
596 0x80, 0x00, 0x00, 0x00, 0x02, 0x74, 0x52, 0x4e, 0x53, 0x00, 0xff, 0x5b, 0x91, 0x22, 0xb5, 0x00,
597 0x00, 0x00, 0x02, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x00, 0x00, 0x00,
598 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0a, 0xf0, 0x00, 0x00, 0x0a, 0xf0, 0x01, 0x42, 0xac,
599 0x34, 0x98, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd5, 0x04, 0x02, 0x12, 0x11,
600 0x11, 0xf7, 0x65, 0x3d, 0x8b, 0x00, 0x00, 0x00, 0x4f, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63,
601 0xf8, 0xff, 0xff, 0xff, 0xb9, 0xbd, 0x70, 0xf0, 0x8c, 0x01, 0xc8, 0xaf, 0x6e, 0x99, 0x02, 0x05,
602 0xd9, 0x7b, 0xc1, 0xfc, 0x6b, 0xff, 0xa1, 0xa0, 0x87, 0x30, 0xff, 0xd9, 0xde, 0xbd, 0xd5, 0x4b,
603 0xf7, 0xee, 0xfd, 0x0e, 0xe3, 0xef, 0xcd, 0x06, 0x19, 0x14, 0xf5, 0x1e, 0xce, 0xef, 0x01, 0x31,
604 0x92, 0xd7, 0x82, 0x41, 0x31, 0x9c, 0x3f, 0x07, 0x02, 0xee, 0xa1, 0xaa, 0xff, 0xff, 0x9f, 0xe1,
605 0xd9, 0x56, 0x30, 0xf8, 0x0e, 0xe5, 0x03, 0x00, 0xa9, 0x42, 0x84, 0x3d, 0xdf, 0x8f, 0xa6, 0x8f,
606 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
608 if err != nil {
609 t.Fatalf("Decode: %v", err)
612 const hex = "0123456789abcdef"
613 var got []byte
614 bounds := m.Bounds()
615 for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
616 for x := bounds.Min.X; x < bounds.Max.X; x++ {
617 if r, _, _, a := m.At(x, y).RGBA(); a != 0 {
618 got = append(got,
619 hex[0x0f&(r>>12)],
620 hex[0x0f&(r>>8)],
621 ' ',
623 } else {
624 got = append(got,
625 '.',
626 '.',
627 ' ',
631 got = append(got, '\n')
634 const want = "" +
635 ".. .. .. ce bd bd bd bd bd bd bd bd bd bd e6 \n" +
636 ".. .. .. 7b 84 94 94 94 94 94 94 94 94 6b bd \n" +
637 ".. .. .. 7b d6 .. .. .. .. .. .. .. .. 8c bd \n" +
638 ".. .. .. 7b d6 .. .. .. .. .. .. .. .. 8c bd \n" +
639 ".. .. .. 7b d6 .. .. .. .. .. .. .. .. 8c bd \n" +
640 "e6 bd bd 7b a5 bd bd f7 .. .. .. .. .. 8c bd \n" +
641 "bd 6b 94 94 94 94 5a ef .. .. .. .. .. 8c bd \n" +
642 "bd 8c .. .. .. .. 63 ad ad ad ad ad ad 73 bd \n" +
643 "bd 8c .. .. .. .. 63 9c 9c 9c 9c 9c 9c 9c de \n" +
644 "bd 6b 94 94 94 94 5a ef .. .. .. .. .. .. .. \n" +
645 "e6 b5 b5 b5 b5 b5 b5 f7 .. .. .. .. .. .. .. \n"
647 if string(got) != want {
648 t.Errorf("got:\n%swant:\n%s", got, want)
652 func benchmarkDecode(b *testing.B, filename string, bytesPerPixel int) {
653 b.StopTimer()
654 data, err := ioutil.ReadFile(filename)
655 if err != nil {
656 b.Fatal(err)
658 s := string(data)
659 cfg, err := DecodeConfig(strings.NewReader(s))
660 if err != nil {
661 b.Fatal(err)
663 b.SetBytes(int64(cfg.Width * cfg.Height * bytesPerPixel))
664 b.StartTimer()
665 for i := 0; i < b.N; i++ {
666 Decode(strings.NewReader(s))
670 func BenchmarkDecodeGray(b *testing.B) {
671 benchmarkDecode(b, "testdata/benchGray.png", 1)
674 func BenchmarkDecodeNRGBAGradient(b *testing.B) {
675 benchmarkDecode(b, "testdata/benchNRGBA-gradient.png", 4)
678 func BenchmarkDecodeNRGBAOpaque(b *testing.B) {
679 benchmarkDecode(b, "testdata/benchNRGBA-opaque.png", 4)
682 func BenchmarkDecodePaletted(b *testing.B) {
683 benchmarkDecode(b, "testdata/benchPaletted.png", 1)
686 func BenchmarkDecodeRGB(b *testing.B) {
687 benchmarkDecode(b, "testdata/benchRGB.png", 4)
690 func BenchmarkDecodeInterlacing(b *testing.B) {
691 benchmarkDecode(b, "testdata/benchRGB-interlace.png", 4)