src/pkg/image/png/reader.go - The Go Programming Language

Golang

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