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