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 implements a PNG image decoder and encoder.
7 // The PNG specification is at http://www.libpng.org/pub/png/spec/1.2/PNG-Contents.html
20 // Color type, as per the PNG spec.
29 // A cb is a combination of color type and bit depth.
49 // Filter type, as per the PNG spec.
60 // The PNG specification says that the IHDR, PLTE (if present), IDAT and IEND
61 // chunks must appear in that order. There may be multiple IDAT chunks, and
62 // IDAT chunks must be sequential (i.e. they may not have any other chunks
72 const pngHeader = "\x89PNG\r\n\x1a\n"
74 type imgOrErr struct {
82 palette image.PalettedColorModel
85 idatWriter io.WriteCloser
86 idatDone chan imgOrErr
90 // A FormatError reports that the input is not a valid PNG.
91 type FormatError string
93 func (e FormatError) String() string { return "png: invalid format: " + string(e) }
95 var chunkOrderError = FormatError("chunk out of order")
97 // An IDATDecodingError wraps an inner error (such as a ZLIB decoding error) encountered while processing an IDAT chunk.
98 type IDATDecodingError struct {
102 func (e IDATDecodingError) String() string { return "png: IDAT decoding error: " + e.Err.String() }
104 // An UnsupportedError reports that the input uses a valid but unimplemented PNG feature.
105 type UnsupportedError string
107 func (e UnsupportedError) String() string { return "png: unsupported feature: " + string(e) }
110 func parseUint32(b []uint8) uint32 {
111 return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
114 func abs(x int) int {
121 func min(a, b int) int {
128 func (d *decoder) parseIHDR(r io.Reader, crc hash.Hash32, length uint32) os.Error {
130 return FormatError("bad IHDR length")
132 _, err := io.ReadFull(r, d.tmp[0:13])
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")
140 w := int32(parseUint32(d.tmp[0:4]))
141 h := int32(parseUint32(d.tmp[4:8]))
143 return FormatError("negative dimension")
145 nPixels := int64(w) * int64(h)
146 if nPixels != int64(int(nPixels)) {
147 return UnsupportedError("dimension overflow")
150 d.depth = int(d.tmp[8])
181 case ctGrayscaleAlpha:
183 case ctTrueColorAlpha:
192 case ctGrayscaleAlpha:
194 case ctTrueColorAlpha:
198 if d.cb == cbInvalid {
199 return UnsupportedError(fmt.Sprintf("bit depth %d, color type %d", d.tmp[8], d.tmp[9]))
201 d.width, d.height = int(w), int(h)
205 func (d *decoder) parsePLTE(r io.Reader, crc hash.Hash32, length uint32) os.Error {
206 np := int(length / 3) // The number of palette entries.
207 if length%3 != 0 || np <= 0 || np > 256 || np > 1<<uint(d.depth) {
208 return FormatError("bad PLTE length")
210 n, err := io.ReadFull(r, d.tmp[0:3*np])
214 crc.Write(d.tmp[0:n])
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}
221 case cbTC8, cbTCA8, cbTC16, cbTCA16:
222 // As per the PNG spec, a PLTE chunk is optional (and for practical purposes,
223 // ignorable) for the ctTrueColor and ctTrueColorAlpha color types (section 4.1.2).
225 return FormatError("PLTE, color type mismatch")
230 func (d *decoder) parsetRNS(r io.Reader, crc hash.Hash32, length uint32) os.Error {
232 return FormatError("bad tRNS length")
234 n, err := io.ReadFull(r, d.tmp[0:length])
238 crc.Write(d.tmp[0:n])
241 return UnsupportedError("grayscale transparency")
243 return UnsupportedError("truecolor transparency")
244 case cbP1, cbP2, cbP4, cbP8:
245 if n > len(d.palette) {
246 return FormatError("bad tRNS length")
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]}
252 case cbGA8, cbGA16, cbTCA8, cbTCA16:
253 return FormatError("tRNS, color type mismatch")
258 // The Paeth filter function, as per the PNG specification.
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 {
272 func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
273 r, err := zlib.NewReader(idat)
279 maxPalette := uint8(0)
283 paletted *image.Paletted
287 nrgba64 *image.NRGBA64
291 case cbG1, cbG2, cbG4, cbG8:
292 bitsPerPixel = d.depth
293 gray = image.NewGray(d.width, d.height)
297 nrgba = image.NewNRGBA(d.width, d.height)
301 rgba = image.NewRGBA(d.width, d.height)
303 case cbP1, cbP2, cbP4, cbP8:
304 bitsPerPixel = d.depth
305 paletted = image.NewPaletted(d.width, d.height, d.palette)
307 maxPalette = uint8(len(d.palette) - 1)
310 nrgba = image.NewNRGBA(d.width, d.height)
314 gray16 = image.NewGray16(d.width, d.height)
318 nrgba64 = image.NewNRGBA64(d.width, d.height)
322 rgba64 = image.NewRGBA64(d.width, d.height)
326 nrgba64 = image.NewNRGBA64(d.width, d.height)
329 bytesPerPixel := (bitsPerPixel + 7) / 8
331 // cr and pr are the bytes for the current and previous row.
332 // The +1 is for the per-row filter type, which is at cr[0].
333 cr := make([]uint8, 1+(bitsPerPixel*d.width+7)/8)
334 pr := make([]uint8, 1+(bitsPerPixel*d.width+7)/8)
336 for y := 0; y < d.height; y++ {
337 // Read the decompressed bytes.
338 _, err := io.ReadFull(r, cr)
350 for i := bytesPerPixel; i < len(cdat); i++ {
351 cdat[i] += cdat[i-bytesPerPixel]
354 for i := 0; i < len(cdat); i++ {
358 for i := 0; i < bytesPerPixel; i++ {
359 cdat[i] += pdat[i] / 2
361 for i := bytesPerPixel; i < len(cdat); i++ {
362 cdat[i] += uint8((int(cdat[i-bytesPerPixel]) + int(pdat[i])) / 2)
365 for i := 0; i < bytesPerPixel; i++ {
366 cdat[i] += paeth(0, pdat[i], 0)
368 for i := bytesPerPixel; i < len(cdat); i++ {
369 cdat[i] += paeth(cdat[i-bytesPerPixel], pdat[i], pdat[i-bytesPerPixel])
372 return nil, FormatError("bad filter type")
375 // Convert from bytes to colors.
378 for x := 0; x < d.width; x += 8 {
380 for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ {
381 gray.SetGray(x+x2, y, image.GrayColor{(b >> 7) * 0xff})
386 for x := 0; x < d.width; x += 4 {
388 for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ {
389 gray.SetGray(x+x2, y, image.GrayColor{(b >> 6) * 0x55})
394 for x := 0; x < d.width; x += 2 {
396 for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ {
397 gray.SetGray(x+x2, y, image.GrayColor{(b >> 4) * 0x11})
402 for x := 0; x < d.width; x++ {
403 gray.SetGray(x, y, image.GrayColor{cdat[x]})
406 for x := 0; x < d.width; x++ {
408 nrgba.SetNRGBA(x, y, image.NRGBAColor{ycol, ycol, ycol, cdat[2*x+1]})
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})
415 for x := 0; x < d.width; x += 8 {
417 for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ {
419 if idx > maxPalette {
420 return nil, FormatError("palette index out of range")
422 paletted.SetColorIndex(x+x2, y, idx)
427 for x := 0; x < d.width; x += 4 {
429 for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ {
431 if idx > maxPalette {
432 return nil, FormatError("palette index out of range")
434 paletted.SetColorIndex(x+x2, y, idx)
439 for x := 0; x < d.width; x += 2 {
441 for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ {
443 if idx > maxPalette {
444 return nil, FormatError("palette index out of range")
446 paletted.SetColorIndex(x+x2, y, idx)
451 for x := 0; x < d.width; x++ {
452 if cdat[x] > maxPalette {
453 return nil, FormatError("palette index out of range")
455 paletted.SetColorIndex(x, y, cdat[x])
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]})
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})
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})
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})
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})
489 // The current row for y is the previous row for y+1.
495 func (d *decoder) parseIDAT(r io.Reader, crc hash.Hash32, length uint32) os.Error {
496 // There may be more than one IDAT chunk, but their contents must be
497 // treated as if it was one continuous stream (to the zlib decoder).
498 // We bring up an io.Pipe and write the IDAT chunks into the pipe as
499 // we see them, and decode the stream in a separate go-routine, which
500 // signals its completion (successful or not) via a channel.
501 if d.idatWriter == nil {
504 d.idatDone = make(chan imgOrErr)
506 img, err := d.idatReader(pr)
508 err = FormatError("too little IDAT")
510 pr.CloseWithError(FormatError("too much IDAT"))
511 d.idatDone <- imgOrErr{img, err}
516 n, err1 := r.Read(buf[0:min(len(buf), int(length))])
517 // We delay checking err1. It is possible to get n bytes and an error,
518 // but if the n bytes themselves contain a FormatError, for example, we
519 // want to report that error, and not the one that made the Read stop.
520 n, err2 := d.idatWriter.Write(buf[0:n])
533 func (d *decoder) parseIEND(r io.Reader, crc hash.Hash32, length uint32) os.Error {
535 return FormatError("bad IEND length")
540 func (d *decoder) parseChunk(r io.Reader) os.Error {
542 n, err := io.ReadFull(r, d.tmp[0:4])
544 return io.ErrUnexpectedEOF
549 length := parseUint32(d.tmp[0:4])
551 // Read the chunk type.
552 n, err = io.ReadFull(r, d.tmp[0:4])
554 return io.ErrUnexpectedEOF
559 crc := crc32.NewIEEE()
560 crc.Write(d.tmp[0:4])
562 // Read the chunk data.
563 switch string(d.tmp[0:4]) {
565 if d.stage != dsStart {
566 return chunkOrderError
569 err = d.parseIHDR(r, crc, length)
571 if d.stage != dsSeenIHDR {
572 return chunkOrderError
575 err = d.parsePLTE(r, crc, length)
577 if d.stage != dsSeenPLTE {
578 return chunkOrderError
580 err = d.parsetRNS(r, crc, length)
582 if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) {
583 return chunkOrderError
586 err = d.parseIDAT(r, crc, length)
588 if d.stage != dsSeenIDAT {
589 return chunkOrderError
592 err = d.parseIEND(r, crc, length)
594 // Ignore this chunk (of a known length).
595 var ignored [4096]byte
597 n, err = io.ReadFull(r, ignored[0:min(len(ignored), int(length))])
601 crc.Write(ignored[0:n])
609 // Read the checksum.
610 n, err = io.ReadFull(r, d.tmp[0:4])
612 return io.ErrUnexpectedEOF
617 if parseUint32(d.tmp[0:4]) != crc.Sum32() {
618 return FormatError("invalid checksum")
623 func (d *decoder) checkHeader(r io.Reader) os.Error {
624 _, err := io.ReadFull(r, d.tmp[0:8])
628 if string(d.tmp[0:8]) != pngHeader {
629 return FormatError("not a PNG file")
634 // Decode reads a PNG image from r and returns it as an image.Image.
635 // The type of Image returned depends on the PNG contents.
636 func Decode(r io.Reader) (image.Image, os.Error) {
638 err := d.checkHeader(r)
642 for d.stage != dsSeenIEND {
643 err = d.parseChunk(r)
649 if d.idatWriter != nil {
653 img, err = ie.img, ie.err
662 // DecodeConfig returns the color model and dimensions of a PNG image without
663 // decoding the entire image.
664 func DecodeConfig(r io.Reader) (image.Config, os.Error) {
666 err := d.checkHeader(r)
668 return image.Config{}, err
671 err = d.parseChunk(r)
673 return image.Config{}, err
675 if d.stage == dsSeenIHDR && d.cb != cbP8 {
678 if d.stage == dsSeenPLTE && d.cb == cbP8 {
682 var cm image.ColorModel
684 case cbG1, cbG2, cbG4, cbG8:
685 cm = image.GrayColorModel
687 cm = image.NRGBAColorModel
689 cm = image.RGBAColorModel
690 case cbP1, cbP2, cbP4, cbP8:
693 cm = image.NRGBAColorModel
695 cm = image.Gray16ColorModel
697 cm = image.NRGBA64ColorModel
699 cm = image.RGBA64ColorModel
701 cm = image.NRGBA64ColorModel
703 return image.Config{cm, d.width, d.height}, nil
707 image.RegisterFormat("png", pngHeader, Decode, DecodeConfig)