The Go Programming Language

Source file src/pkg/image/png/reader.go

     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 implements a PNG image decoder and encoder.
     6	//
     7	// The PNG specification is at http://www.libpng.org/pub/png/spec/1.2/PNG-Contents.html
     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	// Color type, as per the PNG spec.
    21	const (
    22		ctGrayscale      = 0
    23		ctTrueColor      = 2
    24		ctPaletted       = 3
    25		ctGrayscaleAlpha = 4
    26		ctTrueColorAlpha = 6
    27	)
    28	
    29	// A cb is a combination of color type and bit depth.
    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	// Filter type, as per the PNG spec.
    50	const (
    51		ftNone    = 0
    52		ftSub     = 1
    53		ftUp      = 2
    54		ftAverage = 3
    55		ftPaeth   = 4
    56		nFilter   = 5
    57	)
    58	
    59	// Decoding stage.
    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
    63	// between them).
    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	// A FormatError reports that the input is not a valid PNG.
    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	// An IDATDecodingError wraps an inner error (such as a ZLIB decoding error) encountered while processing an IDAT chunk.
    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	// An UnsupportedError reports that the input uses a valid but unimplemented PNG feature.
   105	type UnsupportedError string
   106	
   107	func (e UnsupportedError) String() string { return "png: unsupported feature: " + string(e) }
   108	
   109	// Big-endian.
   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) // 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")
   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			// 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).
   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	// 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 {
   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		// 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)
   335	
   336		for y := 0; y < d.height; y++ {
   337			// Read the decompressed bytes.
   338			_, err := io.ReadFull(r, cr)
   339			if err != nil {
   340				return nil, err
   341			}
   342	
   343			// Apply the filter.
   344			cdat := cr[1:]
   345			pdat := pr[1:]
   346			switch cr[0] {
   347			case ftNone:
   348				// No-op.
   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			// Convert from bytes to colors.
   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			// The current row for y is the previous row for y+1.
   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		// 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 {
   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			// 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])
   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		// Read the length.
   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		// Read the chunk type.
   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		// Read the chunk data.
   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			// Ignore this chunk (of a known length).
   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		// Read the checksum.
   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	// 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) {
   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	// 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) {
   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	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.