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