Source file src/image/png/writer.go

Documentation: image/png

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

View as plain text