1
2
3
4
5
6
7
8 package png
9
10 import (
11 "compress/zlib"
12 "fmt"
13 "hash"
14 "hash/crc32"
15 "image"
16 "io"
17 "os"
18 )
19
20
21 const (
22 ctGrayscale = 0
23 ctTrueColor = 2
24 ctPaletted = 3
25 ctGrayscaleAlpha = 4
26 ctTrueColorAlpha = 6
27 )
28
29
30 const (
31 cbInvalid = iota
32 cbG1
33 cbG2
34 cbG4
35 cbG8
36 cbGA8
37 cbTC8
38 cbP1
39 cbP2
40 cbP4
41 cbP8
42 cbTCA8
43 cbG16
44 cbGA16
45 cbTC16
46 cbTCA16
47 )
48
49
50 const (
51 ftNone = 0
52 ftSub = 1
53 ftUp = 2
54 ftAverage = 3
55 ftPaeth = 4
56 nFilter = 5
57 )
58
59
60
61
62
63
64 const (
65 dsStart = iota
66 dsSeenIHDR
67 dsSeenPLTE
68 dsSeenIDAT
69 dsSeenIEND
70 )
71
72 const pngHeader = "\x89PNG\r\n\x1a\n"
73
74 type imgOrErr struct {
75 img image.Image
76 err os.Error
77 }
78
79 type decoder struct {
80 width, height int
81 depth int
82 palette image.PalettedColorModel
83 cb int
84 stage int
85 idatWriter io.WriteCloser
86 idatDone chan imgOrErr
87 tmp [3 * 256]byte
88 }
89
90
91 type FormatError string
92
93 func (e FormatError) String() string { return "png: invalid format: " + string(e) }
94
95 var chunkOrderError = FormatError("chunk out of order")
96
97
98 type IDATDecodingError struct {
99 Err os.Error
100 }
101
102 func (e IDATDecodingError) String() string { return "png: IDAT decoding error: " + e.Err.String() }
103
104
105 type UnsupportedError string
106
107 func (e UnsupportedError) String() string { return "png: unsupported feature: " + string(e) }
108
109
110 func parseUint32(b []uint8) uint32 {
111 return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
112 }
113
114 func abs(x int) int {
115 if x < 0 {
116 return -x
117 }
118 return x
119 }
120
121 func min(a, b int) int {
122 if a < b {
123 return a
124 }
125 return b
126 }
127
128 func (d *decoder) parseIHDR(r io.Reader, crc hash.Hash32, length uint32) os.Error {
129 if length != 13 {
130 return FormatError("bad IHDR length")
131 }
132 _, err := io.ReadFull(r, d.tmp[0:13])
133 if err != nil {
134 return err
135 }
136 crc.Write(d.tmp[0:13])
137 if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 {
138 return UnsupportedError("compression, filter or interlace method")
139 }
140 w := int32(parseUint32(d.tmp[0:4]))
141 h := int32(parseUint32(d.tmp[4:8]))
142 if w < 0 || h < 0 {
143 return FormatError("negative dimension")
144 }
145 nPixels := int64(w) * int64(h)
146 if nPixels != int64(int(nPixels)) {
147 return UnsupportedError("dimension overflow")
148 }
149 d.cb = cbInvalid
150 d.depth = int(d.tmp[8])
151 switch d.depth {
152 case 1:
153 switch d.tmp[9] {
154 case ctGrayscale:
155 d.cb = cbG1
156 case ctPaletted:
157 d.cb = cbP1
158 }
159 case 2:
160 switch d.tmp[9] {
161 case ctGrayscale:
162 d.cb = cbG2
163 case ctPaletted:
164 d.cb = cbP2
165 }
166 case 4:
167 switch d.tmp[9] {
168 case ctGrayscale:
169 d.cb = cbG4
170 case ctPaletted:
171 d.cb = cbP4
172 }
173 case 8:
174 switch d.tmp[9] {
175 case ctGrayscale:
176 d.cb = cbG8
177 case ctTrueColor:
178 d.cb = cbTC8
179 case ctPaletted:
180 d.cb = cbP8
181 case ctGrayscaleAlpha:
182 d.cb = cbGA8
183 case ctTrueColorAlpha:
184 d.cb = cbTCA8
185 }
186 case 16:
187 switch d.tmp[9] {
188 case ctGrayscale:
189 d.cb = cbG16
190 case ctTrueColor:
191 d.cb = cbTC16
192 case ctGrayscaleAlpha:
193 d.cb = cbGA16
194 case ctTrueColorAlpha:
195 d.cb = cbTCA16
196 }
197 }
198 if d.cb == cbInvalid {
199 return UnsupportedError(fmt.Sprintf("bit depth %d, color type %d", d.tmp[8], d.tmp[9]))
200 }
201 d.width, d.height = int(w), int(h)
202 return nil
203 }
204
205 func (d *decoder) parsePLTE(r io.Reader, crc hash.Hash32, length uint32) os.Error {
206 np := int(length / 3)
207 if length%3 != 0 || np <= 0 || np > 256 || np > 1<<uint(d.depth) {
208 return FormatError("bad PLTE length")
209 }
210 n, err := io.ReadFull(r, d.tmp[0:3*np])
211 if err != nil {
212 return err
213 }
214 crc.Write(d.tmp[0:n])
215 switch d.cb {
216 case cbP1, cbP2, cbP4, cbP8:
217 d.palette = image.PalettedColorModel(make([]image.Color, np))
218 for i := 0; i < np; i++ {
219 d.palette[i] = image.RGBAColor{d.tmp[3*i+0], d.tmp[3*i+1], d.tmp[3*i+2], 0xff}
220 }
221 case cbTC8, cbTCA8, cbTC16, cbTCA16:
222
223
224 default:
225 return FormatError("PLTE, color type mismatch")
226 }
227 return nil
228 }
229
230 func (d *decoder) parsetRNS(r io.Reader, crc hash.Hash32, length uint32) os.Error {
231 if length > 256 {
232 return FormatError("bad tRNS length")
233 }
234 n, err := io.ReadFull(r, d.tmp[0:length])
235 if err != nil {
236 return err
237 }
238 crc.Write(d.tmp[0:n])
239 switch d.cb {
240 case cbG8, cbG16:
241 return UnsupportedError("grayscale transparency")
242 case cbTC8, cbTC16:
243 return UnsupportedError("truecolor transparency")
244 case cbP1, cbP2, cbP4, cbP8:
245 if n > len(d.palette) {
246 return FormatError("bad tRNS length")
247 }
248 for i := 0; i < n; i++ {
249 rgba := d.palette[i].(image.RGBAColor)
250 d.palette[i] = image.RGBAColor{rgba.R, rgba.G, rgba.B, d.tmp[i]}
251 }
252 case cbGA8, cbGA16, cbTCA8, cbTCA16:
253 return FormatError("tRNS, color type mismatch")
254 }
255 return nil
256 }
257
258
259 func paeth(a, b, c uint8) uint8 {
260 p := int(a) + int(b) - int(c)
261 pa := abs(p - int(a))
262 pb := abs(p - int(b))
263 pc := abs(p - int(c))
264 if pa <= pb && pa <= pc {
265 return a
266 } else if pb <= pc {
267 return b
268 }
269 return c
270 }
271
272 func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
273 r, err := zlib.NewReader(idat)
274 if err != nil {
275 return nil, err
276 }
277 defer r.Close()
278 bitsPerPixel := 0
279 maxPalette := uint8(0)
280 var (
281 gray *image.Gray
282 rgba *image.RGBA
283 paletted *image.Paletted
284 nrgba *image.NRGBA
285 gray16 *image.Gray16
286 rgba64 *image.RGBA64
287 nrgba64 *image.NRGBA64
288 img image.Image
289 )
290 switch d.cb {
291 case cbG1, cbG2, cbG4, cbG8:
292 bitsPerPixel = d.depth
293 gray = image.NewGray(d.width, d.height)
294 img = gray
295 case cbGA8:
296 bitsPerPixel = 16
297 nrgba = image.NewNRGBA(d.width, d.height)
298 img = nrgba
299 case cbTC8:
300 bitsPerPixel = 24
301 rgba = image.NewRGBA(d.width, d.height)
302 img = rgba
303 case cbP1, cbP2, cbP4, cbP8:
304 bitsPerPixel = d.depth
305 paletted = image.NewPaletted(d.width, d.height, d.palette)
306 img = paletted
307 maxPalette = uint8(len(d.palette) - 1)
308 case cbTCA8:
309 bitsPerPixel = 32
310 nrgba = image.NewNRGBA(d.width, d.height)
311 img = nrgba
312 case cbG16:
313 bitsPerPixel = 16
314 gray16 = image.NewGray16(d.width, d.height)
315 img = gray16
316 case cbGA16:
317 bitsPerPixel = 32
318 nrgba64 = image.NewNRGBA64(d.width, d.height)
319 img = nrgba64
320 case cbTC16:
321 bitsPerPixel = 48
322 rgba64 = image.NewRGBA64(d.width, d.height)
323 img = rgba64
324 case cbTCA16:
325 bitsPerPixel = 64
326 nrgba64 = image.NewNRGBA64(d.width, d.height)
327 img = nrgba64
328 }
329 bytesPerPixel := (bitsPerPixel + 7) / 8
330
331
332
333 cr := make([]uint8, 1+(bitsPerPixel*d.width+7)/8)
334 pr := make([]uint8, 1+(bitsPerPixel*d.width+7)/8)
335
336 for y := 0; y < d.height; y++ {
337
338 _, err := io.ReadFull(r, cr)
339 if err != nil {
340 return nil, err
341 }
342
343
344 cdat := cr[1:]
345 pdat := pr[1:]
346 switch cr[0] {
347 case ftNone:
348
349 case ftSub:
350 for i := bytesPerPixel; i < len(cdat); i++ {
351 cdat[i] += cdat[i-bytesPerPixel]
352 }
353 case ftUp:
354 for i := 0; i < len(cdat); i++ {
355 cdat[i] += pdat[i]
356 }
357 case ftAverage:
358 for i := 0; i < bytesPerPixel; i++ {
359 cdat[i] += pdat[i] / 2
360 }
361 for i := bytesPerPixel; i < len(cdat); i++ {
362 cdat[i] += uint8((int(cdat[i-bytesPerPixel]) + int(pdat[i])) / 2)
363 }
364 case ftPaeth:
365 for i := 0; i < bytesPerPixel; i++ {
366 cdat[i] += paeth(0, pdat[i], 0)
367 }
368 for i := bytesPerPixel; i < len(cdat); i++ {
369 cdat[i] += paeth(cdat[i-bytesPerPixel], pdat[i], pdat[i-bytesPerPixel])
370 }
371 default:
372 return nil, FormatError("bad filter type")
373 }
374
375
376 switch d.cb {
377 case cbG1:
378 for x := 0; x < d.width; x += 8 {
379 b := cdat[x/8]
380 for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ {
381 gray.SetGray(x+x2, y, image.GrayColor{(b >> 7) * 0xff})
382 b <<= 1
383 }
384 }
385 case cbG2:
386 for x := 0; x < d.width; x += 4 {
387 b := cdat[x/4]
388 for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ {
389 gray.SetGray(x+x2, y, image.GrayColor{(b >> 6) * 0x55})
390 b <<= 2
391 }
392 }
393 case cbG4:
394 for x := 0; x < d.width; x += 2 {
395 b := cdat[x/2]
396 for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ {
397 gray.SetGray(x+x2, y, image.GrayColor{(b >> 4) * 0x11})
398 b <<= 4
399 }
400 }
401 case cbG8:
402 for x := 0; x < d.width; x++ {
403 gray.SetGray(x, y, image.GrayColor{cdat[x]})
404 }
405 case cbGA8:
406 for x := 0; x < d.width; x++ {
407 ycol := cdat[2*x+0]
408 nrgba.SetNRGBA(x, y, image.NRGBAColor{ycol, ycol, ycol, cdat[2*x+1]})
409 }
410 case cbTC8:
411 for x := 0; x < d.width; x++ {
412 rgba.SetRGBA(x, y, image.RGBAColor{cdat[3*x+0], cdat[3*x+1], cdat[3*x+2], 0xff})
413 }
414 case cbP1:
415 for x := 0; x < d.width; x += 8 {
416 b := cdat[x/8]
417 for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ {
418 idx := b >> 7
419 if idx > maxPalette {
420 return nil, FormatError("palette index out of range")
421 }
422 paletted.SetColorIndex(x+x2, y, idx)
423 b <<= 1
424 }
425 }
426 case cbP2:
427 for x := 0; x < d.width; x += 4 {
428 b := cdat[x/4]
429 for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ {
430 idx := b >> 6
431 if idx > maxPalette {
432 return nil, FormatError("palette index out of range")
433 }
434 paletted.SetColorIndex(x+x2, y, idx)
435 b <<= 2
436 }
437 }
438 case cbP4:
439 for x := 0; x < d.width; x += 2 {
440 b := cdat[x/2]
441 for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ {
442 idx := b >> 4
443 if idx > maxPalette {
444 return nil, FormatError("palette index out of range")
445 }
446 paletted.SetColorIndex(x+x2, y, idx)
447 b <<= 4
448 }
449 }
450 case cbP8:
451 for x := 0; x < d.width; x++ {
452 if cdat[x] > maxPalette {
453 return nil, FormatError("palette index out of range")
454 }
455 paletted.SetColorIndex(x, y, cdat[x])
456 }
457 case cbTCA8:
458 for x := 0; x < d.width; x++ {
459 nrgba.SetNRGBA(x, y, image.NRGBAColor{cdat[4*x+0], cdat[4*x+1], cdat[4*x+2], cdat[4*x+3]})
460 }
461 case cbG16:
462 for x := 0; x < d.width; x++ {
463 ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
464 gray16.SetGray16(x, y, image.Gray16Color{ycol})
465 }
466 case cbGA16:
467 for x := 0; x < d.width; x++ {
468 ycol := uint16(cdat[4*x+0])<<8 | uint16(cdat[4*x+1])
469 acol := uint16(cdat[4*x+2])<<8 | uint16(cdat[4*x+3])
470 nrgba64.SetNRGBA64(x, y, image.NRGBA64Color{ycol, ycol, ycol, acol})
471 }
472 case cbTC16:
473 for x := 0; x < d.width; x++ {
474 rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
475 gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
476 bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
477 rgba64.SetRGBA64(x, y, image.RGBA64Color{rcol, gcol, bcol, 0xffff})
478 }
479 case cbTCA16:
480 for x := 0; x < d.width; x++ {
481 rcol := uint16(cdat[8*x+0])<<8 | uint16(cdat[8*x+1])
482 gcol := uint16(cdat[8*x+2])<<8 | uint16(cdat[8*x+3])
483 bcol := uint16(cdat[8*x+4])<<8 | uint16(cdat[8*x+5])
484 acol := uint16(cdat[8*x+6])<<8 | uint16(cdat[8*x+7])
485 nrgba64.SetNRGBA64(x, y, image.NRGBA64Color{rcol, gcol, bcol, acol})
486 }
487 }
488
489
490 pr, cr = cr, pr
491 }
492 return img, nil
493 }
494
495 func (d *decoder) parseIDAT(r io.Reader, crc hash.Hash32, length uint32) os.Error {
496
497
498
499
500
501 if d.idatWriter == nil {
502 pr, pw := io.Pipe()
503 d.idatWriter = pw
504 d.idatDone = make(chan imgOrErr)
505 go func() {
506 img, err := d.idatReader(pr)
507 if err == os.EOF {
508 err = FormatError("too little IDAT")
509 }
510 pr.CloseWithError(FormatError("too much IDAT"))
511 d.idatDone <- imgOrErr{img, err}
512 }()
513 }
514 var buf [4096]byte
515 for length > 0 {
516 n, err1 := r.Read(buf[0:min(len(buf), int(length))])
517
518
519
520 n, err2 := d.idatWriter.Write(buf[0:n])
521 if err2 != nil {
522 return err2
523 }
524 if err1 != nil {
525 return err1
526 }
527 crc.Write(buf[0:n])
528 length -= uint32(n)
529 }
530 return nil
531 }
532
533 func (d *decoder) parseIEND(r io.Reader, crc hash.Hash32, length uint32) os.Error {
534 if length != 0 {
535 return FormatError("bad IEND length")
536 }
537 return nil
538 }
539
540 func (d *decoder) parseChunk(r io.Reader) os.Error {
541
542 n, err := io.ReadFull(r, d.tmp[0:4])
543 if err == os.EOF {
544 return io.ErrUnexpectedEOF
545 }
546 if err != nil {
547 return err
548 }
549 length := parseUint32(d.tmp[0:4])
550
551
552 n, err = io.ReadFull(r, d.tmp[0:4])
553 if err == os.EOF {
554 return io.ErrUnexpectedEOF
555 }
556 if err != nil {
557 return err
558 }
559 crc := crc32.NewIEEE()
560 crc.Write(d.tmp[0:4])
561
562
563 switch string(d.tmp[0:4]) {
564 case "IHDR":
565 if d.stage != dsStart {
566 return chunkOrderError
567 }
568 d.stage = dsSeenIHDR
569 err = d.parseIHDR(r, crc, length)
570 case "PLTE":
571 if d.stage != dsSeenIHDR {
572 return chunkOrderError
573 }
574 d.stage = dsSeenPLTE
575 err = d.parsePLTE(r, crc, length)
576 case "tRNS":
577 if d.stage != dsSeenPLTE {
578 return chunkOrderError
579 }
580 err = d.parsetRNS(r, crc, length)
581 case "IDAT":
582 if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) {
583 return chunkOrderError
584 }
585 d.stage = dsSeenIDAT
586 err = d.parseIDAT(r, crc, length)
587 case "IEND":
588 if d.stage != dsSeenIDAT {
589 return chunkOrderError
590 }
591 d.stage = dsSeenIEND
592 err = d.parseIEND(r, crc, length)
593 default:
594
595 var ignored [4096]byte
596 for length > 0 {
597 n, err = io.ReadFull(r, ignored[0:min(len(ignored), int(length))])
598 if err != nil {
599 return err
600 }
601 crc.Write(ignored[0:n])
602 length -= uint32(n)
603 }
604 }
605 if err != nil {
606 return err
607 }
608
609
610 n, err = io.ReadFull(r, d.tmp[0:4])
611 if err == os.EOF {
612 return io.ErrUnexpectedEOF
613 }
614 if err != nil {
615 return err
616 }
617 if parseUint32(d.tmp[0:4]) != crc.Sum32() {
618 return FormatError("invalid checksum")
619 }
620 return nil
621 }
622
623 func (d *decoder) checkHeader(r io.Reader) os.Error {
624 _, err := io.ReadFull(r, d.tmp[0:8])
625 if err != nil {
626 return err
627 }
628 if string(d.tmp[0:8]) != pngHeader {
629 return FormatError("not a PNG file")
630 }
631 return nil
632 }
633
634
635
636 func Decode(r io.Reader) (image.Image, os.Error) {
637 var d decoder
638 err := d.checkHeader(r)
639 if err != nil {
640 return nil, err
641 }
642 for d.stage != dsSeenIEND {
643 err = d.parseChunk(r)
644 if err != nil {
645 break
646 }
647 }
648 var img image.Image
649 if d.idatWriter != nil {
650 d.idatWriter.Close()
651 ie := <-d.idatDone
652 if err == nil {
653 img, err = ie.img, ie.err
654 }
655 }
656 if err != nil {
657 return nil, err
658 }
659 return img, nil
660 }
661
662
663
664 func DecodeConfig(r io.Reader) (image.Config, os.Error) {
665 var d decoder
666 err := d.checkHeader(r)
667 if err != nil {
668 return image.Config{}, err
669 }
670 for {
671 err = d.parseChunk(r)
672 if err != nil {
673 return image.Config{}, err
674 }
675 if d.stage == dsSeenIHDR && d.cb != cbP8 {
676 break
677 }
678 if d.stage == dsSeenPLTE && d.cb == cbP8 {
679 break
680 }
681 }
682 var cm image.ColorModel
683 switch d.cb {
684 case cbG1, cbG2, cbG4, cbG8:
685 cm = image.GrayColorModel
686 case cbGA8:
687 cm = image.NRGBAColorModel
688 case cbTC8:
689 cm = image.RGBAColorModel
690 case cbP1, cbP2, cbP4, cbP8:
691 cm = d.palette
692 case cbTCA8:
693 cm = image.NRGBAColorModel
694 case cbG16:
695 cm = image.Gray16ColorModel
696 case cbGA16:
697 cm = image.NRGBA64ColorModel
698 case cbTC16:
699 cm = image.RGBA64ColorModel
700 case cbTCA16:
701 cm = image.NRGBA64ColorModel
702 }
703 return image.Config{cm, d.width, d.height}, nil
704 }
705
706 func init() {
707 image.RegisterFormat("png", pngHeader, Decode, DecodeConfig)
708 }