github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/image/png/writer.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
     6  
     7  import (
     8  	"bufio"
     9  	"compress/zlib"
    10  	"hash/crc32"
    11  	"image"
    12  	"image/color"
    13  	"io"
    14  	"strconv"
    15  )
    16  
    17  // Encoder configures encoding PNG images.
    18  type Encoder struct {
    19  	CompressionLevel CompressionLevel
    20  
    21  	// BufferPool optionally specifies a buffer pool to get temporary
    22  	// EncoderBuffers when encoding an image.
    23  	BufferPool EncoderBufferPool
    24  }
    25  
    26  // EncoderBufferPool is an interface for getting and returning temporary
    27  // instances of the EncoderBuffer struct. This can be used to reuse buffers
    28  // when encoding multiple images.
    29  type EncoderBufferPool interface {
    30  	Get() *EncoderBuffer
    31  	Put(*EncoderBuffer)
    32  }
    33  
    34  // EncoderBuffer holds the buffers used for encoding PNG images.
    35  type EncoderBuffer encoder
    36  
    37  type encoder struct {
    38  	enc     *Encoder
    39  	w       io.Writer
    40  	m       image.Image
    41  	cb      int
    42  	err     error
    43  	header  [8]byte
    44  	footer  [4]byte
    45  	tmp     [4 * 256]byte
    46  	cr      [nFilter][]uint8
    47  	pr      []uint8
    48  	zw      *zlib.Writer
    49  	zwLevel int
    50  	bw      *bufio.Writer
    51  }
    52  
    53  type CompressionLevel int
    54  
    55  const (
    56  	DefaultCompression CompressionLevel = 0
    57  	NoCompression      CompressionLevel = -1
    58  	BestSpeed          CompressionLevel = -2
    59  	BestCompression    CompressionLevel = -3
    60  
    61  	// Positive CompressionLevel values are reserved to mean a numeric zlib
    62  	// compression level, although that is not implemented yet.
    63  )
    64  
    65  // Big-endian.
    66  func writeUint32(b []uint8, u uint32) {
    67  	b[0] = uint8(u >> 24)
    68  	b[1] = uint8(u >> 16)
    69  	b[2] = uint8(u >> 8)
    70  	b[3] = uint8(u >> 0)
    71  }
    72  
    73  type opaquer interface {
    74  	Opaque() bool
    75  }
    76  
    77  // Returns whether or not the image is fully opaque.
    78  func opaque(m image.Image) bool {
    79  	if o, ok := m.(opaquer); ok {
    80  		return o.Opaque()
    81  	}
    82  	b := m.Bounds()
    83  	for y := b.Min.Y; y < b.Max.Y; y++ {
    84  		for x := b.Min.X; x < b.Max.X; x++ {
    85  			_, _, _, a := m.At(x, y).RGBA()
    86  			if a != 0xffff {
    87  				return false
    88  			}
    89  		}
    90  	}
    91  	return true
    92  }
    93  
    94  // The absolute value of a byte interpreted as a signed int8.
    95  func abs8(d uint8) int {
    96  	if d < 128 {
    97  		return int(d)
    98  	}
    99  	return 256 - int(d)
   100  }
   101  
   102  func (e *encoder) writeChunk(b []byte, name string) {
   103  	if e.err != nil {
   104  		return
   105  	}
   106  	n := uint32(len(b))
   107  	if int(n) != len(b) {
   108  		e.err = UnsupportedError(name + " chunk is too large: " + strconv.Itoa(len(b)))
   109  		return
   110  	}
   111  	writeUint32(e.header[:4], n)
   112  	e.header[4] = name[0]
   113  	e.header[5] = name[1]
   114  	e.header[6] = name[2]
   115  	e.header[7] = name[3]
   116  	crc := crc32.NewIEEE()
   117  	crc.Write(e.header[4:8])
   118  	crc.Write(b)
   119  	writeUint32(e.footer[:4], crc.Sum32())
   120  
   121  	_, e.err = e.w.Write(e.header[:8])
   122  	if e.err != nil {
   123  		return
   124  	}
   125  	_, e.err = e.w.Write(b)
   126  	if e.err != nil {
   127  		return
   128  	}
   129  	_, e.err = e.w.Write(e.footer[:4])
   130  }
   131  
   132  func (e *encoder) writeIHDR() {
   133  	b := e.m.Bounds()
   134  	writeUint32(e.tmp[0:4], uint32(b.Dx()))
   135  	writeUint32(e.tmp[4:8], uint32(b.Dy()))
   136  	// Set bit depth and color type.
   137  	switch e.cb {
   138  	case cbG8:
   139  		e.tmp[8] = 8
   140  		e.tmp[9] = ctGrayscale
   141  	case cbTC8:
   142  		e.tmp[8] = 8
   143  		e.tmp[9] = ctTrueColor
   144  	case cbP8:
   145  		e.tmp[8] = 8
   146  		e.tmp[9] = ctPaletted
   147  	case cbTCA8:
   148  		e.tmp[8] = 8
   149  		e.tmp[9] = ctTrueColorAlpha
   150  	case cbG16:
   151  		e.tmp[8] = 16
   152  		e.tmp[9] = ctGrayscale
   153  	case cbTC16:
   154  		e.tmp[8] = 16
   155  		e.tmp[9] = ctTrueColor
   156  	case cbTCA16:
   157  		e.tmp[8] = 16
   158  		e.tmp[9] = ctTrueColorAlpha
   159  	}
   160  	e.tmp[10] = 0 // default compression method
   161  	e.tmp[11] = 0 // default filter method
   162  	e.tmp[12] = 0 // non-interlaced
   163  	e.writeChunk(e.tmp[:13], "IHDR")
   164  }
   165  
   166  func (e *encoder) writePLTEAndTRNS(p color.Palette) {
   167  	if len(p) < 1 || len(p) > 256 {
   168  		e.err = FormatError("bad palette length: " + strconv.Itoa(len(p)))
   169  		return
   170  	}
   171  	last := -1
   172  	for i, c := range p {
   173  		c1 := color.NRGBAModel.Convert(c).(color.NRGBA)
   174  		e.tmp[3*i+0] = c1.R
   175  		e.tmp[3*i+1] = c1.G
   176  		e.tmp[3*i+2] = c1.B
   177  		if c1.A != 0xff {
   178  			last = i
   179  		}
   180  		e.tmp[3*256+i] = c1.A
   181  	}
   182  	e.writeChunk(e.tmp[:3*len(p)], "PLTE")
   183  	if last != -1 {
   184  		e.writeChunk(e.tmp[3*256:3*256+1+last], "tRNS")
   185  	}
   186  }
   187  
   188  // An encoder is an io.Writer that satisfies writes by writing PNG IDAT chunks,
   189  // including an 8-byte header and 4-byte CRC checksum per Write call. Such calls
   190  // should be relatively infrequent, since writeIDATs uses a bufio.Writer.
   191  //
   192  // This method should only be called from writeIDATs (via writeImage).
   193  // No other code should treat an encoder as an io.Writer.
   194  func (e *encoder) Write(b []byte) (int, error) {
   195  	e.writeChunk(b, "IDAT")
   196  	if e.err != nil {
   197  		return 0, e.err
   198  	}
   199  	return len(b), nil
   200  }
   201  
   202  // Chooses the filter to use for encoding the current row, and applies it.
   203  // The return value is the index of the filter and also of the row in cr that has had it applied.
   204  func filter(cr *[nFilter][]byte, pr []byte, bpp int) int {
   205  	// We try all five filter types, and pick the one that minimizes the sum of absolute differences.
   206  	// This is the same heuristic that libpng uses, although the filters are attempted in order of
   207  	// estimated most likely to be minimal (ftUp, ftPaeth, ftNone, ftSub, ftAverage), rather than
   208  	// in their enumeration order (ftNone, ftSub, ftUp, ftAverage, ftPaeth).
   209  	cdat0 := cr[0][1:]
   210  	cdat1 := cr[1][1:]
   211  	cdat2 := cr[2][1:]
   212  	cdat3 := cr[3][1:]
   213  	cdat4 := cr[4][1:]
   214  	pdat := pr[1:]
   215  	n := len(cdat0)
   216  
   217  	// The up filter.
   218  	sum := 0
   219  	for i := 0; i < n; i++ {
   220  		cdat2[i] = cdat0[i] - pdat[i]
   221  		sum += abs8(cdat2[i])
   222  	}
   223  	best := sum
   224  	filter := ftUp
   225  
   226  	// The Paeth filter.
   227  	sum = 0
   228  	for i := 0; i < bpp; i++ {
   229  		cdat4[i] = cdat0[i] - pdat[i]
   230  		sum += abs8(cdat4[i])
   231  	}
   232  	for i := bpp; i < n; i++ {
   233  		cdat4[i] = cdat0[i] - paeth(cdat0[i-bpp], pdat[i], pdat[i-bpp])
   234  		sum += abs8(cdat4[i])
   235  		if sum >= best {
   236  			break
   237  		}
   238  	}
   239  	if sum < best {
   240  		best = sum
   241  		filter = ftPaeth
   242  	}
   243  
   244  	// The none filter.
   245  	sum = 0
   246  	for i := 0; i < n; i++ {
   247  		sum += abs8(cdat0[i])
   248  		if sum >= best {
   249  			break
   250  		}
   251  	}
   252  	if sum < best {
   253  		best = sum
   254  		filter = ftNone
   255  	}
   256  
   257  	// The sub filter.
   258  	sum = 0
   259  	for i := 0; i < bpp; i++ {
   260  		cdat1[i] = cdat0[i]
   261  		sum += abs8(cdat1[i])
   262  	}
   263  	for i := bpp; i < n; i++ {
   264  		cdat1[i] = cdat0[i] - cdat0[i-bpp]
   265  		sum += abs8(cdat1[i])
   266  		if sum >= best {
   267  			break
   268  		}
   269  	}
   270  	if sum < best {
   271  		best = sum
   272  		filter = ftSub
   273  	}
   274  
   275  	// The average filter.
   276  	sum = 0
   277  	for i := 0; i < bpp; i++ {
   278  		cdat3[i] = cdat0[i] - pdat[i]/2
   279  		sum += abs8(cdat3[i])
   280  	}
   281  	for i := bpp; i < n; i++ {
   282  		cdat3[i] = cdat0[i] - uint8((int(cdat0[i-bpp])+int(pdat[i]))/2)
   283  		sum += abs8(cdat3[i])
   284  		if sum >= best {
   285  			break
   286  		}
   287  	}
   288  	if sum < best {
   289  		best = sum
   290  		filter = ftAverage
   291  	}
   292  
   293  	return filter
   294  }
   295  
   296  func zeroMemory(v []uint8) {
   297  	for i := range v {
   298  		v[i] = 0
   299  	}
   300  }
   301  
   302  func (e *encoder) writeImage(w io.Writer, m image.Image, cb int, level int) error {
   303  	if e.zw == nil || e.zwLevel != level {
   304  		zw, err := zlib.NewWriterLevel(w, level)
   305  		if err != nil {
   306  			return err
   307  		}
   308  		e.zw = zw
   309  		e.zwLevel = level
   310  	} else {
   311  		e.zw.Reset(w)
   312  	}
   313  	defer e.zw.Close()
   314  
   315  	bpp := 0 // Bytes per pixel.
   316  
   317  	switch cb {
   318  	case cbG8:
   319  		bpp = 1
   320  	case cbTC8:
   321  		bpp = 3
   322  	case cbP8:
   323  		bpp = 1
   324  	case cbTCA8:
   325  		bpp = 4
   326  	case cbTC16:
   327  		bpp = 6
   328  	case cbTCA16:
   329  		bpp = 8
   330  	case cbG16:
   331  		bpp = 2
   332  	}
   333  	// cr[*] and pr are the bytes for the current and previous row.
   334  	// cr[0] is unfiltered (or equivalently, filtered with the ftNone filter).
   335  	// cr[ft], for non-zero filter types ft, are buffers for transforming cr[0] under the
   336  	// other PNG filter types. These buffers are allocated once and re-used for each row.
   337  	// The +1 is for the per-row filter type, which is at cr[*][0].
   338  	b := m.Bounds()
   339  	sz := 1 + bpp*b.Dx()
   340  	for i := range e.cr {
   341  		if cap(e.cr[i]) < sz {
   342  			e.cr[i] = make([]uint8, sz)
   343  		} else {
   344  			e.cr[i] = e.cr[i][:sz]
   345  		}
   346  		e.cr[i][0] = uint8(i)
   347  	}
   348  	cr := e.cr
   349  	if cap(e.pr) < sz {
   350  		e.pr = make([]uint8, sz)
   351  	} else {
   352  		e.pr = e.pr[:sz]
   353  		zeroMemory(e.pr)
   354  	}
   355  	pr := e.pr
   356  
   357  	gray, _ := m.(*image.Gray)
   358  	rgba, _ := m.(*image.RGBA)
   359  	paletted, _ := m.(*image.Paletted)
   360  	nrgba, _ := m.(*image.NRGBA)
   361  
   362  	for y := b.Min.Y; y < b.Max.Y; y++ {
   363  		// Convert from colors to bytes.
   364  		i := 1
   365  		switch cb {
   366  		case cbG8:
   367  			if gray != nil {
   368  				offset := (y - b.Min.Y) * gray.Stride
   369  				copy(cr[0][1:], gray.Pix[offset:offset+b.Dx()])
   370  			} else {
   371  				for x := b.Min.X; x < b.Max.X; x++ {
   372  					c := color.GrayModel.Convert(m.At(x, y)).(color.Gray)
   373  					cr[0][i] = c.Y
   374  					i++
   375  				}
   376  			}
   377  		case cbTC8:
   378  			// We have previously verified that the alpha value is fully opaque.
   379  			cr0 := cr[0]
   380  			stride, pix := 0, []byte(nil)
   381  			if rgba != nil {
   382  				stride, pix = rgba.Stride, rgba.Pix
   383  			} else if nrgba != nil {
   384  				stride, pix = nrgba.Stride, nrgba.Pix
   385  			}
   386  			if stride != 0 {
   387  				j0 := (y - b.Min.Y) * stride
   388  				j1 := j0 + b.Dx()*4
   389  				for j := j0; j < j1; j += 4 {
   390  					cr0[i+0] = pix[j+0]
   391  					cr0[i+1] = pix[j+1]
   392  					cr0[i+2] = pix[j+2]
   393  					i += 3
   394  				}
   395  			} else {
   396  				for x := b.Min.X; x < b.Max.X; x++ {
   397  					r, g, b, _ := m.At(x, y).RGBA()
   398  					cr0[i+0] = uint8(r >> 8)
   399  					cr0[i+1] = uint8(g >> 8)
   400  					cr0[i+2] = uint8(b >> 8)
   401  					i += 3
   402  				}
   403  			}
   404  		case cbP8:
   405  			if paletted != nil {
   406  				offset := (y - b.Min.Y) * paletted.Stride
   407  				copy(cr[0][1:], paletted.Pix[offset:offset+b.Dx()])
   408  			} else {
   409  				pi := m.(image.PalettedImage)
   410  				for x := b.Min.X; x < b.Max.X; x++ {
   411  					cr[0][i] = pi.ColorIndexAt(x, y)
   412  					i += 1
   413  				}
   414  			}
   415  		case cbTCA8:
   416  			if nrgba != nil {
   417  				offset := (y - b.Min.Y) * nrgba.Stride
   418  				copy(cr[0][1:], nrgba.Pix[offset:offset+b.Dx()*4])
   419  			} else {
   420  				// Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
   421  				for x := b.Min.X; x < b.Max.X; x++ {
   422  					c := color.NRGBAModel.Convert(m.At(x, y)).(color.NRGBA)
   423  					cr[0][i+0] = c.R
   424  					cr[0][i+1] = c.G
   425  					cr[0][i+2] = c.B
   426  					cr[0][i+3] = c.A
   427  					i += 4
   428  				}
   429  			}
   430  		case cbG16:
   431  			for x := b.Min.X; x < b.Max.X; x++ {
   432  				c := color.Gray16Model.Convert(m.At(x, y)).(color.Gray16)
   433  				cr[0][i+0] = uint8(c.Y >> 8)
   434  				cr[0][i+1] = uint8(c.Y)
   435  				i += 2
   436  			}
   437  		case cbTC16:
   438  			// We have previously verified that the alpha value is fully opaque.
   439  			for x := b.Min.X; x < b.Max.X; x++ {
   440  				r, g, b, _ := m.At(x, y).RGBA()
   441  				cr[0][i+0] = uint8(r >> 8)
   442  				cr[0][i+1] = uint8(r)
   443  				cr[0][i+2] = uint8(g >> 8)
   444  				cr[0][i+3] = uint8(g)
   445  				cr[0][i+4] = uint8(b >> 8)
   446  				cr[0][i+5] = uint8(b)
   447  				i += 6
   448  			}
   449  		case cbTCA16:
   450  			// Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
   451  			for x := b.Min.X; x < b.Max.X; x++ {
   452  				c := color.NRGBA64Model.Convert(m.At(x, y)).(color.NRGBA64)
   453  				cr[0][i+0] = uint8(c.R >> 8)
   454  				cr[0][i+1] = uint8(c.R)
   455  				cr[0][i+2] = uint8(c.G >> 8)
   456  				cr[0][i+3] = uint8(c.G)
   457  				cr[0][i+4] = uint8(c.B >> 8)
   458  				cr[0][i+5] = uint8(c.B)
   459  				cr[0][i+6] = uint8(c.A >> 8)
   460  				cr[0][i+7] = uint8(c.A)
   461  				i += 8
   462  			}
   463  		}
   464  
   465  		// Apply the filter.
   466  		// Skip filter for NoCompression and paletted images (cbP8) as
   467  		// "filters are rarely useful on palette images" and will result
   468  		// in larger files (see http://www.libpng.org/pub/png/book/chapter09.html).
   469  		f := ftNone
   470  		if level != zlib.NoCompression && cb != cbP8 {
   471  			f = filter(&cr, pr, bpp)
   472  		}
   473  
   474  		// Write the compressed bytes.
   475  		if _, err := e.zw.Write(cr[f]); err != nil {
   476  			return err
   477  		}
   478  
   479  		// The current row for y is the previous row for y+1.
   480  		pr, cr[0] = cr[0], pr
   481  	}
   482  	return nil
   483  }
   484  
   485  // Write the actual image data to one or more IDAT chunks.
   486  func (e *encoder) writeIDATs() {
   487  	if e.err != nil {
   488  		return
   489  	}
   490  	if e.bw == nil {
   491  		e.bw = bufio.NewWriterSize(e, 1<<15)
   492  	} else {
   493  		e.bw.Reset(e)
   494  	}
   495  	e.err = e.writeImage(e.bw, e.m, e.cb, levelToZlib(e.enc.CompressionLevel))
   496  	if e.err != nil {
   497  		return
   498  	}
   499  	e.err = e.bw.Flush()
   500  }
   501  
   502  // This function is required because we want the zero value of
   503  // Encoder.CompressionLevel to map to zlib.DefaultCompression.
   504  func levelToZlib(l CompressionLevel) int {
   505  	switch l {
   506  	case DefaultCompression:
   507  		return zlib.DefaultCompression
   508  	case NoCompression:
   509  		return zlib.NoCompression
   510  	case BestSpeed:
   511  		return zlib.BestSpeed
   512  	case BestCompression:
   513  		return zlib.BestCompression
   514  	default:
   515  		return zlib.DefaultCompression
   516  	}
   517  }
   518  
   519  func (e *encoder) writeIEND() { e.writeChunk(nil, "IEND") }
   520  
   521  // Encode writes the Image m to w in PNG format. Any Image may be
   522  // encoded, but images that are not image.NRGBA might be encoded lossily.
   523  func Encode(w io.Writer, m image.Image) error {
   524  	var e Encoder
   525  	return e.Encode(w, m)
   526  }
   527  
   528  // Encode writes the Image m to w in PNG format.
   529  func (enc *Encoder) Encode(w io.Writer, m image.Image) error {
   530  	// Obviously, negative widths and heights are invalid. Furthermore, the PNG
   531  	// spec section 11.2.2 says that zero is invalid. Excessively large images are
   532  	// also rejected.
   533  	mw, mh := int64(m.Bounds().Dx()), int64(m.Bounds().Dy())
   534  	if mw <= 0 || mh <= 0 || mw >= 1<<32 || mh >= 1<<32 {
   535  		return FormatError("invalid image size: " + strconv.FormatInt(mw, 10) + "x" + strconv.FormatInt(mh, 10))
   536  	}
   537  
   538  	var e *encoder
   539  	if enc.BufferPool != nil {
   540  		buffer := enc.BufferPool.Get()
   541  		e = (*encoder)(buffer)
   542  
   543  	}
   544  	if e == nil {
   545  		e = &encoder{}
   546  	}
   547  	if enc.BufferPool != nil {
   548  		defer enc.BufferPool.Put((*EncoderBuffer)(e))
   549  	}
   550  
   551  	e.enc = enc
   552  	e.w = w
   553  	e.m = m
   554  
   555  	var pal color.Palette
   556  	// cbP8 encoding needs PalettedImage's ColorIndexAt method.
   557  	if _, ok := m.(image.PalettedImage); ok {
   558  		pal, _ = m.ColorModel().(color.Palette)
   559  	}
   560  	if pal != nil {
   561  		e.cb = cbP8
   562  	} else {
   563  		switch m.ColorModel() {
   564  		case color.GrayModel:
   565  			e.cb = cbG8
   566  		case color.Gray16Model:
   567  			e.cb = cbG16
   568  		case color.RGBAModel, color.NRGBAModel, color.AlphaModel:
   569  			if opaque(m) {
   570  				e.cb = cbTC8
   571  			} else {
   572  				e.cb = cbTCA8
   573  			}
   574  		default:
   575  			if opaque(m) {
   576  				e.cb = cbTC16
   577  			} else {
   578  				e.cb = cbTCA16
   579  			}
   580  		}
   581  	}
   582  
   583  	_, e.err = io.WriteString(w, pngHeader)
   584  	e.writeIHDR()
   585  	if pal != nil {
   586  		e.writePLTEAndTRNS(pal)
   587  	}
   588  	e.writeIDATs()
   589  	e.writeIEND()
   590  	return e.err
   591  }