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, 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	}

View as plain text