gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

writer.go (11878B)


      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 }