1
2
3
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
18
19
20
21
22
23
24
25
26 var enc = binary.LittleEndian
27
28
29
30
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
91 v1 := uint16(pix[i])<<8 | uint16(pix[i+1])
92 if predictor {
93 v0, v1 = v1, v1-v0
94 }
95
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
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
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
208
209
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
227
228 parea := make([]byte, 1024)
229 pstart := ifdOffset + ifdLen*len(d) + 6
230 var o int
231
232
233 sort.Sort(byTag(d))
234
235
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
269
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
278 type Options struct {
279
280 Compression CompressionType
281
282
283
284
285
286 Predictor bool
287 }
288
289
290
291
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
300 predictor = opt.Predictor && compression == cLZW
301 }
302
303 _, err := io.WriteString(w, leHeader)
304 if err != nil {
305 return err
306 }
307
308
309
310 var buf bytes.Buffer
311
312
313 var dst io.Writer
314
315
316 var imageLen int
317
318 switch compression {
319 case cNone:
320 dst = w
321
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
381 err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
382 case *image.NRGBA64:
383 extraSamples = 2
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
388 err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
389 case *image.RGBA64:
390 extraSamples = 1
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
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
425
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