github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/go/image/png/reader_test.go (about) 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. 4 5 package png 6 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" 19 ) 20 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", 57 } 58 59 var filenamesPaletted = []string{ 60 "basn3p01", 61 "basn3p02", 62 "basn3p04", 63 "basn3p08", 64 "basn3p08-trns", 65 } 66 67 var filenamesShort = []string{ 68 "basn0g01", 69 "basn0g04-31", 70 "basn6a16", 71 } 72 73 func readPNG(filename string) (image.Image, error) { 74 f, err := os.Open(filename) 75 if err != nil { 76 return nil, err 77 } 78 defer f.Close() 79 return Decode(f) 80 } 81 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", 97 } 98 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", 105 } 106 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", 124 } 125 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 137 } 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 150 } 151 paletted = png.(*image.Paletted) 152 } 153 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") 171 } 172 } 173 io.WriteString(w, "}\n") 174 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") 182 } 183 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") 198 } 199 if a != 0xff { 200 lastAlpha = i 201 } 202 fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b) 203 } 204 io.WriteString(w, "}\n") 205 if s, ok := fakebKGDs[filename]; ok { 206 io.WriteString(w, s) 207 } 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) 214 } 215 io.WriteString(w, "}\n") 216 } 217 } else if strings.HasPrefix(filename, "ft") { 218 if s, ok := fakebKGDs[filename]; ok { 219 io.WriteString(w, s) 220 } 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) 235 } 236 io.WriteString(w, "}\n") 237 } 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) 249 } 250 io.WriteString(w, "}\n") 251 } 252 } 253 } 254 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) 263 } 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) 268 } 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) 273 } 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) 278 } 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) 290 } 291 } 292 } 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) 304 } 305 } 306 } 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)) 311 c++ 312 if c == 8/bitdepth { 313 fmt.Fprintf(w, "%02x", b) 314 b = 0 315 c = 0 316 } 317 } 318 if c != 0 { 319 for c != 8/bitdepth { 320 b = b << uint(bitdepth) 321 c++ 322 } 323 fmt.Fprintf(w, "%02x", b) 324 } 325 } 326 io.WriteString(w, "\n") 327 } 328 io.WriteString(w, "}\n") 329 } 330 331 func TestReader(t *testing.T) { 332 names := filenames 333 if testing.Short() { 334 names = filenamesShort 335 } 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 342 } 343 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)) 350 } 351 continue 352 } 353 354 piper, pipew := io.Pipe() 355 pb := bufio.NewScanner(piper) 356 go sng(pipew, fn, img) 357 defer piper.Close() 358 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 364 } 365 defer sf.Close() 366 sb := bufio.NewScanner(sf) 367 368 // Compare the two, in SNG format, line by line. 369 for { 370 pdone := !pb.Scan() 371 sdone := !sb.Scan() 372 if pdone && sdone { 373 break 374 } 375 if pdone || sdone { 376 t.Errorf("%s: Different sizes", fn) 377 break 378 } 379 ps := pb.Text() 380 ss := sb.Text() 381 382 // Newer versions of the sng command line tool append an optional 383 // color name to the RGB tuple. For example: 384 // # rgb = (0xff,0xff,0xff) grey100 385 // # rgb = (0x00,0x00,0xff) blue1 386 // instead of the older version's plainer: 387 // # rgb = (0xff,0xff,0xff) 388 // # rgb = (0x00,0x00,0xff) 389 // We strip any such name. 390 if strings.Contains(ss, "# rgb = (") && !strings.HasSuffix(ss, ")") { 391 if i := strings.LastIndex(ss, ") "); i >= 0 { 392 ss = ss[:i+1] 393 } 394 } 395 396 if ps != ss { 397 t.Errorf("%s: Mismatch\n%s\nversus\n%s\n", fn, ps, ss) 398 break 399 } 400 } 401 if pb.Err() != nil { 402 t.Error(fn, pb.Err()) 403 } 404 if sb.Err() != nil { 405 t.Error(fn, sb.Err()) 406 } 407 } 408 } 409 410 var readerErrors = []struct { 411 file string 412 err string 413 }{ 414 {"invalid-zlib.png", "zlib: invalid checksum"}, 415 {"invalid-crc32.png", "invalid checksum"}, 416 {"invalid-noend.png", "unexpected EOF"}, 417 {"invalid-trunc.png", "unexpected EOF"}, 418 } 419 420 func TestReaderError(t *testing.T) { 421 for _, tt := range readerErrors { 422 img, err := readPNG("testdata/" + tt.file) 423 if err == nil { 424 t.Errorf("decoding %s: missing error", tt.file) 425 continue 426 } 427 if !strings.Contains(err.Error(), tt.err) { 428 t.Errorf("decoding %s: %s, want %s", tt.file, err, tt.err) 429 } 430 if img != nil { 431 t.Errorf("decoding %s: have image + error", tt.file) 432 } 433 } 434 } 435 436 func TestPalettedDecodeConfig(t *testing.T) { 437 for _, fn := range filenamesPaletted { 438 f, err := os.Open("testdata/pngsuite/" + fn + ".png") 439 if err != nil { 440 t.Errorf("%s: open failed: %v", fn, err) 441 continue 442 } 443 defer f.Close() 444 cfg, err := DecodeConfig(f) 445 if err != nil { 446 t.Errorf("%s: %v", fn, err) 447 continue 448 } 449 pal, ok := cfg.ColorModel.(color.Palette) 450 if !ok { 451 t.Errorf("%s: expected paletted color model", fn) 452 continue 453 } 454 if pal == nil { 455 t.Errorf("%s: palette not initialized", fn) 456 continue 457 } 458 } 459 } 460 461 func TestInterlaced(t *testing.T) { 462 a, err := readPNG("testdata/gray-gradient.png") 463 if err != nil { 464 t.Fatal(err) 465 } 466 b, err := readPNG("testdata/gray-gradient.interlaced.png") 467 if err != nil { 468 t.Fatal(err) 469 } 470 if !reflect.DeepEqual(a, b) { 471 t.Fatalf("decodings differ:\nnon-interlaced:\n%#v\ninterlaced:\n%#v", a, b) 472 } 473 } 474 475 func TestIncompleteIDATOnRowBoundary(t *testing.T) { 476 // The following is an invalid 1x2 grayscale PNG image. The header is OK, 477 // but the zlib-compressed IDAT payload contains two bytes "\x02\x00", 478 // which is only one row of data (the leading "\x02" is a row filter). 479 const ( 480 ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x02\x08\x00\x00\x00\x00\xbc\xea\xe9\xfb" 481 idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae" 482 iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82" 483 ) 484 _, err := Decode(strings.NewReader(pngHeader + ihdr + idat + iend)) 485 if err == nil { 486 t.Fatal("got nil error, want non-nil") 487 } 488 } 489 490 func TestTrailingIDATChunks(t *testing.T) { 491 // The following is a valid 1x1 PNG image containing color.Gray{255} and 492 // a trailing zero-length IDAT chunk (see PNG specification section 12.9): 493 const ( 494 ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x00\x00\x00\x00\x3a\x7e\x9b\x55" 495 idatWhite = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\xfa\x0f\x08\x00\x00\xff\xff\x01\x05\x01\x02\x5a\xdd\x39\xcd" 496 idatZero = "\x00\x00\x00\x00IDAT\x35\xaf\x06\x1e" 497 iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82" 498 ) 499 _, err := Decode(strings.NewReader(pngHeader + ihdr + idatWhite + idatZero + iend)) 500 if err != nil { 501 t.Fatalf("decoding valid image: %v", err) 502 } 503 504 // Non-zero-length trailing IDAT chunks should be ignored (recoverable error). 505 // The following chunk contains a single pixel with color.Gray{0}. 506 const idatBlack = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae" 507 508 img, err := Decode(strings.NewReader(pngHeader + ihdr + idatWhite + idatBlack + iend)) 509 if err != nil { 510 t.Fatalf("trailing IDAT not ignored: %v", err) 511 } 512 if img.At(0, 0) == (color.Gray{0}) { 513 t.Fatal("decoded image from trailing IDAT chunk") 514 } 515 } 516 517 func TestMultipletRNSChunks(t *testing.T) { 518 /* 519 The following is a valid 1x1 paletted PNG image with a 1-element palette 520 containing color.NRGBA{0xff, 0x00, 0x00, 0x7f}: 521 0000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR 522 0000010: 0000 0001 0000 0001 0803 0000 0028 cb34 .............(.4 523 0000020: bb00 0000 0350 4c54 45ff 0000 19e2 0937 .....PLTE......7 524 0000030: 0000 0001 7452 4e53 7f80 5cb4 cb00 0000 ....tRNS..\..... 525 0000040: 0e49 4441 5478 9c62 6200 0400 00ff ff00 .IDATx.bb....... 526 0000050: 0600 03fa d059 ae00 0000 0049 454e 44ae .....Y.....IEND. 527 0000060: 4260 82 B`. 528 Dropping the tRNS chunk makes that color's alpha 0xff instead of 0x7f. 529 */ 530 const ( 531 ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x03\x00\x00\x00\x28\xcb\x34\xbb" 532 plte = "\x00\x00\x00\x03PLTE\xff\x00\x00\x19\xe2\x09\x37" 533 trns = "\x00\x00\x00\x01tRNS\x7f\x80\x5c\xb4\xcb" 534 idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae" 535 iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82" 536 ) 537 for i := 0; i < 4; i++ { 538 var b []byte 539 b = append(b, pngHeader...) 540 b = append(b, ihdr...) 541 b = append(b, plte...) 542 for j := 0; j < i; j++ { 543 b = append(b, trns...) 544 } 545 b = append(b, idat...) 546 b = append(b, iend...) 547 548 var want color.Color 549 m, err := Decode(bytes.NewReader(b)) 550 switch i { 551 case 0: 552 if err != nil { 553 t.Errorf("%d tRNS chunks: %v", i, err) 554 continue 555 } 556 want = color.RGBA{0xff, 0x00, 0x00, 0xff} 557 case 1: 558 if err != nil { 559 t.Errorf("%d tRNS chunks: %v", i, err) 560 continue 561 } 562 want = color.NRGBA{0xff, 0x00, 0x00, 0x7f} 563 default: 564 if err == nil { 565 t.Errorf("%d tRNS chunks: got nil error, want non-nil", i) 566 } 567 continue 568 } 569 if got := m.At(0, 0); got != want { 570 t.Errorf("%d tRNS chunks: got %T %v, want %T %v", i, got, got, want, want) 571 } 572 } 573 } 574 575 func TestUnknownChunkLengthUnderflow(t *testing.T) { 576 data := []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0xff, 0xff, 577 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0xf4, 0x7c, 0x55, 0x04, 0x1a, 578 0xd3, 0x11, 0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e, 0x00, 0x00, 579 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf4, 0x7c, 0x55, 0x04, 0x1a, 580 0xd3} 581 _, err := Decode(bytes.NewReader(data)) 582 if err == nil { 583 t.Errorf("Didn't fail reading an unknown chunk with length 0xffffffff") 584 } 585 } 586 587 func TestPaletted8OutOfRangePixel(t *testing.T) { 588 // IDAT contains a reference to a palette index that does not exist in the file. 589 img, err := readPNG("testdata/invalid-palette.png") 590 if err != nil { 591 t.Errorf("decoding invalid-palette.png: unexpected error %v", err) 592 return 593 } 594 595 // Expect that the palette is extended with opaque black. 596 want := color.RGBA{0x00, 0x00, 0x00, 0xff} 597 if got := img.At(15, 15); got != want { 598 t.Errorf("got %F %v, expected %T %v", got, got, want, want) 599 } 600 } 601 602 func TestGray8Transparent(t *testing.T) { 603 // These bytes come from https://golang.org/issues/19553 604 m, err := Decode(bytes.NewReader([]byte{ 605 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 606 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x85, 0x2c, 0x88, 607 0x80, 0x00, 0x00, 0x00, 0x02, 0x74, 0x52, 0x4e, 0x53, 0x00, 0xff, 0x5b, 0x91, 0x22, 0xb5, 0x00, 608 0x00, 0x00, 0x02, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x00, 0x00, 0x00, 609 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0a, 0xf0, 0x00, 0x00, 0x0a, 0xf0, 0x01, 0x42, 0xac, 610 0x34, 0x98, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd5, 0x04, 0x02, 0x12, 0x11, 611 0x11, 0xf7, 0x65, 0x3d, 0x8b, 0x00, 0x00, 0x00, 0x4f, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 612 0xf8, 0xff, 0xff, 0xff, 0xb9, 0xbd, 0x70, 0xf0, 0x8c, 0x01, 0xc8, 0xaf, 0x6e, 0x99, 0x02, 0x05, 613 0xd9, 0x7b, 0xc1, 0xfc, 0x6b, 0xff, 0xa1, 0xa0, 0x87, 0x30, 0xff, 0xd9, 0xde, 0xbd, 0xd5, 0x4b, 614 0xf7, 0xee, 0xfd, 0x0e, 0xe3, 0xef, 0xcd, 0x06, 0x19, 0x14, 0xf5, 0x1e, 0xce, 0xef, 0x01, 0x31, 615 0x92, 0xd7, 0x82, 0x41, 0x31, 0x9c, 0x3f, 0x07, 0x02, 0xee, 0xa1, 0xaa, 0xff, 0xff, 0x9f, 0xe1, 616 0xd9, 0x56, 0x30, 0xf8, 0x0e, 0xe5, 0x03, 0x00, 0xa9, 0x42, 0x84, 0x3d, 0xdf, 0x8f, 0xa6, 0x8f, 617 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 618 })) 619 if err != nil { 620 t.Fatalf("Decode: %v", err) 621 } 622 623 const hex = "0123456789abcdef" 624 var got []byte 625 bounds := m.Bounds() 626 for y := bounds.Min.Y; y < bounds.Max.Y; y++ { 627 for x := bounds.Min.X; x < bounds.Max.X; x++ { 628 if r, _, _, a := m.At(x, y).RGBA(); a != 0 { 629 got = append(got, 630 hex[0x0f&(r>>12)], 631 hex[0x0f&(r>>8)], 632 ' ', 633 ) 634 } else { 635 got = append(got, 636 '.', 637 '.', 638 ' ', 639 ) 640 } 641 } 642 got = append(got, '\n') 643 } 644 645 const want = "" + 646 ".. .. .. ce bd bd bd bd bd bd bd bd bd bd e6 \n" + 647 ".. .. .. 7b 84 94 94 94 94 94 94 94 94 6b bd \n" + 648 ".. .. .. 7b d6 .. .. .. .. .. .. .. .. 8c bd \n" + 649 ".. .. .. 7b d6 .. .. .. .. .. .. .. .. 8c bd \n" + 650 ".. .. .. 7b d6 .. .. .. .. .. .. .. .. 8c bd \n" + 651 "e6 bd bd 7b a5 bd bd f7 .. .. .. .. .. 8c bd \n" + 652 "bd 6b 94 94 94 94 5a ef .. .. .. .. .. 8c bd \n" + 653 "bd 8c .. .. .. .. 63 ad ad ad ad ad ad 73 bd \n" + 654 "bd 8c .. .. .. .. 63 9c 9c 9c 9c 9c 9c 9c de \n" + 655 "bd 6b 94 94 94 94 5a ef .. .. .. .. .. .. .. \n" + 656 "e6 b5 b5 b5 b5 b5 b5 f7 .. .. .. .. .. .. .. \n" 657 658 if string(got) != want { 659 t.Errorf("got:\n%swant:\n%s", got, want) 660 } 661 } 662 663 func TestDimensionOverflow(t *testing.T) { 664 // These bytes come from https://golang.org/issues/22304 665 // 666 // It encodes a 2147483646 × 2147483646 (i.e. 0x7ffffffe × 0x7ffffffe) 667 // NRGBA image. The (width × height) per se doesn't overflow an int64, but 668 // (width × height × bytesPerPixel) will. 669 _, err := Decode(bytes.NewReader([]byte{ 670 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 671 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x08, 0x06, 0x00, 0x00, 0x00, 0x30, 0x57, 0xb3, 672 0xfd, 0x00, 0x00, 0x00, 0x15, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x62, 0x62, 0x20, 0x12, 0x8c, 673 0x2a, 0xa4, 0xb3, 0x42, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x13, 0x38, 0x00, 0x15, 0x2d, 0xef, 674 0x5f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 675 })) 676 if _, ok := err.(UnsupportedError); !ok { 677 t.Fatalf("Decode: got %v (of type %T), want non-nil error (of type png.UnsupportedError)", err, err) 678 } 679 } 680 681 func benchmarkDecode(b *testing.B, filename string, bytesPerPixel int) { 682 data, err := ioutil.ReadFile(filename) 683 if err != nil { 684 b.Fatal(err) 685 } 686 cfg, err := DecodeConfig(bytes.NewReader(data)) 687 if err != nil { 688 b.Fatal(err) 689 } 690 b.SetBytes(int64(cfg.Width * cfg.Height * bytesPerPixel)) 691 b.ReportAllocs() 692 b.ResetTimer() 693 for i := 0; i < b.N; i++ { 694 Decode(bytes.NewReader(data)) 695 } 696 } 697 698 func BenchmarkDecodeGray(b *testing.B) { 699 benchmarkDecode(b, "testdata/benchGray.png", 1) 700 } 701 702 func BenchmarkDecodeNRGBAGradient(b *testing.B) { 703 benchmarkDecode(b, "testdata/benchNRGBA-gradient.png", 4) 704 } 705 706 func BenchmarkDecodeNRGBAOpaque(b *testing.B) { 707 benchmarkDecode(b, "testdata/benchNRGBA-opaque.png", 4) 708 } 709 710 func BenchmarkDecodePaletted(b *testing.B) { 711 benchmarkDecode(b, "testdata/benchPaletted.png", 1) 712 } 713 714 func BenchmarkDecodeRGB(b *testing.B) { 715 benchmarkDecode(b, "testdata/benchRGB.png", 4) 716 } 717 718 func BenchmarkDecodeInterlacing(b *testing.B) { 719 benchmarkDecode(b, "testdata/benchRGB-interlace.png", 4) 720 }