git.lucas.co / go_mono
git clone https://git.lucas.co/go_mono.git

tiff/writer.go (11.6K)

  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 }