...
Run Format

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

View as plain text