writer.go raw

   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