123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056 |
- // Code generated by gen.go. DO NOT EDIT.
- // Copyright 2009 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // Package png implements a PNG image decoder and encoder.
- //
- // The PNG specification is at https://www.w3.org/TR/PNG/.
- package png
- import (
- "compress/zlib"
- "encoding/binary"
- "fmt"
- "hash"
- "hash/crc32"
- "image"
- "image/color"
- "io"
- )
- // Color type, as per the PNG spec.
- const (
- ctGrayscale = 0
- ctTrueColor = 2
- ctPaletted = 3
- ctGrayscaleAlpha = 4
- ctTrueColorAlpha = 6
- )
- // A cb is a combination of color type and bit depth.
- const (
- cbInvalid = iota
- cbG1
- cbG2
- cbG4
- cbG8
- cbGA8
- cbTC8
- cbP1
- cbP2
- cbP4
- cbP8
- cbTCA8
- cbG16
- cbGA16
- cbTC16
- cbTCA16
- )
- func cbPaletted(cb int) bool {
- return cbP1 <= cb && cb <= cbP8
- }
- func cbTrueColor(cb int) bool {
- return cb == cbTC8 || cb == cbTC16
- }
- // Filter type, as per the PNG spec.
- const (
- ftNone = 0
- ftSub = 1
- ftUp = 2
- ftAverage = 3
- ftPaeth = 4
- nFilter = 5
- )
- // Interlace type.
- const (
- itNone = 0
- itAdam7 = 1
- )
- // interlaceScan defines the placement and size of a pass for Adam7 interlacing.
- type interlaceScan struct {
- xFactor, yFactor, xOffset, yOffset int
- }
- // interlacing defines Adam7 interlacing, with 7 passes of reduced images.
- // See https://www.w3.org/TR/PNG/#8Interlace
- var interlacing = []interlaceScan{
- {8, 8, 0, 0},
- {8, 8, 4, 0},
- {4, 8, 0, 4},
- {4, 4, 2, 0},
- {2, 4, 0, 2},
- {2, 2, 1, 0},
- {1, 2, 0, 1},
- }
- // Decoding stage.
- // The PNG specification says that the IHDR, PLTE (if present), tRNS (if
- // present), IDAT and IEND chunks must appear in that order. There may be
- // multiple IDAT chunks, and IDAT chunks must be sequential (i.e. they may not
- // have any other chunks between them).
- // https://www.w3.org/TR/PNG/#5ChunkOrdering
- const (
- dsStart = iota
- dsSeenIHDR
- dsSeenPLTE
- dsSeentRNS
- dsSeenIDAT
- dsSeenIEND
- )
- const pngHeader = "\x89PNG\r\n\x1a\n"
- type decoder struct {
- r io.Reader
- img image.Image
- crc hash.Hash32
- width, height int
- depth int
- palette color.Palette
- cb int
- stage int
- idatLength uint32
- tmp [3 * 256]byte
- interlace int
- // useTransparent and transparent are used for grayscale and truecolor
- // transparency, as opposed to palette transparency.
- useTransparent bool
- transparent [6]byte
- }
- // A FormatError reports that the input is not a valid PNG.
- type FormatError string
- func (e FormatError) Error() string { return "png: invalid format: " + string(e) }
- var chunkOrderError = FormatError("chunk out of order")
- // An UnsupportedError reports that the input uses a valid but unimplemented PNG feature.
- type UnsupportedError string
- func (e UnsupportedError) Error() string { return "png: unsupported feature: " + string(e) }
- func (d *decoder) parseIHDR(length uint32) error {
- if length != 13 {
- return FormatError("bad IHDR length")
- }
- if _, err := io.ReadFull(d.r, d.tmp[:13]); err != nil {
- return err
- }
- d.crc.Write(d.tmp[:13])
- if d.tmp[10] != 0 {
- return UnsupportedError("compression method")
- }
- if d.tmp[11] != 0 {
- return UnsupportedError("filter method")
- }
- if d.tmp[12] != itNone && d.tmp[12] != itAdam7 {
- return FormatError("invalid interlace method")
- }
- d.interlace = int(d.tmp[12])
- w := int32(binary.BigEndian.Uint32(d.tmp[0:4]))
- h := int32(binary.BigEndian.Uint32(d.tmp[4:8]))
- if w <= 0 || h <= 0 {
- return FormatError("non-positive dimension")
- }
- nPixels64 := int64(w) * int64(h)
- nPixels := int(nPixels64)
- if nPixels64 != int64(nPixels) {
- return UnsupportedError("dimension overflow")
- }
- // There can be up to 8 bytes per pixel, for 16 bits per channel RGBA.
- if nPixels != (nPixels*8)/8 {
- return UnsupportedError("dimension overflow")
- }
- d.cb = cbInvalid
- d.depth = int(d.tmp[8])
- switch d.depth {
- case 1:
- switch d.tmp[9] {
- case ctGrayscale:
- d.cb = cbG1
- case ctPaletted:
- d.cb = cbP1
- }
- case 2:
- switch d.tmp[9] {
- case ctGrayscale:
- d.cb = cbG2
- case ctPaletted:
- d.cb = cbP2
- }
- case 4:
- switch d.tmp[9] {
- case ctGrayscale:
- d.cb = cbG4
- case ctPaletted:
- d.cb = cbP4
- }
- case 8:
- switch d.tmp[9] {
- case ctGrayscale:
- d.cb = cbG8
- case ctTrueColor:
- d.cb = cbTC8
- case ctPaletted:
- d.cb = cbP8
- case ctGrayscaleAlpha:
- d.cb = cbGA8
- case ctTrueColorAlpha:
- d.cb = cbTCA8
- }
- case 16:
- switch d.tmp[9] {
- case ctGrayscale:
- d.cb = cbG16
- case ctTrueColor:
- d.cb = cbTC16
- case ctGrayscaleAlpha:
- d.cb = cbGA16
- case ctTrueColorAlpha:
- d.cb = cbTCA16
- }
- }
- if d.cb == cbInvalid {
- return UnsupportedError(fmt.Sprintf("bit depth %d, color type %d", d.tmp[8], d.tmp[9]))
- }
- d.width, d.height = int(w), int(h)
- return d.verifyChecksum()
- }
- func (d *decoder) parsePLTE(length uint32) error {
- np := int(length / 3) // The number of palette entries.
- if length%3 != 0 || np <= 0 || np > 256 || np > 1<<uint(d.depth) {
- return FormatError("bad PLTE length")
- }
- n, err := io.ReadFull(d.r, d.tmp[:3*np])
- if err != nil {
- return err
- }
- d.crc.Write(d.tmp[:n])
- switch d.cb {
- case cbP1, cbP2, cbP4, cbP8:
- d.palette = make(color.Palette, 256)
- for i := 0; i < np; i++ {
- d.palette[i] = color.RGBA{d.tmp[3*i+0], d.tmp[3*i+1], d.tmp[3*i+2], 0xff}
- }
- for i := np; i < 256; i++ {
- // Initialize the rest of the palette to opaque black. The spec (section
- // 11.2.3) says that "any out-of-range pixel value found in the image data
- // is an error", but some real-world PNG files have out-of-range pixel
- // values. We fall back to opaque black, the same as libpng 1.5.13;
- // ImageMagick 6.5.7 returns an error.
- d.palette[i] = color.RGBA{0x00, 0x00, 0x00, 0xff}
- }
- d.palette = d.palette[:np]
- case cbTC8, cbTCA8, cbTC16, cbTCA16:
- // As per the PNG spec, a PLTE chunk is optional (and for practical purposes,
- // ignorable) for the ctTrueColor and ctTrueColorAlpha color types (section 4.1.2).
- default:
- return FormatError("PLTE, color type mismatch")
- }
- return d.verifyChecksum()
- }
- func (d *decoder) parsetRNS(length uint32) error {
- switch d.cb {
- case cbG1, cbG2, cbG4, cbG8, cbG16:
- if length != 2 {
- return FormatError("bad tRNS length")
- }
- n, err := io.ReadFull(d.r, d.tmp[:length])
- if err != nil {
- return err
- }
- d.crc.Write(d.tmp[:n])
- copy(d.transparent[:], d.tmp[:length])
- switch d.cb {
- case cbG1:
- d.transparent[1] *= 0xff
- case cbG2:
- d.transparent[1] *= 0x55
- case cbG4:
- d.transparent[1] *= 0x11
- }
- d.useTransparent = true
- case cbTC8, cbTC16:
- if length != 6 {
- return FormatError("bad tRNS length")
- }
- n, err := io.ReadFull(d.r, d.tmp[:length])
- if err != nil {
- return err
- }
- d.crc.Write(d.tmp[:n])
- copy(d.transparent[:], d.tmp[:length])
- d.useTransparent = true
- case cbP1, cbP2, cbP4, cbP8:
- if length > 256 {
- return FormatError("bad tRNS length")
- }
- n, err := io.ReadFull(d.r, d.tmp[:length])
- if err != nil {
- return err
- }
- d.crc.Write(d.tmp[:n])
- if len(d.palette) < n {
- d.palette = d.palette[:n]
- }
- for i := 0; i < n; i++ {
- rgba := d.palette[i].(color.RGBA)
- d.palette[i] = color.NRGBA{rgba.R, rgba.G, rgba.B, d.tmp[i]}
- }
- default:
- return FormatError("tRNS, color type mismatch")
- }
- return d.verifyChecksum()
- }
- // Read presents one or more IDAT chunks as one continuous stream (minus the
- // intermediate chunk headers and footers). If the PNG data looked like:
- //
- // ... len0 IDAT xxx crc0 len1 IDAT yy crc1 len2 IEND crc2
- //
- // then this reader presents xxxyy. For well-formed PNG data, the decoder state
- // immediately before the first Read call is that d.r is positioned between the
- // first IDAT and xxx, and the decoder state immediately after the last Read
- // call is that d.r is positioned between yy and crc1.
- func (d *decoder) Read(p []byte) (int, error) {
- if len(p) == 0 {
- return 0, nil
- }
- for d.idatLength == 0 {
- // We have exhausted an IDAT chunk. Verify the checksum of that chunk.
- if err := d.verifyChecksum(); err != nil {
- return 0, err
- }
- // Read the length and chunk type of the next chunk, and check that
- // it is an IDAT chunk.
- if _, err := io.ReadFull(d.r, d.tmp[:8]); err != nil {
- return 0, err
- }
- d.idatLength = binary.BigEndian.Uint32(d.tmp[:4])
- if string(d.tmp[4:8]) != "IDAT" {
- return 0, FormatError("not enough pixel data")
- }
- d.crc.Reset()
- d.crc.Write(d.tmp[4:8])
- }
- if int(d.idatLength) < 0 {
- return 0, UnsupportedError("IDAT chunk length overflow")
- }
- n, err := d.r.Read(p[:min(len(p), int(d.idatLength))])
- d.crc.Write(p[:n])
- d.idatLength -= uint32(n)
- return n, err
- }
- // decode decodes the IDAT data into an image.
- func (d *decoder) decode() (image.Image, error) {
- r, err := zlib.NewReader(d)
- if err != nil {
- return nil, err
- }
- defer r.Close()
- var img image.Image
- if d.interlace == itNone {
- img, err = d.readImagePass(r, 0, false)
- if err != nil {
- return nil, err
- }
- } else if d.interlace == itAdam7 {
- // Allocate a blank image of the full size.
- img, err = d.readImagePass(nil, 0, true)
- if err != nil {
- return nil, err
- }
- for pass := 0; pass < 7; pass++ {
- imagePass, err := d.readImagePass(r, pass, false)
- if err != nil {
- return nil, err
- }
- if imagePass != nil {
- d.mergePassInto(img, imagePass, pass)
- }
- }
- }
- // Check for EOF, to verify the zlib checksum.
- n := 0
- for i := 0; n == 0 && err == nil; i++ {
- if i == 100 {
- return nil, io.ErrNoProgress
- }
- n, err = r.Read(d.tmp[:1])
- }
- if err != nil && err != io.EOF {
- return nil, FormatError(err.Error())
- }
- if n != 0 || d.idatLength != 0 {
- return nil, FormatError("too much pixel data")
- }
- return img, nil
- }
- // readImagePass reads a single image pass, sized according to the pass number.
- func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image.Image, error) {
- bitsPerPixel := 0
- pixOffset := 0
- var (
- gray *image.Gray
- rgba *image.RGBA
- paletted *image.Paletted
- nrgba *image.NRGBA
- gray16 *image.Gray16
- rgba64 *image.RGBA64
- nrgba64 *image.NRGBA64
- img image.Image
- )
- width, height := d.width, d.height
- if d.interlace == itAdam7 && !allocateOnly {
- p := interlacing[pass]
- // Add the multiplication factor and subtract one, effectively rounding up.
- width = (width - p.xOffset + p.xFactor - 1) / p.xFactor
- height = (height - p.yOffset + p.yFactor - 1) / p.yFactor
- // A PNG image can't have zero width or height, but for an interlaced
- // image, an individual pass might have zero width or height. If so, we
- // shouldn't even read a per-row filter type byte, so return early.
- if width == 0 || height == 0 {
- return nil, nil
- }
- }
- switch d.cb {
- case cbG1, cbG2, cbG4, cbG8:
- bitsPerPixel = d.depth
- if d.useTransparent {
- nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
- img = nrgba
- } else {
- gray = image.NewGray(image.Rect(0, 0, width, height))
- img = gray
- }
- case cbGA8:
- bitsPerPixel = 16
- nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
- img = nrgba
- case cbTC8:
- bitsPerPixel = 24
- if d.useTransparent {
- nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
- img = nrgba
- } else {
- rgba = image.NewRGBA(image.Rect(0, 0, width, height))
- img = rgba
- }
- case cbP1, cbP2, cbP4, cbP8:
- bitsPerPixel = d.depth
- paletted = image.NewPaletted(image.Rect(0, 0, width, height), d.palette)
- img = paletted
- case cbTCA8:
- bitsPerPixel = 32
- nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
- img = nrgba
- case cbG16:
- bitsPerPixel = 16
- if d.useTransparent {
- nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
- img = nrgba64
- } else {
- gray16 = image.NewGray16(image.Rect(0, 0, width, height))
- img = gray16
- }
- case cbGA16:
- bitsPerPixel = 32
- nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
- img = nrgba64
- case cbTC16:
- bitsPerPixel = 48
- if d.useTransparent {
- nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
- img = nrgba64
- } else {
- rgba64 = image.NewRGBA64(image.Rect(0, 0, width, height))
- img = rgba64
- }
- case cbTCA16:
- bitsPerPixel = 64
- nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
- img = nrgba64
- }
- if allocateOnly {
- return img, nil
- }
- bytesPerPixel := (bitsPerPixel + 7) / 8
- // The +1 is for the per-row filter type, which is at cr[0].
- rowSize := 1 + (int64(bitsPerPixel)*int64(width)+7)/8
- if rowSize != int64(int(rowSize)) {
- return nil, UnsupportedError("dimension overflow")
- }
- // cr and pr are the bytes for the current and previous row.
- cr := make([]uint8, rowSize)
- pr := make([]uint8, rowSize)
- for y := 0; y < height; y++ {
- // Read the decompressed bytes.
- _, err := io.ReadFull(r, cr)
- if err != nil {
- if err == io.EOF || err == io.ErrUnexpectedEOF {
- return nil, FormatError("not enough pixel data")
- }
- return nil, err
- }
- // Apply the filter.
- cdat := cr[1:]
- pdat := pr[1:]
- switch cr[0] {
- case ftNone:
- // No-op.
- case ftSub:
- for i := bytesPerPixel; i < len(cdat); i++ {
- cdat[i] += cdat[i-bytesPerPixel]
- }
- case ftUp:
- for i, p := range pdat {
- cdat[i] += p
- }
- case ftAverage:
- // The first column has no column to the left of it, so it is a
- // special case. We know that the first column exists because we
- // check above that width != 0, and so len(cdat) != 0.
- for i := 0; i < bytesPerPixel; i++ {
- cdat[i] += pdat[i] / 2
- }
- for i := bytesPerPixel; i < len(cdat); i++ {
- cdat[i] += uint8((int(cdat[i-bytesPerPixel]) + int(pdat[i])) / 2)
- }
- case ftPaeth:
- filterPaeth(cdat, pdat, bytesPerPixel)
- default:
- return nil, FormatError("bad filter type")
- }
- // Convert from bytes to colors.
- switch d.cb {
- case cbG1:
- if d.useTransparent {
- ty := d.transparent[1]
- for x := 0; x < width; x += 8 {
- b := cdat[x/8]
- for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
- ycol := (b >> 7) * 0xff
- acol := uint8(0xff)
- if ycol == ty {
- acol = 0x00
- }
- nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol})
- b <<= 1
- }
- }
- } else {
- for x := 0; x < width; x += 8 {
- b := cdat[x/8]
- for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
- gray.SetGray(x+x2, y, color.Gray{(b >> 7) * 0xff})
- b <<= 1
- }
- }
- }
- case cbG2:
- if d.useTransparent {
- ty := d.transparent[1]
- for x := 0; x < width; x += 4 {
- b := cdat[x/4]
- for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
- ycol := (b >> 6) * 0x55
- acol := uint8(0xff)
- if ycol == ty {
- acol = 0x00
- }
- nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol})
- b <<= 2
- }
- }
- } else {
- for x := 0; x < width; x += 4 {
- b := cdat[x/4]
- for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
- gray.SetGray(x+x2, y, color.Gray{(b >> 6) * 0x55})
- b <<= 2
- }
- }
- }
- case cbG4:
- if d.useTransparent {
- ty := d.transparent[1]
- for x := 0; x < width; x += 2 {
- b := cdat[x/2]
- for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
- ycol := (b >> 4) * 0x11
- acol := uint8(0xff)
- if ycol == ty {
- acol = 0x00
- }
- nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol})
- b <<= 4
- }
- }
- } else {
- for x := 0; x < width; x += 2 {
- b := cdat[x/2]
- for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
- gray.SetGray(x+x2, y, color.Gray{(b >> 4) * 0x11})
- b <<= 4
- }
- }
- }
- case cbG8:
- if d.useTransparent {
- ty := d.transparent[1]
- for x := 0; x < width; x++ {
- ycol := cdat[x]
- acol := uint8(0xff)
- if ycol == ty {
- acol = 0x00
- }
- nrgba.SetNRGBA(x, y, color.NRGBA{ycol, ycol, ycol, acol})
- }
- } else {
- copy(gray.Pix[pixOffset:], cdat)
- pixOffset += gray.Stride
- }
- case cbGA8:
- for x := 0; x < width; x++ {
- ycol := cdat[2*x+0]
- nrgba.SetNRGBA(x, y, color.NRGBA{ycol, ycol, ycol, cdat[2*x+1]})
- }
- case cbTC8:
- if d.useTransparent {
- pix, i, j := nrgba.Pix, pixOffset, 0
- tr, tg, tb := d.transparent[1], d.transparent[3], d.transparent[5]
- for x := 0; x < width; x++ {
- r := cdat[j+0]
- g := cdat[j+1]
- b := cdat[j+2]
- a := uint8(0xff)
- if r == tr && g == tg && b == tb {
- a = 0x00
- }
- pix[i+0] = r
- pix[i+1] = g
- pix[i+2] = b
- pix[i+3] = a
- i += 4
- j += 3
- }
- pixOffset += nrgba.Stride
- } else {
- pix, i, j := rgba.Pix, pixOffset, 0
- for x := 0; x < width; x++ {
- pix[i+0] = cdat[j+0]
- pix[i+1] = cdat[j+1]
- pix[i+2] = cdat[j+2]
- pix[i+3] = 0xff
- i += 4
- j += 3
- }
- pixOffset += rgba.Stride
- }
- case cbP1:
- for x := 0; x < width; x += 8 {
- b := cdat[x/8]
- for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
- idx := b >> 7
- if len(paletted.Palette) <= int(idx) {
- paletted.Palette = paletted.Palette[:int(idx)+1]
- }
- paletted.SetColorIndex(x+x2, y, idx)
- b <<= 1
- }
- }
- case cbP2:
- for x := 0; x < width; x += 4 {
- b := cdat[x/4]
- for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
- idx := b >> 6
- if len(paletted.Palette) <= int(idx) {
- paletted.Palette = paletted.Palette[:int(idx)+1]
- }
- paletted.SetColorIndex(x+x2, y, idx)
- b <<= 2
- }
- }
- case cbP4:
- for x := 0; x < width; x += 2 {
- b := cdat[x/2]
- for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
- idx := b >> 4
- if len(paletted.Palette) <= int(idx) {
- paletted.Palette = paletted.Palette[:int(idx)+1]
- }
- paletted.SetColorIndex(x+x2, y, idx)
- b <<= 4
- }
- }
- case cbP8:
- if len(paletted.Palette) != 256 {
- for x := 0; x < width; x++ {
- if len(paletted.Palette) <= int(cdat[x]) {
- paletted.Palette = paletted.Palette[:int(cdat[x])+1]
- }
- }
- }
- copy(paletted.Pix[pixOffset:], cdat)
- pixOffset += paletted.Stride
- case cbTCA8:
- copy(nrgba.Pix[pixOffset:], cdat)
- pixOffset += nrgba.Stride
- case cbG16:
- if d.useTransparent {
- ty := uint16(d.transparent[0])<<8 | uint16(d.transparent[1])
- for x := 0; x < width; x++ {
- ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
- acol := uint16(0xffff)
- if ycol == ty {
- acol = 0x0000
- }
- nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol})
- }
- } else {
- for x := 0; x < width; x++ {
- ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
- gray16.SetGray16(x, y, color.Gray16{ycol})
- }
- }
- case cbGA16:
- for x := 0; x < width; x++ {
- ycol := uint16(cdat[4*x+0])<<8 | uint16(cdat[4*x+1])
- acol := uint16(cdat[4*x+2])<<8 | uint16(cdat[4*x+3])
- nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol})
- }
- case cbTC16:
- if d.useTransparent {
- tr := uint16(d.transparent[0])<<8 | uint16(d.transparent[1])
- tg := uint16(d.transparent[2])<<8 | uint16(d.transparent[3])
- tb := uint16(d.transparent[4])<<8 | uint16(d.transparent[5])
- for x := 0; x < width; x++ {
- rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
- gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
- bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
- acol := uint16(0xffff)
- if rcol == tr && gcol == tg && bcol == tb {
- acol = 0x0000
- }
- nrgba64.SetNRGBA64(x, y, color.NRGBA64{rcol, gcol, bcol, acol})
- }
- } else {
- for x := 0; x < width; x++ {
- rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
- gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
- bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
- rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff})
- }
- }
- case cbTCA16:
- for x := 0; x < width; x++ {
- rcol := uint16(cdat[8*x+0])<<8 | uint16(cdat[8*x+1])
- gcol := uint16(cdat[8*x+2])<<8 | uint16(cdat[8*x+3])
- bcol := uint16(cdat[8*x+4])<<8 | uint16(cdat[8*x+5])
- acol := uint16(cdat[8*x+6])<<8 | uint16(cdat[8*x+7])
- nrgba64.SetNRGBA64(x, y, color.NRGBA64{rcol, gcol, bcol, acol})
- }
- }
- // The current row for y is the previous row for y+1.
- pr, cr = cr, pr
- }
- return img, nil
- }
- // mergePassInto merges a single pass into a full sized image.
- func (d *decoder) mergePassInto(dst image.Image, src image.Image, pass int) {
- p := interlacing[pass]
- var (
- srcPix []uint8
- dstPix []uint8
- stride int
- rect image.Rectangle
- bytesPerPixel int
- )
- switch target := dst.(type) {
- case *image.Alpha:
- srcPix = src.(*image.Alpha).Pix
- dstPix, stride, rect = target.Pix, target.Stride, target.Rect
- bytesPerPixel = 1
- case *image.Alpha16:
- srcPix = src.(*image.Alpha16).Pix
- dstPix, stride, rect = target.Pix, target.Stride, target.Rect
- bytesPerPixel = 2
- case *image.Gray:
- srcPix = src.(*image.Gray).Pix
- dstPix, stride, rect = target.Pix, target.Stride, target.Rect
- bytesPerPixel = 1
- case *image.Gray16:
- srcPix = src.(*image.Gray16).Pix
- dstPix, stride, rect = target.Pix, target.Stride, target.Rect
- bytesPerPixel = 2
- case *image.NRGBA:
- srcPix = src.(*image.NRGBA).Pix
- dstPix, stride, rect = target.Pix, target.Stride, target.Rect
- bytesPerPixel = 4
- case *image.NRGBA64:
- srcPix = src.(*image.NRGBA64).Pix
- dstPix, stride, rect = target.Pix, target.Stride, target.Rect
- bytesPerPixel = 8
- case *image.Paletted:
- source := src.(*image.Paletted)
- srcPix = source.Pix
- dstPix, stride, rect = target.Pix, target.Stride, target.Rect
- bytesPerPixel = 1
- if len(target.Palette) < len(source.Palette) {
- // readImagePass can return a paletted image whose implicit palette
- // length (one more than the maximum Pix value) is larger than the
- // explicit palette length (what's in the PLTE chunk). Make the
- // same adjustment here.
- target.Palette = source.Palette
- }
- case *image.RGBA:
- srcPix = src.(*image.RGBA).Pix
- dstPix, stride, rect = target.Pix, target.Stride, target.Rect
- bytesPerPixel = 4
- case *image.RGBA64:
- srcPix = src.(*image.RGBA64).Pix
- dstPix, stride, rect = target.Pix, target.Stride, target.Rect
- bytesPerPixel = 8
- }
- s, bounds := 0, src.Bounds()
- for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
- dBase := (y*p.yFactor+p.yOffset-rect.Min.Y)*stride + (p.xOffset-rect.Min.X)*bytesPerPixel
- for x := bounds.Min.X; x < bounds.Max.X; x++ {
- d := dBase + x*p.xFactor*bytesPerPixel
- copy(dstPix[d:], srcPix[s:s+bytesPerPixel])
- s += bytesPerPixel
- }
- }
- }
- func (d *decoder) parseIDAT(length uint32) (err error) {
- d.idatLength = length
- d.img, err = d.decode()
- if err != nil {
- return err
- }
- return d.verifyChecksum()
- }
- func (d *decoder) parseIEND(length uint32) error {
- if length != 0 {
- return FormatError("bad IEND length")
- }
- return d.verifyChecksum()
- }
- func (d *decoder) parseChunk(configOnly bool) error {
- // Read the length and chunk type.
- if _, err := io.ReadFull(d.r, d.tmp[:8]); err != nil {
- return err
- }
- length := binary.BigEndian.Uint32(d.tmp[:4])
- d.crc.Reset()
- d.crc.Write(d.tmp[4:8])
- // Read the chunk data.
- switch string(d.tmp[4:8]) {
- case "IHDR":
- if d.stage != dsStart {
- return chunkOrderError
- }
- d.stage = dsSeenIHDR
- return d.parseIHDR(length)
- case "PLTE":
- if d.stage != dsSeenIHDR {
- return chunkOrderError
- }
- d.stage = dsSeenPLTE
- return d.parsePLTE(length)
- case "tRNS":
- if cbPaletted(d.cb) {
- if d.stage != dsSeenPLTE {
- return chunkOrderError
- }
- } else if cbTrueColor(d.cb) {
- if d.stage != dsSeenIHDR && d.stage != dsSeenPLTE {
- return chunkOrderError
- }
- } else if d.stage != dsSeenIHDR {
- return chunkOrderError
- }
- d.stage = dsSeentRNS
- return d.parsetRNS(length)
- case "IDAT":
- if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.stage == dsSeenIHDR && cbPaletted(d.cb)) {
- return chunkOrderError
- } else if d.stage == dsSeenIDAT {
- // Ignore trailing zero-length or garbage IDAT chunks.
- //
- // This does not affect valid PNG images that contain multiple IDAT
- // chunks, since the first call to parseIDAT below will consume all
- // consecutive IDAT chunks required for decoding the image.
- break
- }
- d.stage = dsSeenIDAT
- if configOnly {
- return nil
- }
- return d.parseIDAT(length)
- case "IEND":
- if d.stage != dsSeenIDAT {
- return chunkOrderError
- }
- d.stage = dsSeenIEND
- return d.parseIEND(length)
- }
- if length > 0x7fffffff {
- return FormatError(fmt.Sprintf("Bad chunk length: %d", length))
- }
- // Ignore this chunk (of a known length).
- var ignored [4096]byte
- for length > 0 {
- n, err := io.ReadFull(d.r, ignored[:min(len(ignored), int(length))])
- if err != nil {
- return err
- }
- d.crc.Write(ignored[:n])
- length -= uint32(n)
- }
- return d.verifyChecksum()
- }
- func (d *decoder) verifyChecksum() error {
- if _, err := io.ReadFull(d.r, d.tmp[:4]); err != nil {
- return err
- }
- if binary.BigEndian.Uint32(d.tmp[:4]) != d.crc.Sum32() {
- return FormatError("invalid checksum")
- }
- return nil
- }
- func (d *decoder) checkHeader() error {
- _, err := io.ReadFull(d.r, d.tmp[:len(pngHeader)])
- if err != nil {
- return err
- }
- if string(d.tmp[:len(pngHeader)]) != pngHeader {
- return FormatError("not a PNG file")
- }
- return nil
- }
- // Decode reads a PNG image from r and returns it as an [image.Image].
- // The type of Image returned depends on the PNG contents.
- func Decode(r io.Reader) (image.Image, error) {
- d := &decoder{
- r: r,
- crc: crc32.NewIEEE(),
- }
- if err := d.checkHeader(); err != nil {
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
- }
- return nil, err
- }
- for d.stage != dsSeenIEND {
- if err := d.parseChunk(false); err != nil {
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
- }
- return nil, err
- }
- }
- return d.img, nil
- }
- // DecodeConfig returns the color model and dimensions of a PNG image without
- // decoding the entire image.
- func DecodeConfig(r io.Reader) (image.Config, error) {
- d := &decoder{
- r: r,
- crc: crc32.NewIEEE(),
- }
- if err := d.checkHeader(); err != nil {
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
- }
- return image.Config{}, err
- }
- for {
- if err := d.parseChunk(true); err != nil {
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
- }
- return image.Config{}, err
- }
- if cbPaletted(d.cb) {
- if d.stage >= dsSeentRNS {
- break
- }
- } else {
- if d.stage >= dsSeenIHDR {
- break
- }
- }
- }
- var cm color.Model
- switch d.cb {
- case cbG1, cbG2, cbG4, cbG8:
- cm = color.GrayModel
- case cbGA8:
- cm = color.NRGBAModel
- case cbTC8:
- cm = color.RGBAModel
- case cbP1, cbP2, cbP4, cbP8:
- cm = d.palette
- case cbTCA8:
- cm = color.NRGBAModel
- case cbG16:
- cm = color.Gray16Model
- case cbGA16:
- cm = color.NRGBA64Model
- case cbTC16:
- cm = color.RGBA64Model
- case cbTCA16:
- cm = color.NRGBA64Model
- }
- return image.Config{
- ColorModel: cm,
- Width: d.width,
- Height: d.height,
- }, nil
- }
- func init() {
- }
|