github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/image/png/reader.go (about)

     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, err := r.Read(pr[:1])
   509  	if err != io.EOF {
   510  		return nil, FormatError(err.Error())
   511  	}
   512  	if n != 0 || d.idatLength != 0 {
   513  		return nil, FormatError("too much pixel data")
   514  	}
   515  
   516  	return img, nil
   517  }
   518  
   519  func (d *decoder) parseIDAT(length uint32) (err error) {
   520  	d.idatLength = length
   521  	d.img, err = d.decode()
   522  	if err != nil {
   523  		return err
   524  	}
   525  	return d.verifyChecksum()
   526  }
   527  
   528  func (d *decoder) parseIEND(length uint32) error {
   529  	if length != 0 {
   530  		return FormatError("bad IEND length")
   531  	}
   532  	return d.verifyChecksum()
   533  }
   534  
   535  func (d *decoder) parseChunk() error {
   536  	// Read the length and chunk type.
   537  	n, err := io.ReadFull(d.r, d.tmp[:8])
   538  	if err != nil {
   539  		return err
   540  	}
   541  	length := binary.BigEndian.Uint32(d.tmp[:4])
   542  	d.crc.Reset()
   543  	d.crc.Write(d.tmp[4:8])
   544  
   545  	// Read the chunk data.
   546  	switch string(d.tmp[4:8]) {
   547  	case "IHDR":
   548  		if d.stage != dsStart {
   549  			return chunkOrderError
   550  		}
   551  		d.stage = dsSeenIHDR
   552  		return d.parseIHDR(length)
   553  	case "PLTE":
   554  		if d.stage != dsSeenIHDR {
   555  			return chunkOrderError
   556  		}
   557  		d.stage = dsSeenPLTE
   558  		return d.parsePLTE(length)
   559  	case "tRNS":
   560  		if d.stage != dsSeenPLTE {
   561  			return chunkOrderError
   562  		}
   563  		return d.parsetRNS(length)
   564  	case "IDAT":
   565  		if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) {
   566  			return chunkOrderError
   567  		}
   568  		d.stage = dsSeenIDAT
   569  		return d.parseIDAT(length)
   570  	case "IEND":
   571  		if d.stage != dsSeenIDAT {
   572  			return chunkOrderError
   573  		}
   574  		d.stage = dsSeenIEND
   575  		return d.parseIEND(length)
   576  	}
   577  	// Ignore this chunk (of a known length).
   578  	var ignored [4096]byte
   579  	for length > 0 {
   580  		n, err = io.ReadFull(d.r, ignored[:min(len(ignored), int(length))])
   581  		if err != nil {
   582  			return err
   583  		}
   584  		d.crc.Write(ignored[:n])
   585  		length -= uint32(n)
   586  	}
   587  	return d.verifyChecksum()
   588  }
   589  
   590  func (d *decoder) verifyChecksum() error {
   591  	if _, err := io.ReadFull(d.r, d.tmp[:4]); err != nil {
   592  		return err
   593  	}
   594  	if binary.BigEndian.Uint32(d.tmp[:4]) != d.crc.Sum32() {
   595  		return FormatError("invalid checksum")
   596  	}
   597  	return nil
   598  }
   599  
   600  func (d *decoder) checkHeader() error {
   601  	_, err := io.ReadFull(d.r, d.tmp[:len(pngHeader)])
   602  	if err != nil {
   603  		return err
   604  	}
   605  	if string(d.tmp[:len(pngHeader)]) != pngHeader {
   606  		return FormatError("not a PNG file")
   607  	}
   608  	return nil
   609  }
   610  
   611  // Decode reads a PNG image from r and returns it as an image.Image.
   612  // The type of Image returned depends on the PNG contents.
   613  func Decode(r io.Reader) (image.Image, error) {
   614  	d := &decoder{
   615  		r:   r,
   616  		crc: crc32.NewIEEE(),
   617  	}
   618  	if err := d.checkHeader(); err != nil {
   619  		if err == io.EOF {
   620  			err = io.ErrUnexpectedEOF
   621  		}
   622  		return nil, err
   623  	}
   624  	for d.stage != dsSeenIEND {
   625  		if err := d.parseChunk(); err != nil {
   626  			if err == io.EOF {
   627  				err = io.ErrUnexpectedEOF
   628  			}
   629  			return nil, err
   630  		}
   631  	}
   632  	return d.img, nil
   633  }
   634  
   635  // DecodeConfig returns the color model and dimensions of a PNG image without
   636  // decoding the entire image.
   637  func DecodeConfig(r io.Reader) (image.Config, error) {
   638  	d := &decoder{
   639  		r:   r,
   640  		crc: crc32.NewIEEE(),
   641  	}
   642  	if err := d.checkHeader(); err != nil {
   643  		if err == io.EOF {
   644  			err = io.ErrUnexpectedEOF
   645  		}
   646  		return image.Config{}, err
   647  	}
   648  	for {
   649  		if err := d.parseChunk(); err != nil {
   650  			if err == io.EOF {
   651  				err = io.ErrUnexpectedEOF
   652  			}
   653  			return image.Config{}, err
   654  		}
   655  		paletted := d.cb == cbP8 || d.cb == cbP4 || d.cb == cbP2 || d.cb == cbP1
   656  		if d.stage == dsSeenIHDR && !paletted {
   657  			break
   658  		}
   659  		if d.stage == dsSeenPLTE && paletted {
   660  			break
   661  		}
   662  	}
   663  	var cm color.Model
   664  	switch d.cb {
   665  	case cbG1, cbG2, cbG4, cbG8:
   666  		cm = color.GrayModel
   667  	case cbGA8:
   668  		cm = color.NRGBAModel
   669  	case cbTC8:
   670  		cm = color.RGBAModel
   671  	case cbP1, cbP2, cbP4, cbP8:
   672  		cm = d.palette
   673  	case cbTCA8:
   674  		cm = color.NRGBAModel
   675  	case cbG16:
   676  		cm = color.Gray16Model
   677  	case cbGA16:
   678  		cm = color.NRGBA64Model
   679  	case cbTC16:
   680  		cm = color.RGBA64Model
   681  	case cbTCA16:
   682  		cm = color.NRGBA64Model
   683  	}
   684  	return image.Config{
   685  		ColorModel: cm,
   686  		Width:      d.width,
   687  		Height:     d.height,
   688  	}, nil
   689  }
   690  
   691  func init() {
   692  	image.RegisterFormat("png", pngHeader, Decode, DecodeConfig)
   693  }