github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/image/tiff/writer.go (about)

     1  // Copyright 2012 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 tiff
     6  
     7  import (
     8  	"bytes"
     9  	"compress/zlib"
    10  	"encoding/binary"
    11  	"image"
    12  	"io"
    13  	"sort"
    14  )
    15  
    16  // The TIFF format allows to choose the order of the different elements freely.
    17  // The basic structure of a TIFF file written by this package is:
    18  //
    19  //   1. Header (8 bytes).
    20  //   2. Image data.
    21  //   3. Image File Directory (IFD).
    22  //   4. "Pointer area" for larger entries in the IFD.
    23  
    24  // We only write little-endian TIFF files.
    25  var enc = binary.LittleEndian
    26  
    27  // An ifdEntry is a single entry in an Image File Directory.
    28  // A value of type dtRational is composed of two 32-bit values,
    29  // thus data contains two uints (numerator and denominator) for a single number.
    30  type ifdEntry struct {
    31  	tag      int
    32  	datatype int
    33  	data     []uint32
    34  }
    35  
    36  func (e ifdEntry) putData(p []byte) {
    37  	for _, d := range e.data {
    38  		switch e.datatype {
    39  		case dtByte, dtASCII:
    40  			p[0] = byte(d)
    41  			p = p[1:]
    42  		case dtShort:
    43  			enc.PutUint16(p, uint16(d))
    44  			p = p[2:]
    45  		case dtLong, dtRational:
    46  			enc.PutUint32(p, uint32(d))
    47  			p = p[4:]
    48  		}
    49  	}
    50  }
    51  
    52  type byTag []ifdEntry
    53  
    54  func (d byTag) Len() int           { return len(d) }
    55  func (d byTag) Less(i, j int) bool { return d[i].tag < d[j].tag }
    56  func (d byTag) Swap(i, j int)      { d[i], d[j] = d[j], d[i] }
    57  
    58  func encodeGray(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
    59  	if !predictor {
    60  		return writePix(w, pix, dy, dx, stride)
    61  	}
    62  	buf := make([]byte, dx)
    63  	for y := 0; y < dy; y++ {
    64  		min := y*stride + 0
    65  		max := y*stride + dx
    66  		off := 0
    67  		var v0 uint8
    68  		for i := min; i < max; i++ {
    69  			v1 := pix[i]
    70  			buf[off] = v1 - v0
    71  			v0 = v1
    72  			off++
    73  		}
    74  		if _, err := w.Write(buf); err != nil {
    75  			return err
    76  		}
    77  	}
    78  	return nil
    79  }
    80  
    81  func encodeGray16(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
    82  	buf := make([]byte, dx*2)
    83  	for y := 0; y < dy; y++ {
    84  		min := y*stride + 0
    85  		max := y*stride + dx*2
    86  		off := 0
    87  		var v0 uint16
    88  		for i := min; i < max; i += 2 {
    89  			// An image.Gray16's Pix is in big-endian order.
    90  			v1 := uint16(pix[i])<<8 | uint16(pix[i+1])
    91  			if predictor {
    92  				v0, v1 = v1, v1-v0
    93  			}
    94  			// We only write little-endian TIFF files.
    95  			buf[off+0] = byte(v1)
    96  			buf[off+1] = byte(v1 >> 8)
    97  			off += 2
    98  		}
    99  		if _, err := w.Write(buf); err != nil {
   100  			return err
   101  		}
   102  	}
   103  	return nil
   104  }
   105  
   106  func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
   107  	if !predictor {
   108  		return writePix(w, pix, dy, dx*4, stride)
   109  	}
   110  	buf := make([]byte, dx*4)
   111  	for y := 0; y < dy; y++ {
   112  		min := y*stride + 0
   113  		max := y*stride + dx*4
   114  		off := 0
   115  		var r0, g0, b0, a0 uint8
   116  		for i := min; i < max; i += 4 {
   117  			r1, g1, b1, a1 := pix[i+0], pix[i+1], pix[i+2], pix[i+3]
   118  			buf[off+0] = r1 - r0
   119  			buf[off+1] = g1 - g0
   120  			buf[off+2] = b1 - b0
   121  			buf[off+3] = a1 - a0
   122  			off += 4
   123  			r0, g0, b0, a0 = r1, g1, b1, a1
   124  		}
   125  		if _, err := w.Write(buf); err != nil {
   126  			return err
   127  		}
   128  	}
   129  	return nil
   130  }
   131  
   132  func encodeRGBA64(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
   133  	buf := make([]byte, dx*8)
   134  	for y := 0; y < dy; y++ {
   135  		min := y*stride + 0
   136  		max := y*stride + dx*8
   137  		off := 0
   138  		var r0, g0, b0, a0 uint16
   139  		for i := min; i < max; i += 8 {
   140  			// An image.RGBA64's Pix is in big-endian order.
   141  			r1 := uint16(pix[i+0])<<8 | uint16(pix[i+1])
   142  			g1 := uint16(pix[i+2])<<8 | uint16(pix[i+3])
   143  			b1 := uint16(pix[i+4])<<8 | uint16(pix[i+5])
   144  			a1 := uint16(pix[i+6])<<8 | uint16(pix[i+7])
   145  			if predictor {
   146  				r0, r1 = r1, r1-r0
   147  				g0, g1 = g1, g1-g0
   148  				b0, b1 = b1, b1-b0
   149  				a0, a1 = a1, a1-a0
   150  			}
   151  			// We only write little-endian TIFF files.
   152  			buf[off+0] = byte(r1)
   153  			buf[off+1] = byte(r1 >> 8)
   154  			buf[off+2] = byte(g1)
   155  			buf[off+3] = byte(g1 >> 8)
   156  			buf[off+4] = byte(b1)
   157  			buf[off+5] = byte(b1 >> 8)
   158  			buf[off+6] = byte(a1)
   159  			buf[off+7] = byte(a1 >> 8)
   160  			off += 8
   161  		}
   162  		if _, err := w.Write(buf); err != nil {
   163  			return err
   164  		}
   165  	}
   166  	return nil
   167  }
   168  
   169  func encode(w io.Writer, m image.Image, predictor bool) error {
   170  	bounds := m.Bounds()
   171  	buf := make([]byte, 4*bounds.Dx())
   172  	for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
   173  		off := 0
   174  		if predictor {
   175  			var r0, g0, b0, a0 uint8
   176  			for x := bounds.Min.X; x < bounds.Max.X; x++ {
   177  				r, g, b, a := m.At(x, y).RGBA()
   178  				r1 := uint8(r >> 8)
   179  				g1 := uint8(g >> 8)
   180  				b1 := uint8(b >> 8)
   181  				a1 := uint8(a >> 8)
   182  				buf[off+0] = r1 - r0
   183  				buf[off+1] = g1 - g0
   184  				buf[off+2] = b1 - b0
   185  				buf[off+3] = a1 - a0
   186  				off += 4
   187  				r0, g0, b0, a0 = r1, g1, b1, a1
   188  			}
   189  		} else {
   190  			for x := bounds.Min.X; x < bounds.Max.X; x++ {
   191  				r, g, b, a := m.At(x, y).RGBA()
   192  				buf[off+0] = uint8(r >> 8)
   193  				buf[off+1] = uint8(g >> 8)
   194  				buf[off+2] = uint8(b >> 8)
   195  				buf[off+3] = uint8(a >> 8)
   196  				off += 4
   197  			}
   198  		}
   199  		if _, err := w.Write(buf); err != nil {
   200  			return err
   201  		}
   202  	}
   203  	return nil
   204  }
   205  
   206  // writePix writes the internal byte array of an image to w. It is less general
   207  // but much faster then encode. writePix is used when pix directly
   208  // corresponds to one of the TIFF image types.
   209  func writePix(w io.Writer, pix []byte, nrows, length, stride int) error {
   210  	if length == stride {
   211  		_, err := w.Write(pix[:nrows*length])
   212  		return err
   213  	}
   214  	for ; nrows > 0; nrows-- {
   215  		if _, err := w.Write(pix[:length]); err != nil {
   216  			return err
   217  		}
   218  		pix = pix[stride:]
   219  	}
   220  	return nil
   221  }
   222  
   223  func writeIFD(w io.Writer, ifdOffset int, d []ifdEntry) error {
   224  	var buf [ifdLen]byte
   225  	// Make space for "pointer area" containing IFD entry data
   226  	// longer than 4 bytes.
   227  	parea := make([]byte, 1024)
   228  	pstart := ifdOffset + ifdLen*len(d) + 6
   229  	var o int // Current offset in parea.
   230  
   231  	// The IFD has to be written with the tags in ascending order.
   232  	sort.Sort(byTag(d))
   233  
   234  	// Write the number of entries in this IFD.
   235  	if err := binary.Write(w, enc, uint16(len(d))); err != nil {
   236  		return err
   237  	}
   238  	for _, ent := range d {
   239  		enc.PutUint16(buf[0:2], uint16(ent.tag))
   240  		enc.PutUint16(buf[2:4], uint16(ent.datatype))
   241  		count := uint32(len(ent.data))
   242  		if ent.datatype == dtRational {
   243  			count /= 2
   244  		}
   245  		enc.PutUint32(buf[4:8], count)
   246  		datalen := int(count * lengths[ent.datatype])
   247  		if datalen <= 4 {
   248  			ent.putData(buf[8:12])
   249  		} else {
   250  			if (o + datalen) > len(parea) {
   251  				newlen := len(parea) + 1024
   252  				for (o + datalen) > newlen {
   253  					newlen += 1024
   254  				}
   255  				newarea := make([]byte, newlen)
   256  				copy(newarea, parea)
   257  				parea = newarea
   258  			}
   259  			ent.putData(parea[o : o+datalen])
   260  			enc.PutUint32(buf[8:12], uint32(pstart+o))
   261  			o += datalen
   262  		}
   263  		if _, err := w.Write(buf[:]); err != nil {
   264  			return err
   265  		}
   266  	}
   267  	// The IFD ends with the offset of the next IFD in the file,
   268  	// or zero if it is the last one (page 14).
   269  	if err := binary.Write(w, enc, uint32(0)); err != nil {
   270  		return err
   271  	}
   272  	_, err := w.Write(parea[:o])
   273  	return err
   274  }
   275  
   276  // Options are the encoding parameters.
   277  type Options struct {
   278  	// Compression is the type of compression used.
   279  	Compression CompressionType
   280  	// Predictor determines whether a differencing predictor is used;
   281  	// if true, instead of each pixel's color, the color difference to the
   282  	// preceding one is saved.  This improves the compression for certain
   283  	// types of images and compressors. For example, it works well for
   284  	// photos with Deflate compression.
   285  	Predictor bool
   286  }
   287  
   288  // Encode writes the image m to w. opt determines the options used for
   289  // encoding, such as the compression type. If opt is nil, an uncompressed
   290  // image is written.
   291  func Encode(w io.Writer, m image.Image, opt *Options) error {
   292  	d := m.Bounds().Size()
   293  
   294  	compression := uint32(cNone)
   295  	predictor := false
   296  	if opt != nil {
   297  		compression = opt.Compression.specValue()
   298  		// The predictor field is only used with LZW. See page 64 of the spec.
   299  		predictor = opt.Predictor && compression == cLZW
   300  	}
   301  
   302  	_, err := io.WriteString(w, leHeader)
   303  	if err != nil {
   304  		return err
   305  	}
   306  
   307  	// Compressed data is written into a buffer first, so that we
   308  	// know the compressed size.
   309  	var buf bytes.Buffer
   310  	// dst holds the destination for the pixel data of the image --
   311  	// either w or a writer to buf.
   312  	var dst io.Writer
   313  	// imageLen is the length of the pixel data in bytes.
   314  	// The offset of the IFD is imageLen + 8 header bytes.
   315  	var imageLen int
   316  
   317  	switch compression {
   318  	case cNone:
   319  		dst = w
   320  		// Write IFD offset before outputting pixel data.
   321  		switch m.(type) {
   322  		case *image.Paletted:
   323  			imageLen = d.X * d.Y * 1
   324  		case *image.Gray:
   325  			imageLen = d.X * d.Y * 1
   326  		case *image.Gray16:
   327  			imageLen = d.X * d.Y * 2
   328  		case *image.RGBA64:
   329  			imageLen = d.X * d.Y * 8
   330  		case *image.NRGBA64:
   331  			imageLen = d.X * d.Y * 8
   332  		default:
   333  			imageLen = d.X * d.Y * 4
   334  		}
   335  		err = binary.Write(w, enc, uint32(imageLen+8))
   336  		if err != nil {
   337  			return err
   338  		}
   339  	case cDeflate:
   340  		dst = zlib.NewWriter(&buf)
   341  	}
   342  
   343  	pr := uint32(prNone)
   344  	photometricInterpretation := uint32(pRGB)
   345  	samplesPerPixel := uint32(4)
   346  	bitsPerSample := []uint32{8, 8, 8, 8}
   347  	extraSamples := uint32(0)
   348  	colorMap := []uint32{}
   349  
   350  	if predictor {
   351  		pr = prHorizontal
   352  	}
   353  	switch m := m.(type) {
   354  	case *image.Paletted:
   355  		photometricInterpretation = pPaletted
   356  		samplesPerPixel = 1
   357  		bitsPerSample = []uint32{8}
   358  		colorMap = make([]uint32, 256*3)
   359  		for i := 0; i < 256 && i < len(m.Palette); i++ {
   360  			r, g, b, _ := m.Palette[i].RGBA()
   361  			colorMap[i+0*256] = uint32(r)
   362  			colorMap[i+1*256] = uint32(g)
   363  			colorMap[i+2*256] = uint32(b)
   364  		}
   365  		err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
   366  	case *image.Gray:
   367  		photometricInterpretation = pBlackIsZero
   368  		samplesPerPixel = 1
   369  		bitsPerSample = []uint32{8}
   370  		err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
   371  	case *image.Gray16:
   372  		photometricInterpretation = pBlackIsZero
   373  		samplesPerPixel = 1
   374  		bitsPerSample = []uint32{16}
   375  		err = encodeGray16(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
   376  	case *image.NRGBA:
   377  		extraSamples = 2 // Unassociated alpha.
   378  		err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
   379  	case *image.NRGBA64:
   380  		extraSamples = 2 // Unassociated alpha.
   381  		bitsPerSample = []uint32{16, 16, 16, 16}
   382  		err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
   383  	case *image.RGBA:
   384  		extraSamples = 1 // Associated alpha.
   385  		err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
   386  	case *image.RGBA64:
   387  		extraSamples = 1 // Associated alpha.
   388  		bitsPerSample = []uint32{16, 16, 16, 16}
   389  		err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
   390  	default:
   391  		extraSamples = 1 // Associated alpha.
   392  		err = encode(dst, m, predictor)
   393  	}
   394  	if err != nil {
   395  		return err
   396  	}
   397  
   398  	if compression != cNone {
   399  		if err = dst.(io.Closer).Close(); err != nil {
   400  			return err
   401  		}
   402  		imageLen = buf.Len()
   403  		if err = binary.Write(w, enc, uint32(imageLen+8)); err != nil {
   404  			return err
   405  		}
   406  		if _, err = buf.WriteTo(w); err != nil {
   407  			return err
   408  		}
   409  	}
   410  
   411  	ifd := []ifdEntry{
   412  		{tImageWidth, dtShort, []uint32{uint32(d.X)}},
   413  		{tImageLength, dtShort, []uint32{uint32(d.Y)}},
   414  		{tBitsPerSample, dtShort, bitsPerSample},
   415  		{tCompression, dtShort, []uint32{compression}},
   416  		{tPhotometricInterpretation, dtShort, []uint32{photometricInterpretation}},
   417  		{tStripOffsets, dtLong, []uint32{8}},
   418  		{tSamplesPerPixel, dtShort, []uint32{samplesPerPixel}},
   419  		{tRowsPerStrip, dtShort, []uint32{uint32(d.Y)}},
   420  		{tStripByteCounts, dtLong, []uint32{uint32(imageLen)}},
   421  		// There is currently no support for storing the image
   422  		// resolution, so give a bogus value of 72x72 dpi.
   423  		{tXResolution, dtRational, []uint32{72, 1}},
   424  		{tYResolution, dtRational, []uint32{72, 1}},
   425  		{tResolutionUnit, dtShort, []uint32{resPerInch}},
   426  	}
   427  	if pr != prNone {
   428  		ifd = append(ifd, ifdEntry{tPredictor, dtShort, []uint32{pr}})
   429  	}
   430  	if len(colorMap) != 0 {
   431  		ifd = append(ifd, ifdEntry{tColorMap, dtShort, colorMap})
   432  	}
   433  	if extraSamples > 0 {
   434  		ifd = append(ifd, ifdEntry{tExtraSamples, dtShort, []uint32{extraSamples}})
   435  	}
   436  
   437  	return writeIFD(w, imageLen+8, ifd)
   438  }