Source file
src/image/png/reader_test.go
1
2
3
4
5 package png
6
7 import (
8 "bufio"
9 "bytes"
10 "fmt"
11 "image"
12 "image/color"
13 "io"
14 "os"
15 "reflect"
16 "strings"
17 "testing"
18 )
19
20 var filenames = []string{
21 "basn0g01",
22 "basn0g01-30",
23 "basn0g02",
24 "basn0g02-29",
25 "basn0g04",
26 "basn0g04-31",
27 "basn0g08",
28 "basn0g16",
29 "basn2c08",
30 "basn2c16",
31 "basn3p01",
32 "basn3p02",
33 "basn3p04",
34 "basn3p04-31i",
35 "basn3p08",
36 "basn3p08-trns",
37 "basn4a08",
38 "basn4a16",
39 "basn6a08",
40 "basn6a16",
41 "ftbbn0g01",
42 "ftbbn0g02",
43 "ftbbn0g04",
44 "ftbbn2c16",
45 "ftbbn3p08",
46 "ftbgn2c16",
47 "ftbgn3p08",
48 "ftbrn2c08",
49 "ftbwn0g16",
50 "ftbwn3p08",
51 "ftbyn3p08",
52 "ftp0n0g08",
53 "ftp0n2c08",
54 "ftp0n3p08",
55 "ftp1n3p08",
56 }
57
58 var filenamesPaletted = []string{
59 "basn3p01",
60 "basn3p02",
61 "basn3p04",
62 "basn3p08",
63 "basn3p08-trns",
64 }
65
66 var filenamesShort = []string{
67 "basn0g01",
68 "basn0g04-31",
69 "basn6a16",
70 }
71
72 func readPNG(filename string) (image.Image, error) {
73 f, err := os.Open(filename)
74 if err != nil {
75 return nil, err
76 }
77 defer f.Close()
78 return Decode(f)
79 }
80
81
82
83
84 var fakebKGDs = map[string]string{
85 "ftbbn0g01": "bKGD {gray: 0;}\n",
86 "ftbbn0g02": "bKGD {gray: 0;}\n",
87 "ftbbn0g04": "bKGD {gray: 0;}\n",
88 "ftbbn2c16": "bKGD {red: 0; green: 0; blue: 65535;}\n",
89 "ftbbn3p08": "bKGD {index: 245}\n",
90 "ftbgn2c16": "bKGD {red: 0; green: 65535; blue: 0;}\n",
91 "ftbgn3p08": "bKGD {index: 245}\n",
92 "ftbrn2c08": "bKGD {red: 255; green: 0; blue: 0;}\n",
93 "ftbwn0g16": "bKGD {gray: 65535;}\n",
94 "ftbwn3p08": "bKGD {index: 0}\n",
95 "ftbyn3p08": "bKGD {index: 245}\n",
96 }
97
98
99
100
101 var fakegAMAs = map[string]string{
102 "ftbbn0g01": "",
103 "ftbbn0g02": "gAMA {0.45455}\n",
104 }
105
106
107
108
109
110
111
112
113
114
115 var fakeIHDRUsings = map[string]string{
116 "ftbbn0g01": " using grayscale;\n",
117 "ftbbn0g02": " using grayscale;\n",
118 "ftbbn0g04": " using grayscale;\n",
119 "ftbbn2c16": " using color;\n",
120 "ftbgn2c16": " using color;\n",
121 "ftbrn2c08": " using color;\n",
122 "ftbwn0g16": " using grayscale;\n",
123 }
124
125
126 func sng(w io.WriteCloser, filename string, png image.Image) {
127 defer w.Close()
128 bounds := png.Bounds()
129 cm := png.ColorModel()
130 var bitdepth int
131 switch cm {
132 case color.RGBAModel, color.NRGBAModel, color.AlphaModel, color.GrayModel:
133 bitdepth = 8
134 default:
135 bitdepth = 16
136 }
137 cpm, _ := cm.(color.Palette)
138 var paletted *image.Paletted
139 if cpm != nil {
140 switch {
141 case len(cpm) <= 2:
142 bitdepth = 1
143 case len(cpm) <= 4:
144 bitdepth = 2
145 case len(cpm) <= 16:
146 bitdepth = 4
147 default:
148 bitdepth = 8
149 }
150 paletted = png.(*image.Paletted)
151 }
152
153
154 io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n")
155 fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth)
156 if s, ok := fakeIHDRUsings[filename]; ok {
157 io.WriteString(w, s)
158 } else {
159 switch {
160 case cm == color.RGBAModel, cm == color.RGBA64Model:
161 io.WriteString(w, " using color;\n")
162 case cm == color.NRGBAModel, cm == color.NRGBA64Model:
163 io.WriteString(w, " using color alpha;\n")
164 case cm == color.GrayModel, cm == color.Gray16Model:
165 io.WriteString(w, " using grayscale;\n")
166 case cpm != nil:
167 io.WriteString(w, " using color palette;\n")
168 default:
169 io.WriteString(w, "unknown PNG decoder color model\n")
170 }
171 }
172 io.WriteString(w, "}\n")
173
174
175
176
177 if s, ok := fakegAMAs[filename]; ok {
178 io.WriteString(w, s)
179 } else {
180 io.WriteString(w, "gAMA {1.0000}\n")
181 }
182
183
184 useTransparent := false
185 if cpm != nil {
186 lastAlpha := -1
187 io.WriteString(w, "PLTE {\n")
188 for i, c := range cpm {
189 var r, g, b, a uint8
190 switch c := c.(type) {
191 case color.RGBA:
192 r, g, b, a = c.R, c.G, c.B, 0xff
193 case color.NRGBA:
194 r, g, b, a = c.R, c.G, c.B, c.A
195 default:
196 panic("unknown palette color type")
197 }
198 if a != 0xff {
199 lastAlpha = i
200 }
201 fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b)
202 }
203 io.WriteString(w, "}\n")
204 if s, ok := fakebKGDs[filename]; ok {
205 io.WriteString(w, s)
206 }
207 if lastAlpha != -1 {
208 io.WriteString(w, "tRNS {\n")
209 for i := 0; i <= lastAlpha; i++ {
210 _, _, _, a := cpm[i].RGBA()
211 a >>= 8
212 fmt.Fprintf(w, " %d", a)
213 }
214 io.WriteString(w, "}\n")
215 }
216 } else if strings.HasPrefix(filename, "ft") {
217 if s, ok := fakebKGDs[filename]; ok {
218 io.WriteString(w, s)
219 }
220
221
222 switch c := png.At(0, 0).(type) {
223 case color.NRGBA:
224 if c.A == 0 {
225 useTransparent = true
226 io.WriteString(w, "tRNS {\n")
227 switch filename {
228 case "ftbbn0g01", "ftbbn0g02", "ftbbn0g04":
229
230
231 fmt.Fprintf(w, " gray: %d;\n", c.R)
232 default:
233 fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B)
234 }
235 io.WriteString(w, "}\n")
236 }
237 case color.NRGBA64:
238 if c.A == 0 {
239 useTransparent = true
240 io.WriteString(w, "tRNS {\n")
241 switch filename {
242 case "ftbwn0g16":
243
244
245 fmt.Fprintf(w, " gray: %d;\n", c.R)
246 default:
247 fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B)
248 }
249 io.WriteString(w, "}\n")
250 }
251 }
252 }
253
254
255 io.WriteString(w, "IMAGE {\n pixels hex\n")
256 for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
257 switch {
258 case cm == color.GrayModel:
259 for x := bounds.Min.X; x < bounds.Max.X; x++ {
260 gray := png.At(x, y).(color.Gray)
261 fmt.Fprintf(w, "%02x", gray.Y)
262 }
263 case cm == color.Gray16Model:
264 for x := bounds.Min.X; x < bounds.Max.X; x++ {
265 gray16 := png.At(x, y).(color.Gray16)
266 fmt.Fprintf(w, "%04x ", gray16.Y)
267 }
268 case cm == color.RGBAModel:
269 for x := bounds.Min.X; x < bounds.Max.X; x++ {
270 rgba := png.At(x, y).(color.RGBA)
271 fmt.Fprintf(w, "%02x%02x%02x ", rgba.R, rgba.G, rgba.B)
272 }
273 case cm == color.RGBA64Model:
274 for x := bounds.Min.X; x < bounds.Max.X; x++ {
275 rgba64 := png.At(x, y).(color.RGBA64)
276 fmt.Fprintf(w, "%04x%04x%04x ", rgba64.R, rgba64.G, rgba64.B)
277 }
278 case cm == color.NRGBAModel:
279 for x := bounds.Min.X; x < bounds.Max.X; x++ {
280 nrgba := png.At(x, y).(color.NRGBA)
281 switch filename {
282 case "ftbbn0g01", "ftbbn0g02", "ftbbn0g04":
283 fmt.Fprintf(w, "%02x", nrgba.R)
284 default:
285 if useTransparent {
286 fmt.Fprintf(w, "%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B)
287 } else {
288 fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
289 }
290 }
291 }
292 case cm == color.NRGBA64Model:
293 for x := bounds.Min.X; x < bounds.Max.X; x++ {
294 nrgba64 := png.At(x, y).(color.NRGBA64)
295 switch filename {
296 case "ftbwn0g16":
297 fmt.Fprintf(w, "%04x ", nrgba64.R)
298 default:
299 if useTransparent {
300 fmt.Fprintf(w, "%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B)
301 } else {
302 fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
303 }
304 }
305 }
306 case cpm != nil:
307 var b, c int
308 for x := bounds.Min.X; x < bounds.Max.X; x++ {
309 b = b<<uint(bitdepth) | int(paletted.ColorIndexAt(x, y))
310 c++
311 if c == 8/bitdepth {
312 fmt.Fprintf(w, "%02x", b)
313 b = 0
314 c = 0
315 }
316 }
317 if c != 0 {
318 for c != 8/bitdepth {
319 b = b << uint(bitdepth)
320 c++
321 }
322 fmt.Fprintf(w, "%02x", b)
323 }
324 }
325 io.WriteString(w, "\n")
326 }
327 io.WriteString(w, "}\n")
328 }
329
330 func TestReader(t *testing.T) {
331 names := filenames
332 if testing.Short() {
333 names = filenamesShort
334 }
335 for _, fn := range names {
336
337 img, err := readPNG("testdata/pngsuite/" + fn + ".png")
338 if err != nil {
339 t.Error(fn, err)
340 continue
341 }
342
343 if fn == "basn4a16" {
344
345
346 c := img.At(2, 1).(color.NRGBA64)
347 if c.R != 0x11a7 || c.G != 0x11a7 || c.B != 0x11a7 || c.A != 0x1085 {
348 t.Error(fn, fmt.Errorf("wrong pixel value at (2, 1): %x", c))
349 }
350 continue
351 }
352
353 piper, pipew := io.Pipe()
354 pb := bufio.NewScanner(piper)
355 go sng(pipew, fn, img)
356 defer piper.Close()
357
358
359 sf, err := os.Open("testdata/pngsuite/" + fn + ".sng")
360 if err != nil {
361 t.Error(fn, err)
362 continue
363 }
364 defer sf.Close()
365 sb := bufio.NewScanner(sf)
366
367
368 for {
369 pdone := !pb.Scan()
370 sdone := !sb.Scan()
371 if pdone && sdone {
372 break
373 }
374 if pdone || sdone {
375 t.Errorf("%s: Different sizes", fn)
376 break
377 }
378 ps := pb.Text()
379 ss := sb.Text()
380
381
382
383
384
385
386
387
388
389 if strings.Contains(ss, "# rgb = (") && !strings.HasSuffix(ss, ")") {
390 if i := strings.LastIndex(ss, ") "); i >= 0 {
391 ss = ss[:i+1]
392 }
393 }
394
395 if ps != ss {
396 t.Errorf("%s: Mismatch\n%s\nversus\n%s\n", fn, ps, ss)
397 break
398 }
399 }
400 if pb.Err() != nil {
401 t.Error(fn, pb.Err())
402 }
403 if sb.Err() != nil {
404 t.Error(fn, sb.Err())
405 }
406 }
407 }
408
409 var readerErrors = []struct {
410 file string
411 err string
412 }{
413 {"invalid-zlib.png", "zlib: invalid checksum"},
414 {"invalid-crc32.png", "invalid checksum"},
415 {"invalid-noend.png", "unexpected EOF"},
416 {"invalid-trunc.png", "unexpected EOF"},
417 }
418
419 func TestReaderError(t *testing.T) {
420 for _, tt := range readerErrors {
421 img, err := readPNG("testdata/" + tt.file)
422 if err == nil {
423 t.Errorf("decoding %s: missing error", tt.file)
424 continue
425 }
426 if !strings.Contains(err.Error(), tt.err) {
427 t.Errorf("decoding %s: %s, want %s", tt.file, err, tt.err)
428 }
429 if img != nil {
430 t.Errorf("decoding %s: have image + error", tt.file)
431 }
432 }
433 }
434
435 func TestPalettedDecodeConfig(t *testing.T) {
436 for _, fn := range filenamesPaletted {
437 f, err := os.Open("testdata/pngsuite/" + fn + ".png")
438 if err != nil {
439 t.Errorf("%s: open failed: %v", fn, err)
440 continue
441 }
442 defer f.Close()
443 cfg, err := DecodeConfig(f)
444 if err != nil {
445 t.Errorf("%s: %v", fn, err)
446 continue
447 }
448 pal, ok := cfg.ColorModel.(color.Palette)
449 if !ok {
450 t.Errorf("%s: expected paletted color model", fn)
451 continue
452 }
453 if pal == nil {
454 t.Errorf("%s: palette not initialized", fn)
455 continue
456 }
457 }
458 }
459
460 func TestInterlaced(t *testing.T) {
461 a, err := readPNG("testdata/gray-gradient.png")
462 if err != nil {
463 t.Fatal(err)
464 }
465 b, err := readPNG("testdata/gray-gradient.interlaced.png")
466 if err != nil {
467 t.Fatal(err)
468 }
469 if !reflect.DeepEqual(a, b) {
470 t.Fatalf("decodings differ:\nnon-interlaced:\n%#v\ninterlaced:\n%#v", a, b)
471 }
472 }
473
474 func TestIncompleteIDATOnRowBoundary(t *testing.T) {
475
476
477
478 const (
479 ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x02\x08\x00\x00\x00\x00\xbc\xea\xe9\xfb"
480 idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
481 iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
482 )
483 _, err := Decode(strings.NewReader(pngHeader + ihdr + idat + iend))
484 if err == nil {
485 t.Fatal("got nil error, want non-nil")
486 }
487 }
488
489 func TestTrailingIDATChunks(t *testing.T) {
490
491
492 const (
493 ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x00\x00\x00\x00\x3a\x7e\x9b\x55"
494 idatWhite = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\xfa\x0f\x08\x00\x00\xff\xff\x01\x05\x01\x02\x5a\xdd\x39\xcd"
495 idatZero = "\x00\x00\x00\x00IDAT\x35\xaf\x06\x1e"
496 iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
497 )
498 _, err := Decode(strings.NewReader(pngHeader + ihdr + idatWhite + idatZero + iend))
499 if err != nil {
500 t.Fatalf("decoding valid image: %v", err)
501 }
502
503
504
505 const idatBlack = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
506
507 img, err := Decode(strings.NewReader(pngHeader + ihdr + idatWhite + idatBlack + iend))
508 if err != nil {
509 t.Fatalf("trailing IDAT not ignored: %v", err)
510 }
511 if img.At(0, 0) == (color.Gray{0}) {
512 t.Fatal("decoded image from trailing IDAT chunk")
513 }
514 }
515
516 func TestMultipletRNSChunks(t *testing.T) {
517
529 const (
530 ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x03\x00\x00\x00\x28\xcb\x34\xbb"
531 plte = "\x00\x00\x00\x03PLTE\xff\x00\x00\x19\xe2\x09\x37"
532 trns = "\x00\x00\x00\x01tRNS\x7f\x80\x5c\xb4\xcb"
533 idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
534 iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
535 )
536 for i := 0; i < 4; i++ {
537 var b []byte
538 b = append(b, pngHeader...)
539 b = append(b, ihdr...)
540 b = append(b, plte...)
541 for j := 0; j < i; j++ {
542 b = append(b, trns...)
543 }
544 b = append(b, idat...)
545 b = append(b, iend...)
546
547 var want color.Color
548 m, err := Decode(bytes.NewReader(b))
549 switch i {
550 case 0:
551 if err != nil {
552 t.Errorf("%d tRNS chunks: %v", i, err)
553 continue
554 }
555 want = color.RGBA{0xff, 0x00, 0x00, 0xff}
556 case 1:
557 if err != nil {
558 t.Errorf("%d tRNS chunks: %v", i, err)
559 continue
560 }
561 want = color.NRGBA{0xff, 0x00, 0x00, 0x7f}
562 default:
563 if err == nil {
564 t.Errorf("%d tRNS chunks: got nil error, want non-nil", i)
565 }
566 continue
567 }
568 if got := m.At(0, 0); got != want {
569 t.Errorf("%d tRNS chunks: got %T %v, want %T %v", i, got, got, want, want)
570 }
571 }
572 }
573
574 func TestUnknownChunkLengthUnderflow(t *testing.T) {
575 data := []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0xff, 0xff,
576 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0xf4, 0x7c, 0x55, 0x04, 0x1a,
577 0xd3, 0x11, 0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e, 0x00, 0x00,
578 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf4, 0x7c, 0x55, 0x04, 0x1a,
579 0xd3}
580 _, err := Decode(bytes.NewReader(data))
581 if err == nil {
582 t.Errorf("Didn't fail reading an unknown chunk with length 0xffffffff")
583 }
584 }
585
586 func TestPaletted8OutOfRangePixel(t *testing.T) {
587
588 img, err := readPNG("testdata/invalid-palette.png")
589 if err != nil {
590 t.Errorf("decoding invalid-palette.png: unexpected error %v", err)
591 return
592 }
593
594
595 want := color.RGBA{0x00, 0x00, 0x00, 0xff}
596 if got := img.At(15, 15); got != want {
597 t.Errorf("got %F %v, expected %T %v", got, got, want, want)
598 }
599 }
600
601 func TestGray8Transparent(t *testing.T) {
602
603 m, err := Decode(bytes.NewReader([]byte{
604 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
605 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x85, 0x2c, 0x88,
606 0x80, 0x00, 0x00, 0x00, 0x02, 0x74, 0x52, 0x4e, 0x53, 0x00, 0xff, 0x5b, 0x91, 0x22, 0xb5, 0x00,
607 0x00, 0x00, 0x02, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x00, 0x00, 0x00,
608 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0a, 0xf0, 0x00, 0x00, 0x0a, 0xf0, 0x01, 0x42, 0xac,
609 0x34, 0x98, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd5, 0x04, 0x02, 0x12, 0x11,
610 0x11, 0xf7, 0x65, 0x3d, 0x8b, 0x00, 0x00, 0x00, 0x4f, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63,
611 0xf8, 0xff, 0xff, 0xff, 0xb9, 0xbd, 0x70, 0xf0, 0x8c, 0x01, 0xc8, 0xaf, 0x6e, 0x99, 0x02, 0x05,
612 0xd9, 0x7b, 0xc1, 0xfc, 0x6b, 0xff, 0xa1, 0xa0, 0x87, 0x30, 0xff, 0xd9, 0xde, 0xbd, 0xd5, 0x4b,
613 0xf7, 0xee, 0xfd, 0x0e, 0xe3, 0xef, 0xcd, 0x06, 0x19, 0x14, 0xf5, 0x1e, 0xce, 0xef, 0x01, 0x31,
614 0x92, 0xd7, 0x82, 0x41, 0x31, 0x9c, 0x3f, 0x07, 0x02, 0xee, 0xa1, 0xaa, 0xff, 0xff, 0x9f, 0xe1,
615 0xd9, 0x56, 0x30, 0xf8, 0x0e, 0xe5, 0x03, 0x00, 0xa9, 0x42, 0x84, 0x3d, 0xdf, 0x8f, 0xa6, 0x8f,
616 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
617 }))
618 if err != nil {
619 t.Fatalf("Decode: %v", err)
620 }
621
622 const hex = "0123456789abcdef"
623 var got []byte
624 bounds := m.Bounds()
625 for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
626 for x := bounds.Min.X; x < bounds.Max.X; x++ {
627 if r, _, _, a := m.At(x, y).RGBA(); a != 0 {
628 got = append(got,
629 hex[0x0f&(r>>12)],
630 hex[0x0f&(r>>8)],
631 ' ',
632 )
633 } else {
634 got = append(got,
635 '.',
636 '.',
637 ' ',
638 )
639 }
640 }
641 got = append(got, '\n')
642 }
643
644 const want = "" +
645 ".. .. .. ce bd bd bd bd bd bd bd bd bd bd e6 \n" +
646 ".. .. .. 7b 84 94 94 94 94 94 94 94 94 6b bd \n" +
647 ".. .. .. 7b d6 .. .. .. .. .. .. .. .. 8c bd \n" +
648 ".. .. .. 7b d6 .. .. .. .. .. .. .. .. 8c bd \n" +
649 ".. .. .. 7b d6 .. .. .. .. .. .. .. .. 8c bd \n" +
650 "e6 bd bd 7b a5 bd bd f7 .. .. .. .. .. 8c bd \n" +
651 "bd 6b 94 94 94 94 5a ef .. .. .. .. .. 8c bd \n" +
652 "bd 8c .. .. .. .. 63 ad ad ad ad ad ad 73 bd \n" +
653 "bd 8c .. .. .. .. 63 9c 9c 9c 9c 9c 9c 9c de \n" +
654 "bd 6b 94 94 94 94 5a ef .. .. .. .. .. .. .. \n" +
655 "e6 b5 b5 b5 b5 b5 b5 f7 .. .. .. .. .. .. .. \n"
656
657 if string(got) != want {
658 t.Errorf("got:\n%swant:\n%s", got, want)
659 }
660 }
661
662 func TestDimensionOverflow(t *testing.T) {
663 maxInt32AsInt := int((1 << 31) - 1)
664 have32BitInts := 0 > (1 + maxInt32AsInt)
665
666 testCases := []struct {
667 src []byte
668 unsupportedConfig bool
669 width int
670 height int
671 }{
672
673
674
675
676
677 {
678 src: []byte{
679 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
680 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x08, 0x06, 0x00, 0x00, 0x00, 0x30, 0x57, 0xb3,
681 0xfd, 0x00, 0x00, 0x00, 0x15, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x62, 0x62, 0x20, 0x12, 0x8c,
682 0x2a, 0xa4, 0xb3, 0x42, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x13, 0x38, 0x00, 0x15, 0x2d, 0xef,
683 0x5f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
684 },
685
686
687
688
689 unsupportedConfig: true,
690 width: 0x7ffffffe,
691 height: 0x7ffffffe,
692 },
693
694
695
696 {
697 src: []byte{
698 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
699 0x00, 0x00, 0xb5, 0x04, 0x00, 0x00, 0xb5, 0x04, 0x08, 0x06, 0x00, 0x00, 0x00, 0xf5, 0x60, 0x2c,
700 0xb8, 0x00, 0x00, 0x00, 0x15, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x62, 0x62, 0x20, 0x12, 0x8c,
701 0x2a, 0xa4, 0xb3, 0x42, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x13, 0x38, 0x00, 0x15, 0x2d, 0xef,
702 0x5f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
703 },
704
705
706 unsupportedConfig: have32BitInts,
707 width: 0x0000b504,
708 height: 0x0000b504,
709 },
710
711 {
712 src: []byte{
713 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
714 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x00, 0x00, 0x30, 0x6e, 0xc5,
715 0x21, 0x00, 0x00, 0x00, 0x15, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x62, 0x62, 0x20, 0x12, 0x8c,
716 0x2a, 0xa4, 0xb3, 0x42, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x13, 0x38, 0x00, 0x15, 0x2d, 0xef,
717 0x5f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
718 },
719 unsupportedConfig: false,
720 width: 0x04000000,
721 height: 0x00000001,
722 },
723
724 {
725 src: []byte{
726 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
727 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x00, 0x00, 0xaa, 0xd4, 0x7c,
728 0xda, 0x00, 0x00, 0x00, 0x15, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x62, 0x66, 0x20, 0x12, 0x30,
729 0x8d, 0x2a, 0xa4, 0xaf, 0x42, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x14, 0xd2, 0x00, 0x16, 0x00,
730 0x00, 0x00,
731 },
732 unsupportedConfig: false,
733 width: 0x08000000,
734 height: 0x00000001,
735 },
736 }
737
738 for i, tc := range testCases {
739 cfg, err := DecodeConfig(bytes.NewReader(tc.src))
740 if tc.unsupportedConfig {
741 if err == nil {
742 t.Errorf("i=%d: DecodeConfig: got nil error, want non-nil", i)
743 } else if _, ok := err.(UnsupportedError); !ok {
744 t.Fatalf("Decode: got %v (of type %T), want non-nil error (of type png.UnsupportedError)", err, err)
745 }
746 continue
747 } else if err != nil {
748 t.Errorf("i=%d: DecodeConfig: %v", i, err)
749 continue
750 } else if cfg.Width != tc.width {
751 t.Errorf("i=%d: width: got %d, want %d", i, cfg.Width, tc.width)
752 continue
753 } else if cfg.Height != tc.height {
754 t.Errorf("i=%d: height: got %d, want %d", i, cfg.Height, tc.height)
755 continue
756 }
757
758 if nPixels := int64(cfg.Width) * int64(cfg.Height); nPixels > 0x7f000000 {
759
760
761
762
763
764 continue
765 } else if testing.Short() {
766
767
768
769
770
771
772 continue
773 }
774
775
776 if _, err := Decode(bytes.NewReader(tc.src)); err == nil {
777 t.Errorf("i=%d: Decode: got nil error, want non-nil", i)
778 }
779 }
780
781 if testing.Short() {
782 t.Skip("skipping tests which allocate large pixel buffers")
783 }
784 }
785
786 func TestDecodePalettedWithTransparency(t *testing.T) {
787
788
789
790
791
792
793
794
795
796
797 src := []byte{
798 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
799 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x04, 0x03, 0x00, 0x00, 0x00, 0x81, 0x54, 0x67,
800 0xc7, 0x00, 0x00, 0x00, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0e,
801 0x00, 0x23, 0x27, 0x7b, 0xb1, 0x2d, 0x0a, 0x49, 0x3f, 0x19, 0x78, 0x5f, 0xcd, 0xe4, 0x69, 0x69,
802 0xe4, 0x71, 0x59, 0x53, 0x80, 0x11, 0x14, 0x8b, 0x00, 0xa9, 0x8d, 0x95, 0xcb, 0x99, 0x2f, 0x6b,
803 0xd7, 0x29, 0x91, 0xd7, 0x7b, 0xba, 0xff, 0xe3, 0xd7, 0x13, 0xc6, 0xd3, 0x58, 0x00, 0x00, 0x00,
804 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, 0x66, 0x00, 0x00, 0x00, 0xfd, 0x49, 0x44,
805 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x00, 0x83, 0x55, 0x0c, 0x68, 0x60, 0x9d, 0x02, 0x9a, 0x80,
806 0xde, 0x23, 0x74, 0x15, 0xef, 0x50, 0x94, 0x70, 0x2d, 0xd2, 0x7b, 0x87, 0xa2, 0x84, 0xeb, 0xee,
807 0xbb, 0x77, 0x6f, 0x51, 0x94, 0xe8, 0xbd, 0x7d, 0xf7, 0xee, 0x12, 0xb2, 0x80, 0xd2, 0x3d, 0x54,
808 0x01, 0x26, 0x10, 0x1f, 0x59, 0x40, 0x0f, 0xc8, 0xd7, 0x7e, 0x84, 0x70, 0x1c, 0xd7, 0xba, 0xb7,
809 0x4a, 0xda, 0xda, 0x77, 0x11, 0xf6, 0xac, 0x5a, 0xa5, 0xf4, 0xf9, 0xbf, 0xfd, 0x3d, 0x24, 0x6b,
810 0x98, 0x94, 0xf4, 0xff, 0x7f, 0x52, 0x42, 0x16, 0x30, 0x0e, 0xd9, 0xed, 0x6a, 0x8c, 0xec, 0x10,
811 0x65, 0x53, 0x97, 0x60, 0x23, 0x64, 0x1d, 0x8a, 0x2e, 0xc6, 0x2e, 0x42, 0x08, 0x3d, 0x4c, 0xca,
812 0x81, 0xc1, 0x82, 0xa6, 0xa2, 0x46, 0x08, 0x3d, 0x4a, 0xa1, 0x82, 0xc6, 0x82, 0xa1, 0x4a, 0x08,
813 0x3d, 0xfa, 0xa6, 0x81, 0xa1, 0xa2, 0xc1, 0x9f, 0x10, 0x66, 0xd4, 0x2b, 0x87, 0x0a, 0x86, 0x1a,
814 0x7d, 0x57, 0x80, 0x9b, 0x99, 0xaf, 0x62, 0x1a, 0x1a, 0xec, 0xf0, 0x0d, 0x66, 0x2a, 0x7b, 0x5a,
815 0xba, 0xd2, 0x64, 0x63, 0x4b, 0xa6, 0xb2, 0xb4, 0x02, 0xa8, 0x12, 0xb5, 0x24, 0xa5, 0x99, 0x2e,
816 0x33, 0x95, 0xd4, 0x92, 0x10, 0xee, 0xd0, 0x59, 0xb9, 0x6a, 0xd6, 0x21, 0x24, 0xb7, 0x33, 0x9d,
817 0x01, 0x01, 0x64, 0xbf, 0xac, 0x59, 0xb2, 0xca, 0xeb, 0x14, 0x92, 0x80, 0xd6, 0x9a, 0x53, 0x4a,
818 0x6b, 0x4e, 0x2d, 0x42, 0x52, 0xa1, 0x73, 0x28, 0x54, 0xe7, 0x90, 0x6a, 0x00, 0x92, 0x92, 0x45,
819 0xa1, 0x40, 0x84, 0x2c, 0xe0, 0xc4, 0xa0, 0xb2, 0x28, 0x14, 0xc1, 0x67, 0xe9, 0x50, 0x60, 0x60,
820 0xea, 0x70, 0x40, 0x12, 0x00, 0x79, 0x54, 0x09, 0x22, 0x00, 0x00, 0x30, 0xf3, 0x52, 0x87, 0xc6,
821 0xe4, 0xbd, 0x70, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
822 }
823
824 cfg, err := DecodeConfig(bytes.NewReader(src))
825 if err != nil {
826 t.Fatalf("DecodeConfig: %v", err)
827 } else if _, _, _, alpha := cfg.ColorModel.(color.Palette)[0].RGBA(); alpha != 0 {
828 t.Errorf("DecodeConfig: got %d, want 0", alpha)
829 }
830
831 img, err := Decode(bytes.NewReader(src))
832 if err != nil {
833 t.Fatalf("Decode: %v", err)
834 } else if _, _, _, alpha := img.ColorModel().(color.Palette)[0].RGBA(); alpha != 0 {
835 t.Errorf("Decode: got %d, want 0", alpha)
836 }
837 }
838
839 func benchmarkDecode(b *testing.B, filename string, bytesPerPixel int) {
840 data, err := os.ReadFile(filename)
841 if err != nil {
842 b.Fatal(err)
843 }
844 cfg, err := DecodeConfig(bytes.NewReader(data))
845 if err != nil {
846 b.Fatal(err)
847 }
848 b.SetBytes(int64(cfg.Width * cfg.Height * bytesPerPixel))
849 b.ReportAllocs()
850 b.ResetTimer()
851 for i := 0; i < b.N; i++ {
852 Decode(bytes.NewReader(data))
853 }
854 }
855
856 func BenchmarkDecodeGray(b *testing.B) {
857 benchmarkDecode(b, "testdata/benchGray.png", 1)
858 }
859
860 func BenchmarkDecodeNRGBAGradient(b *testing.B) {
861 benchmarkDecode(b, "testdata/benchNRGBA-gradient.png", 4)
862 }
863
864 func BenchmarkDecodeNRGBAOpaque(b *testing.B) {
865 benchmarkDecode(b, "testdata/benchNRGBA-opaque.png", 4)
866 }
867
868 func BenchmarkDecodePaletted(b *testing.B) {
869 benchmarkDecode(b, "testdata/benchPaletted.png", 1)
870 }
871
872 func BenchmarkDecodeRGB(b *testing.B) {
873 benchmarkDecode(b, "testdata/benchRGB.png", 4)
874 }
875
876 func BenchmarkDecodeInterlacing(b *testing.B) {
877 benchmarkDecode(b, "testdata/benchRGB-interlace.png", 4)
878 }
879
View as plain text