...

Source file src/golang.org/x/image/tiff/writer.go

Documentation: golang.org/x/image/tiff

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

View as plain text