aboutsummaryrefslogtreecommitdiff
path: root/vendor/golang.org/x/image/tiff
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/image/tiff')
-rw-r--r--vendor/golang.org/x/image/tiff/buffer.go69
-rw-r--r--vendor/golang.org/x/image/tiff/compress.go58
-rw-r--r--vendor/golang.org/x/image/tiff/consts.go133
-rw-r--r--vendor/golang.org/x/image/tiff/lzw/reader.go272
-rw-r--r--vendor/golang.org/x/image/tiff/reader.go684
-rw-r--r--vendor/golang.org/x/image/tiff/writer.go438
6 files changed, 1654 insertions, 0 deletions
diff --git a/vendor/golang.org/x/image/tiff/buffer.go b/vendor/golang.org/x/image/tiff/buffer.go
new file mode 100644
index 0000000..d1801be
--- /dev/null
+++ b/vendor/golang.org/x/image/tiff/buffer.go
@@ -0,0 +1,69 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tiff
+
+import "io"
+
+// buffer buffers an io.Reader to satisfy io.ReaderAt.
+type buffer struct {
+ r io.Reader
+ buf []byte
+}
+
+// fill reads data from b.r until the buffer contains at least end bytes.
+func (b *buffer) fill(end int) error {
+ m := len(b.buf)
+ if end > m {
+ if end > cap(b.buf) {
+ newcap := 1024
+ for newcap < end {
+ newcap *= 2
+ }
+ newbuf := make([]byte, end, newcap)
+ copy(newbuf, b.buf)
+ b.buf = newbuf
+ } else {
+ b.buf = b.buf[:end]
+ }
+ if n, err := io.ReadFull(b.r, b.buf[m:end]); err != nil {
+ end = m + n
+ b.buf = b.buf[:end]
+ return err
+ }
+ }
+ return nil
+}
+
+func (b *buffer) ReadAt(p []byte, off int64) (int, error) {
+ o := int(off)
+ end := o + len(p)
+ if int64(end) != off+int64(len(p)) {
+ return 0, io.ErrUnexpectedEOF
+ }
+
+ err := b.fill(end)
+ return copy(p, b.buf[o:end]), err
+}
+
+// Slice returns a slice of the underlying buffer. The slice contains
+// n bytes starting at offset off.
+func (b *buffer) Slice(off, n int) ([]byte, error) {
+ end := off + n
+ if err := b.fill(end); err != nil {
+ return nil, err
+ }
+ return b.buf[off:end], nil
+}
+
+// newReaderAt converts an io.Reader into an io.ReaderAt.
+func newReaderAt(r io.Reader) io.ReaderAt {
+ if ra, ok := r.(io.ReaderAt); ok {
+ return ra
+ }
+ return &buffer{
+ r: r,
+ buf: make([]byte, 0, 1024),
+ }
+}
diff --git a/vendor/golang.org/x/image/tiff/compress.go b/vendor/golang.org/x/image/tiff/compress.go
new file mode 100644
index 0000000..3f176f0
--- /dev/null
+++ b/vendor/golang.org/x/image/tiff/compress.go
@@ -0,0 +1,58 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tiff
+
+import (
+ "bufio"
+ "io"
+)
+
+type byteReader interface {
+ io.Reader
+ io.ByteReader
+}
+
+// unpackBits decodes the PackBits-compressed data in src and returns the
+// uncompressed data.
+//
+// The PackBits compression format is described in section 9 (p. 42)
+// of the TIFF spec.
+func unpackBits(r io.Reader) ([]byte, error) {
+ buf := make([]byte, 128)
+ dst := make([]byte, 0, 1024)
+ br, ok := r.(byteReader)
+ if !ok {
+ br = bufio.NewReader(r)
+ }
+
+ for {
+ b, err := br.ReadByte()
+ if err != nil {
+ if err == io.EOF {
+ return dst, nil
+ }
+ return nil, err
+ }
+ code := int(int8(b))
+ switch {
+ case code >= 0:
+ n, err := io.ReadFull(br, buf[:code+1])
+ if err != nil {
+ return nil, err
+ }
+ dst = append(dst, buf[:n]...)
+ case code == -128:
+ // No-op.
+ default:
+ if b, err = br.ReadByte(); err != nil {
+ return nil, err
+ }
+ for j := 0; j < 1-code; j++ {
+ buf[j] = b
+ }
+ dst = append(dst, buf[:1-code]...)
+ }
+ }
+}
diff --git a/vendor/golang.org/x/image/tiff/consts.go b/vendor/golang.org/x/image/tiff/consts.go
new file mode 100644
index 0000000..3c51a70
--- /dev/null
+++ b/vendor/golang.org/x/image/tiff/consts.go
@@ -0,0 +1,133 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tiff
+
+// A tiff image file contains one or more images. The metadata
+// of each image is contained in an Image File Directory (IFD),
+// which contains entries of 12 bytes each and is described
+// on page 14-16 of the specification. An IFD entry consists of
+//
+// - a tag, which describes the signification of the entry,
+// - the data type and length of the entry,
+// - the data itself or a pointer to it if it is more than 4 bytes.
+//
+// The presence of a length means that each IFD is effectively an array.
+
+const (
+ leHeader = "II\x2A\x00" // Header for little-endian files.
+ beHeader = "MM\x00\x2A" // Header for big-endian files.
+
+ ifdLen = 12 // Length of an IFD entry in bytes.
+)
+
+// Data types (p. 14-16 of the spec).
+const (
+ dtByte = 1
+ dtASCII = 2
+ dtShort = 3
+ dtLong = 4
+ dtRational = 5
+)
+
+// The length of one instance of each data type in bytes.
+var lengths = [...]uint32{0, 1, 1, 2, 4, 8}
+
+// Tags (see p. 28-41 of the spec).
+const (
+ tImageWidth = 256
+ tImageLength = 257
+ tBitsPerSample = 258
+ tCompression = 259
+ tPhotometricInterpretation = 262
+
+ tStripOffsets = 273
+ tSamplesPerPixel = 277
+ tRowsPerStrip = 278
+ tStripByteCounts = 279
+
+ tTileWidth = 322
+ tTileLength = 323
+ tTileOffsets = 324
+ tTileByteCounts = 325
+
+ tXResolution = 282
+ tYResolution = 283
+ tResolutionUnit = 296
+
+ tPredictor = 317
+ tColorMap = 320
+ tExtraSamples = 338
+ tSampleFormat = 339
+)
+
+// Compression types (defined in various places in the spec and supplements).
+const (
+ cNone = 1
+ cCCITT = 2
+ cG3 = 3 // Group 3 Fax.
+ cG4 = 4 // Group 4 Fax.
+ cLZW = 5
+ cJPEGOld = 6 // Superseded by cJPEG.
+ cJPEG = 7
+ cDeflate = 8 // zlib compression.
+ cPackBits = 32773
+ cDeflateOld = 32946 // Superseded by cDeflate.
+)
+
+// Photometric interpretation values (see p. 37 of the spec).
+const (
+ pWhiteIsZero = 0
+ pBlackIsZero = 1
+ pRGB = 2
+ pPaletted = 3
+ pTransMask = 4 // transparency mask
+ pCMYK = 5
+ pYCbCr = 6
+ pCIELab = 8
+)
+
+// Values for the tPredictor tag (page 64-65 of the spec).
+const (
+ prNone = 1
+ prHorizontal = 2
+)
+
+// Values for the tResolutionUnit tag (page 18).
+const (
+ resNone = 1
+ resPerInch = 2 // Dots per inch.
+ resPerCM = 3 // Dots per centimeter.
+)
+
+// imageMode represents the mode of the image.
+type imageMode int
+
+const (
+ mBilevel imageMode = iota
+ mPaletted
+ mGray
+ mGrayInvert
+ mRGB
+ mRGBA
+ mNRGBA
+)
+
+// CompressionType describes the type of compression used in Options.
+type CompressionType int
+
+const (
+ Uncompressed CompressionType = iota
+ Deflate
+)
+
+// specValue returns the compression type constant from the TIFF spec that
+// is equivalent to c.
+func (c CompressionType) specValue() uint32 {
+ switch c {
+ case Deflate:
+ return cDeflate
+ }
+ return cNone
+}
diff --git a/vendor/golang.org/x/image/tiff/lzw/reader.go b/vendor/golang.org/x/image/tiff/lzw/reader.go
new file mode 100644
index 0000000..51ae39f
--- /dev/null
+++ b/vendor/golang.org/x/image/tiff/lzw/reader.go
@@ -0,0 +1,272 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package lzw implements the Lempel-Ziv-Welch compressed data format,
+// described in T. A. Welch, ``A Technique for High-Performance Data
+// Compression'', Computer, 17(6) (June 1984), pp 8-19.
+//
+// In particular, it implements LZW as used by the TIFF file format, including
+// an "off by one" algorithmic difference when compared to standard LZW.
+package lzw // import "golang.org/x/image/tiff/lzw"
+
+/*
+This file was branched from src/pkg/compress/lzw/reader.go in the
+standard library. Differences from the original are marked with "NOTE".
+
+The tif_lzw.c file in the libtiff C library has this comment:
+
+----
+The 5.0 spec describes a different algorithm than Aldus
+implements. Specifically, Aldus does code length transitions
+one code earlier than should be done (for real LZW).
+Earlier versions of this library implemented the correct
+LZW algorithm, but emitted codes in a bit order opposite
+to the TIFF spec. Thus, to maintain compatibility w/ Aldus
+we interpret MSB-LSB ordered codes to be images written w/
+old versions of this library, but otherwise adhere to the
+Aldus "off by one" algorithm.
+----
+
+The Go code doesn't read (invalid) TIFF files written by old versions of
+libtiff, but the LZW algorithm in this package still differs from the one in
+Go's standard package library to accomodate this "off by one" in valid TIFFs.
+*/
+
+import (
+ "bufio"
+ "errors"
+ "fmt"
+ "io"
+)
+
+// Order specifies the bit ordering in an LZW data stream.
+type Order int
+
+const (
+ // LSB means Least Significant Bits first, as used in the GIF file format.
+ LSB Order = iota
+ // MSB means Most Significant Bits first, as used in the TIFF and PDF
+ // file formats.
+ MSB
+)
+
+const (
+ maxWidth = 12
+ decoderInvalidCode = 0xffff
+ flushBuffer = 1 << maxWidth
+)
+
+// decoder is the state from which the readXxx method converts a byte
+// stream into a code stream.
+type decoder struct {
+ r io.ByteReader
+ bits uint32
+ nBits uint
+ width uint
+ read func(*decoder) (uint16, error) // readLSB or readMSB
+ litWidth int // width in bits of literal codes
+ err error
+
+ // The first 1<<litWidth codes are literal codes.
+ // The next two codes mean clear and EOF.
+ // Other valid codes are in the range [lo, hi] where lo := clear + 2,
+ // with the upper bound incrementing on each code seen.
+ // overflow is the code at which hi overflows the code width. NOTE: TIFF's LZW is "off by one".
+ // last is the most recently seen code, or decoderInvalidCode.
+ clear, eof, hi, overflow, last uint16
+
+ // Each code c in [lo, hi] expands to two or more bytes. For c != hi:
+ // suffix[c] is the last of these bytes.
+ // prefix[c] is the code for all but the last byte.
+ // This code can either be a literal code or another code in [lo, c).
+ // The c == hi case is a special case.
+ suffix [1 << maxWidth]uint8
+ prefix [1 << maxWidth]uint16
+
+ // output is the temporary output buffer.
+ // Literal codes are accumulated from the start of the buffer.
+ // Non-literal codes decode to a sequence of suffixes that are first
+ // written right-to-left from the end of the buffer before being copied
+ // to the start of the buffer.
+ // It is flushed when it contains >= 1<<maxWidth bytes,
+ // so that there is always room to decode an entire code.
+ output [2 * 1 << maxWidth]byte
+ o int // write index into output
+ toRead []byte // bytes to return from Read
+}
+
+// readLSB returns the next code for "Least Significant Bits first" data.
+func (d *decoder) readLSB() (uint16, error) {
+ for d.nBits < d.width {
+ x, err := d.r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ d.bits |= uint32(x) << d.nBits
+ d.nBits += 8
+ }
+ code := uint16(d.bits & (1<<d.width - 1))
+ d.bits >>= d.width
+ d.nBits -= d.width
+ return code, nil
+}
+
+// readMSB returns the next code for "Most Significant Bits first" data.
+func (d *decoder) readMSB() (uint16, error) {
+ for d.nBits < d.width {
+ x, err := d.r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ d.bits |= uint32(x) << (24 - d.nBits)
+ d.nBits += 8
+ }
+ code := uint16(d.bits >> (32 - d.width))
+ d.bits <<= d.width
+ d.nBits -= d.width
+ return code, nil
+}
+
+func (d *decoder) Read(b []byte) (int, error) {
+ for {
+ if len(d.toRead) > 0 {
+ n := copy(b, d.toRead)
+ d.toRead = d.toRead[n:]
+ return n, nil
+ }
+ if d.err != nil {
+ return 0, d.err
+ }
+ d.decode()
+ }
+}
+
+// decode decompresses bytes from r and leaves them in d.toRead.
+// read specifies how to decode bytes into codes.
+// litWidth is the width in bits of literal codes.
+func (d *decoder) decode() {
+ // Loop over the code stream, converting codes into decompressed bytes.
+loop:
+ for {
+ code, err := d.read(d)
+ if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ d.err = err
+ break
+ }
+ switch {
+ case code < d.clear:
+ // We have a literal code.
+ d.output[d.o] = uint8(code)
+ d.o++
+ if d.last != decoderInvalidCode {
+ // Save what the hi code expands to.
+ d.suffix[d.hi] = uint8(code)
+ d.prefix[d.hi] = d.last
+ }
+ case code == d.clear:
+ d.width = 1 + uint(d.litWidth)
+ d.hi = d.eof
+ d.overflow = 1 << d.width
+ d.last = decoderInvalidCode
+ continue
+ case code == d.eof:
+ d.err = io.EOF
+ break loop
+ case code <= d.hi:
+ c, i := code, len(d.output)-1
+ if code == d.hi {
+ // code == hi is a special case which expands to the last expansion
+ // followed by the head of the last expansion. To find the head, we walk
+ // the prefix chain until we find a literal code.
+ c = d.last
+ for c >= d.clear {
+ c = d.prefix[c]
+ }
+ d.output[i] = uint8(c)
+ i--
+ c = d.last
+ }
+ // Copy the suffix chain into output and then write that to w.
+ for c >= d.clear {
+ d.output[i] = d.suffix[c]
+ i--
+ c = d.prefix[c]
+ }
+ d.output[i] = uint8(c)
+ d.o += copy(d.output[d.o:], d.output[i:])
+ if d.last != decoderInvalidCode {
+ // Save what the hi code expands to.
+ d.suffix[d.hi] = uint8(c)
+ d.prefix[d.hi] = d.last
+ }
+ default:
+ d.err = errors.New("lzw: invalid code")
+ break loop
+ }
+ d.last, d.hi = code, d.hi+1
+ if d.hi+1 >= d.overflow { // NOTE: the "+1" is where TIFF's LZW differs from the standard algorithm.
+ if d.width == maxWidth {
+ d.last = decoderInvalidCode
+ } else {
+ d.width++
+ d.overflow <<= 1
+ }
+ }
+ if d.o >= flushBuffer {
+ break
+ }
+ }
+ // Flush pending output.
+ d.toRead = d.output[:d.o]
+ d.o = 0
+}
+
+var errClosed = errors.New("lzw: reader/writer is closed")
+
+func (d *decoder) Close() error {
+ d.err = errClosed // in case any Reads come along
+ return nil
+}
+
+// NewReader creates a new io.ReadCloser.
+// Reads from the returned io.ReadCloser read and decompress data from r.
+// If r does not also implement io.ByteReader,
+// the decompressor may read more data than necessary from r.
+// It is the caller's responsibility to call Close on the ReadCloser when
+// finished reading.
+// The number of bits to use for literal codes, litWidth, must be in the
+// range [2,8] and is typically 8. It must equal the litWidth
+// used during compression.
+func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser {
+ d := new(decoder)
+ switch order {
+ case LSB:
+ d.read = (*decoder).readLSB
+ case MSB:
+ d.read = (*decoder).readMSB
+ default:
+ d.err = errors.New("lzw: unknown order")
+ return d
+ }
+ if litWidth < 2 || 8 < litWidth {
+ d.err = fmt.Errorf("lzw: litWidth %d out of range", litWidth)
+ return d
+ }
+ if br, ok := r.(io.ByteReader); ok {
+ d.r = br
+ } else {
+ d.r = bufio.NewReader(r)
+ }
+ d.litWidth = litWidth
+ d.width = 1 + uint(litWidth)
+ d.clear = uint16(1) << uint(litWidth)
+ d.eof, d.hi = d.clear+1, d.clear+1
+ d.overflow = uint16(1) << d.width
+ d.last = decoderInvalidCode
+
+ return d
+}
diff --git a/vendor/golang.org/x/image/tiff/reader.go b/vendor/golang.org/x/image/tiff/reader.go
new file mode 100644
index 0000000..8a941c1
--- /dev/null
+++ b/vendor/golang.org/x/image/tiff/reader.go
@@ -0,0 +1,684 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tiff implements a TIFF image decoder and encoder.
+//
+// The TIFF specification is at http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
+package tiff // import "golang.org/x/image/tiff"
+
+import (
+ "compress/zlib"
+ "encoding/binary"
+ "fmt"
+ "image"
+ "image/color"
+ "io"
+ "io/ioutil"
+ "math"
+
+ "golang.org/x/image/tiff/lzw"
+)
+
+// A FormatError reports that the input is not a valid TIFF image.
+type FormatError string
+
+func (e FormatError) Error() string {
+ return "tiff: invalid format: " + string(e)
+}
+
+// An UnsupportedError reports that the input uses a valid but
+// unimplemented feature.
+type UnsupportedError string
+
+func (e UnsupportedError) Error() string {
+ return "tiff: unsupported feature: " + string(e)
+}
+
+var errNoPixels = FormatError("not enough pixel data")
+
+type decoder struct {
+ r io.ReaderAt
+ byteOrder binary.ByteOrder
+ config image.Config
+ mode imageMode
+ bpp uint
+ features map[int][]uint
+ palette []color.Color
+
+ buf []byte
+ off int // Current offset in buf.
+ v uint32 // Buffer value for reading with arbitrary bit depths.
+ nbits uint // Remaining number of bits in v.
+}
+
+// firstVal returns the first uint of the features entry with the given tag,
+// or 0 if the tag does not exist.
+func (d *decoder) firstVal(tag int) uint {
+ f := d.features[tag]
+ if len(f) == 0 {
+ return 0
+ }
+ return f[0]
+}
+
+// ifdUint decodes the IFD entry in p, which must be of the Byte, Short
+// or Long type, and returns the decoded uint values.
+func (d *decoder) ifdUint(p []byte) (u []uint, err error) {
+ var raw []byte
+ if len(p) < ifdLen {
+ return nil, FormatError("bad IFD entry")
+ }
+
+ datatype := d.byteOrder.Uint16(p[2:4])
+ if dt := int(datatype); dt <= 0 || dt >= len(lengths) {
+ return nil, UnsupportedError("IFD entry datatype")
+ }
+
+ count := d.byteOrder.Uint32(p[4:8])
+ if count > math.MaxInt32/lengths[datatype] {
+ return nil, FormatError("IFD data too large")
+ }
+ if datalen := lengths[datatype] * count; datalen > 4 {
+ // The IFD contains a pointer to the real value.
+ raw = make([]byte, datalen)
+ _, err = d.r.ReadAt(raw, int64(d.byteOrder.Uint32(p[8:12])))
+ } else {
+ raw = p[8 : 8+datalen]
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ u = make([]uint, count)
+ switch datatype {
+ case dtByte:
+ for i := uint32(0); i < count; i++ {
+ u[i] = uint(raw[i])
+ }
+ case dtShort:
+ for i := uint32(0); i < count; i++ {
+ u[i] = uint(d.byteOrder.Uint16(raw[2*i : 2*(i+1)]))
+ }
+ case dtLong:
+ for i := uint32(0); i < count; i++ {
+ u[i] = uint(d.byteOrder.Uint32(raw[4*i : 4*(i+1)]))
+ }
+ default:
+ return nil, UnsupportedError("data type")
+ }
+ return u, nil
+}
+
+// parseIFD decides whether the the IFD entry in p is "interesting" and
+// stows away the data in the decoder. It returns the tag number of the
+// entry and an error, if any.
+func (d *decoder) parseIFD(p []byte) (int, error) {
+ tag := d.byteOrder.Uint16(p[0:2])
+ switch tag {
+ case tBitsPerSample,
+ tExtraSamples,
+ tPhotometricInterpretation,
+ tCompression,
+ tPredictor,
+ tStripOffsets,
+ tStripByteCounts,
+ tRowsPerStrip,
+ tTileWidth,
+ tTileLength,
+ tTileOffsets,
+ tTileByteCounts,
+ tImageLength,
+ tImageWidth:
+ val, err := d.ifdUint(p)
+ if err != nil {
+ return 0, err
+ }
+ d.features[int(tag)] = val
+ case tColorMap:
+ val, err := d.ifdUint(p)
+ if err != nil {
+ return 0, err
+ }
+ numcolors := len(val) / 3
+ if len(val)%3 != 0 || numcolors <= 0 || numcolors > 256 {
+ return 0, FormatError("bad ColorMap length")
+ }
+ d.palette = make([]color.Color, numcolors)
+ for i := 0; i < numcolors; i++ {
+ d.palette[i] = color.RGBA64{
+ uint16(val[i]),
+ uint16(val[i+numcolors]),
+ uint16(val[i+2*numcolors]),
+ 0xffff,
+ }
+ }
+ case tSampleFormat:
+ // Page 27 of the spec: If the SampleFormat is present and
+ // the value is not 1 [= unsigned integer data], a Baseline
+ // TIFF reader that cannot handle the SampleFormat value
+ // must terminate the import process gracefully.
+ val, err := d.ifdUint(p)
+ if err != nil {
+ return 0, err
+ }
+ for _, v := range val {
+ if v != 1 {
+ return 0, UnsupportedError("sample format")
+ }
+ }
+ }
+ return int(tag), nil
+}
+
+// readBits reads n bits from the internal buffer starting at the current offset.
+func (d *decoder) readBits(n uint) (v uint32, ok bool) {
+ for d.nbits < n {
+ d.v <<= 8
+ if d.off >= len(d.buf) {
+ return 0, false
+ }
+ d.v |= uint32(d.buf[d.off])
+ d.off++
+ d.nbits += 8
+ }
+ d.nbits -= n
+ rv := d.v >> d.nbits
+ d.v &^= rv << d.nbits
+ return rv, true
+}
+
+// flushBits discards the unread bits in the buffer used by readBits.
+// It is used at the end of a line.
+func (d *decoder) flushBits() {
+ d.v = 0
+ d.nbits = 0
+}
+
+// minInt returns the smaller of x or y.
+func minInt(a, b int) int {
+ if a <= b {
+ return a
+ }
+ return b
+}
+
+// decode decodes the raw data of an image.
+// It reads from d.buf and writes the strip or tile into dst.
+func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error {
+ d.off = 0
+
+ // Apply horizontal predictor if necessary.
+ // In this case, p contains the color difference to the preceding pixel.
+ // See page 64-65 of the spec.
+ if d.firstVal(tPredictor) == prHorizontal {
+ switch d.bpp {
+ case 16:
+ var off int
+ n := 2 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel
+ for y := ymin; y < ymax; y++ {
+ off += n
+ for x := 0; x < (xmax-xmin-1)*n; x += 2 {
+ if off+2 > len(d.buf) {
+ return errNoPixels
+ }
+ v0 := d.byteOrder.Uint16(d.buf[off-n : off-n+2])
+ v1 := d.byteOrder.Uint16(d.buf[off : off+2])
+ d.byteOrder.PutUint16(d.buf[off:off+2], v1+v0)
+ off += 2
+ }
+ }
+ case 8:
+ var off int
+ n := 1 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel
+ for y := ymin; y < ymax; y++ {
+ off += n
+ for x := 0; x < (xmax-xmin-1)*n; x++ {
+ if off >= len(d.buf) {
+ return errNoPixels
+ }
+ d.buf[off] += d.buf[off-n]
+ off++
+ }
+ }
+ case 1:
+ return UnsupportedError("horizontal predictor with 1 BitsPerSample")
+ }
+ }
+
+ rMaxX := minInt(xmax, dst.Bounds().Max.X)
+ rMaxY := minInt(ymax, dst.Bounds().Max.Y)
+ switch d.mode {
+ case mGray, mGrayInvert:
+ if d.bpp == 16 {
+ img := dst.(*image.Gray16)
+ for y := ymin; y < rMaxY; y++ {
+ for x := xmin; x < rMaxX; x++ {
+ if d.off+2 > len(d.buf) {
+ return errNoPixels
+ }
+ v := d.byteOrder.Uint16(d.buf[d.off : d.off+2])
+ d.off += 2
+ if d.mode == mGrayInvert {
+ v = 0xffff - v
+ }
+ img.SetGray16(x, y, color.Gray16{v})
+ }
+ if rMaxX == img.Bounds().Max.X {
+ d.off += 2 * (xmax - img.Bounds().Max.X)
+ }
+ }
+ } else {
+ img := dst.(*image.Gray)
+ max := uint32((1 << d.bpp) - 1)
+ for y := ymin; y < rMaxY; y++ {
+ for x := xmin; x < rMaxX; x++ {
+ v, ok := d.readBits(d.bpp)
+ if !ok {
+ return errNoPixels
+ }
+ v = v * 0xff / max
+ if d.mode == mGrayInvert {
+ v = 0xff - v
+ }
+ img.SetGray(x, y, color.Gray{uint8(v)})
+ }
+ d.flushBits()
+ }
+ }
+ case mPaletted:
+ img := dst.(*image.Paletted)
+ for y := ymin; y < rMaxY; y++ {
+ for x := xmin; x < rMaxX; x++ {
+ v, ok := d.readBits(d.bpp)
+ if !ok {
+ return errNoPixels
+ }
+ img.SetColorIndex(x, y, uint8(v))
+ }
+ d.flushBits()
+ }
+ case mRGB:
+ if d.bpp == 16 {
+ img := dst.(*image.RGBA64)
+ for y := ymin; y < rMaxY; y++ {
+ for x := xmin; x < rMaxX; x++ {
+ if d.off+6 > len(d.buf) {
+ return errNoPixels
+ }
+ r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2])
+ g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4])
+ b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6])
+ d.off += 6
+ img.SetRGBA64(x, y, color.RGBA64{r, g, b, 0xffff})
+ }
+ }
+ } else {
+ img := dst.(*image.RGBA)
+ for y := ymin; y < rMaxY; y++ {
+ min := img.PixOffset(xmin, y)
+ max := img.PixOffset(rMaxX, y)
+ off := (y - ymin) * (xmax - xmin) * 3
+ for i := min; i < max; i += 4 {
+ if off+3 > len(d.buf) {
+ return errNoPixels
+ }
+ img.Pix[i+0] = d.buf[off+0]
+ img.Pix[i+1] = d.buf[off+1]
+ img.Pix[i+2] = d.buf[off+2]
+ img.Pix[i+3] = 0xff
+ off += 3
+ }
+ }
+ }
+ case mNRGBA:
+ if d.bpp == 16 {
+ img := dst.(*image.NRGBA64)
+ for y := ymin; y < rMaxY; y++ {
+ for x := xmin; x < rMaxX; x++ {
+ if d.off+8 > len(d.buf) {
+ return errNoPixels
+ }
+ r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2])
+ g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4])
+ b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6])
+ a := d.byteOrder.Uint16(d.buf[d.off+6 : d.off+8])
+ d.off += 8
+ img.SetNRGBA64(x, y, color.NRGBA64{r, g, b, a})
+ }
+ }
+ } else {
+ img := dst.(*image.NRGBA)
+ for y := ymin; y < rMaxY; y++ {
+ min := img.PixOffset(xmin, y)
+ max := img.PixOffset(rMaxX, y)
+ i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4
+ if i1 > len(d.buf) {
+ return errNoPixels
+ }
+ copy(img.Pix[min:max], d.buf[i0:i1])
+ }
+ }
+ case mRGBA:
+ if d.bpp == 16 {
+ img := dst.(*image.RGBA64)
+ for y := ymin; y < rMaxY; y++ {
+ for x := xmin; x < rMaxX; x++ {
+ if d.off+8 > len(d.buf) {
+ return errNoPixels
+ }
+ r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2])
+ g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4])
+ b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6])
+ a := d.byteOrder.Uint16(d.buf[d.off+6 : d.off+8])
+ d.off += 8
+ img.SetRGBA64(x, y, color.RGBA64{r, g, b, a})
+ }
+ }
+ } else {
+ img := dst.(*image.RGBA)
+ for y := ymin; y < rMaxY; y++ {
+ min := img.PixOffset(xmin, y)
+ max := img.PixOffset(rMaxX, y)
+ i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4
+ if i1 > len(d.buf) {
+ return errNoPixels
+ }
+ copy(img.Pix[min:max], d.buf[i0:i1])
+ }
+ }
+ }
+
+ return nil
+}
+
+func newDecoder(r io.Reader) (*decoder, error) {
+ d := &decoder{
+ r: newReaderAt(r),
+ features: make(map[int][]uint),
+ }
+
+ p := make([]byte, 8)
+ if _, err := d.r.ReadAt(p, 0); err != nil {
+ return nil, err
+ }
+ switch string(p[0:4]) {
+ case leHeader:
+ d.byteOrder = binary.LittleEndian
+ case beHeader:
+ d.byteOrder = binary.BigEndian
+ default:
+ return nil, FormatError("malformed header")
+ }
+
+ ifdOffset := int64(d.byteOrder.Uint32(p[4:8]))
+
+ // The first two bytes contain the number of entries (12 bytes each).
+ if _, err := d.r.ReadAt(p[0:2], ifdOffset); err != nil {
+ return nil, err
+ }
+ numItems := int(d.byteOrder.Uint16(p[0:2]))
+
+ // All IFD entries are read in one chunk.
+ p = make([]byte, ifdLen*numItems)
+ if _, err := d.r.ReadAt(p, ifdOffset+2); err != nil {
+ return nil, err
+ }
+
+ prevTag := -1
+ for i := 0; i < len(p); i += ifdLen {
+ tag, err := d.parseIFD(p[i : i+ifdLen])
+ if err != nil {
+ return nil, err
+ }
+ if tag <= prevTag {
+ return nil, FormatError("tags are not sorted in ascending order")
+ }
+ prevTag = tag
+ }
+
+ d.config.Width = int(d.firstVal(tImageWidth))
+ d.config.Height = int(d.firstVal(tImageLength))
+
+ if _, ok := d.features[tBitsPerSample]; !ok {
+ return nil, FormatError("BitsPerSample tag missing")
+ }
+ d.bpp = d.firstVal(tBitsPerSample)
+ switch d.bpp {
+ case 0:
+ return nil, FormatError("BitsPerSample must not be 0")
+ case 1, 8, 16:
+ // Nothing to do, these are accepted by this implementation.
+ default:
+ return nil, UnsupportedError(fmt.Sprintf("BitsPerSample of %v", d.bpp))
+ }
+
+ // Determine the image mode.
+ switch d.firstVal(tPhotometricInterpretation) {
+ case pRGB:
+ if d.bpp == 16 {
+ for _, b := range d.features[tBitsPerSample] {
+ if b != 16 {
+ return nil, FormatError("wrong number of samples for 16bit RGB")
+ }
+ }
+ } else {
+ for _, b := range d.features[tBitsPerSample] {
+ if b != 8 {
+ return nil, FormatError("wrong number of samples for 8bit RGB")
+ }
+ }
+ }
+ // RGB images normally have 3 samples per pixel.
+ // If there are more, ExtraSamples (p. 31-32 of the spec)
+ // gives their meaning (usually an alpha channel).
+ //
+ // This implementation does not support extra samples
+ // of an unspecified type.
+ switch len(d.features[tBitsPerSample]) {
+ case 3:
+ d.mode = mRGB
+ if d.bpp == 16 {
+ d.config.ColorModel = color.RGBA64Model
+ } else {
+ d.config.ColorModel = color.RGBAModel
+ }
+ case 4:
+ switch d.firstVal(tExtraSamples) {
+ case 1:
+ d.mode = mRGBA
+ if d.bpp == 16 {
+ d.config.ColorModel = color.RGBA64Model
+ } else {
+ d.config.ColorModel = color.RGBAModel
+ }
+ case 2:
+ d.mode = mNRGBA
+ if d.bpp == 16 {
+ d.config.ColorModel = color.NRGBA64Model
+ } else {
+ d.config.ColorModel = color.NRGBAModel
+ }
+ default:
+ return nil, FormatError("wrong number of samples for RGB")
+ }
+ default:
+ return nil, FormatError("wrong number of samples for RGB")
+ }
+ case pPaletted:
+ d.mode = mPaletted
+ d.config.ColorModel = color.Palette(d.palette)
+ case pWhiteIsZero:
+ d.mode = mGrayInvert
+ if d.bpp == 16 {
+ d.config.ColorModel = color.Gray16Model
+ } else {
+ d.config.ColorModel = color.GrayModel
+ }
+ case pBlackIsZero:
+ d.mode = mGray
+ if d.bpp == 16 {
+ d.config.ColorModel = color.Gray16Model
+ } else {
+ d.config.ColorModel = color.GrayModel
+ }
+ default:
+ return nil, UnsupportedError("color model")
+ }
+
+ return d, nil
+}
+
+// DecodeConfig returns the color model and dimensions of a TIFF image without
+// decoding the entire image.
+func DecodeConfig(r io.Reader) (image.Config, error) {
+ d, err := newDecoder(r)
+ if err != nil {
+ return image.Config{}, err
+ }
+ return d.config, nil
+}
+
+// Decode reads a TIFF image from r and returns it as an image.Image.
+// The type of Image returned depends on the contents of the TIFF.
+func Decode(r io.Reader) (img image.Image, err error) {
+ d, err := newDecoder(r)
+ if err != nil {
+ return
+ }
+
+ blockPadding := false
+ blockWidth := d.config.Width
+ blockHeight := d.config.Height
+ blocksAcross := 1
+ blocksDown := 1
+
+ if d.config.Width == 0 {
+ blocksAcross = 0
+ }
+ if d.config.Height == 0 {
+ blocksDown = 0
+ }
+
+ var blockOffsets, blockCounts []uint
+
+ if int(d.firstVal(tTileWidth)) != 0 {
+ blockPadding = true
+
+ blockWidth = int(d.firstVal(tTileWidth))
+ blockHeight = int(d.firstVal(tTileLength))
+
+ if blockWidth != 0 {
+ blocksAcross = (d.config.Width + blockWidth - 1) / blockWidth
+ }
+ if blockHeight != 0 {
+ blocksDown = (d.config.Height + blockHeight - 1) / blockHeight
+ }
+
+ blockCounts = d.features[tTileByteCounts]
+ blockOffsets = d.features[tTileOffsets]
+
+ } else {
+ if int(d.firstVal(tRowsPerStrip)) != 0 {
+ blockHeight = int(d.firstVal(tRowsPerStrip))
+ }
+
+ if blockHeight != 0 {
+ blocksDown = (d.config.Height + blockHeight - 1) / blockHeight
+ }
+
+ blockOffsets = d.features[tStripOffsets]
+ blockCounts = d.features[tStripByteCounts]
+ }
+
+ // Check if we have the right number of strips/tiles, offsets and counts.
+ if n := blocksAcross * blocksDown; len(blockOffsets) < n || len(blockCounts) < n {
+ return nil, FormatError("inconsistent header")
+ }
+
+ imgRect := image.Rect(0, 0, d.config.Width, d.config.Height)
+ switch d.mode {
+ case mGray, mGrayInvert:
+ if d.bpp == 16 {
+ img = image.NewGray16(imgRect)
+ } else {
+ img = image.NewGray(imgRect)
+ }
+ case mPaletted:
+ img = image.NewPaletted(imgRect, d.palette)
+ case mNRGBA:
+ if d.bpp == 16 {
+ img = image.NewNRGBA64(imgRect)
+ } else {
+ img = image.NewNRGBA(imgRect)
+ }
+ case mRGB, mRGBA:
+ if d.bpp == 16 {
+ img = image.NewRGBA64(imgRect)
+ } else {
+ img = image.NewRGBA(imgRect)
+ }
+ }
+
+ for i := 0; i < blocksAcross; i++ {
+ blkW := blockWidth
+ if !blockPadding && i == blocksAcross-1 && d.config.Width%blockWidth != 0 {
+ blkW = d.config.Width % blockWidth
+ }
+ for j := 0; j < blocksDown; j++ {
+ blkH := blockHeight
+ if !blockPadding && j == blocksDown-1 && d.config.Height%blockHeight != 0 {
+ blkH = d.config.Height % blockHeight
+ }
+ offset := int64(blockOffsets[j*blocksAcross+i])
+ n := int64(blockCounts[j*blocksAcross+i])
+ switch d.firstVal(tCompression) {
+
+ // According to the spec, Compression does not have a default value,
+ // but some tools interpret a missing Compression value as none so we do
+ // the same.
+ case cNone, 0:
+ if b, ok := d.r.(*buffer); ok {
+ d.buf, err = b.Slice(int(offset), int(n))
+ } else {
+ d.buf = make([]byte, n)
+ _, err = d.r.ReadAt(d.buf, offset)
+ }
+ case cLZW:
+ r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8)
+ d.buf, err = ioutil.ReadAll(r)
+ r.Close()
+ case cDeflate, cDeflateOld:
+ var r io.ReadCloser
+ r, err = zlib.NewReader(io.NewSectionReader(d.r, offset, n))
+ if err != nil {
+ return nil, err
+ }
+ d.buf, err = ioutil.ReadAll(r)
+ r.Close()
+ case cPackBits:
+ d.buf, err = unpackBits(io.NewSectionReader(d.r, offset, n))
+ default:
+ err = UnsupportedError(fmt.Sprintf("compression value %d", d.firstVal(tCompression)))
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ xmin := i * blockWidth
+ ymin := j * blockHeight
+ xmax := xmin + blkW
+ ymax := ymin + blkH
+ err = d.decode(img, xmin, ymin, xmax, ymax)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ return
+}
+
+func init() {
+ image.RegisterFormat("tiff", leHeader, Decode, DecodeConfig)
+ image.RegisterFormat("tiff", beHeader, Decode, DecodeConfig)
+}
diff --git a/vendor/golang.org/x/image/tiff/writer.go b/vendor/golang.org/x/image/tiff/writer.go
new file mode 100644
index 0000000..c8a01ce
--- /dev/null
+++ b/vendor/golang.org/x/image/tiff/writer.go
@@ -0,0 +1,438 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tiff
+
+import (
+ "bytes"
+ "compress/zlib"
+ "encoding/binary"
+ "image"
+ "io"
+ "sort"
+)
+
+// The TIFF format allows to choose the order of the different elements freely.
+// The basic structure of a TIFF file written by this package is:
+//
+// 1. Header (8 bytes).
+// 2. Image data.
+// 3. Image File Directory (IFD).
+// 4. "Pointer area" for larger entries in the IFD.
+
+// We only write little-endian TIFF files.
+var enc = binary.LittleEndian
+
+// An ifdEntry is a single entry in an Image File Directory.
+// A value of type dtRational is composed of two 32-bit values,
+// thus data contains two uints (numerator and denominator) for a single number.
+type ifdEntry struct {
+ tag int
+ datatype int
+ data []uint32
+}
+
+func (e ifdEntry) putData(p []byte) {
+ for _, d := range e.data {
+ switch e.datatype {
+ case dtByte, dtASCII:
+ p[0] = byte(d)
+ p = p[1:]
+ case dtShort:
+ enc.PutUint16(p, uint16(d))
+ p = p[2:]
+ case dtLong, dtRational:
+ enc.PutUint32(p, uint32(d))
+ p = p[4:]
+ }
+ }
+}
+
+type byTag []ifdEntry
+
+func (d byTag) Len() int { return len(d) }
+func (d byTag) Less(i, j int) bool { return d[i].tag < d[j].tag }
+func (d byTag) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
+
+func encodeGray(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
+ if !predictor {
+ return writePix(w, pix, dy, dx, stride)
+ }
+ buf := make([]byte, dx)
+ for y := 0; y < dy; y++ {
+ min := y*stride + 0
+ max := y*stride + dx
+ off := 0
+ var v0 uint8
+ for i := min; i < max; i++ {
+ v1 := pix[i]
+ buf[off] = v1 - v0
+ v0 = v1
+ off++
+ }
+ if _, err := w.Write(buf); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func encodeGray16(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
+ buf := make([]byte, dx*2)
+ for y := 0; y < dy; y++ {
+ min := y*stride + 0
+ max := y*stride + dx*2
+ off := 0
+ var v0 uint16
+ for i := min; i < max; i += 2 {
+ // An image.Gray16's Pix is in big-endian order.
+ v1 := uint16(pix[i])<<8 | uint16(pix[i+1])
+ if predictor {
+ v0, v1 = v1, v1-v0
+ }
+ // We only write little-endian TIFF files.
+ buf[off+0] = byte(v1)
+ buf[off+1] = byte(v1 >> 8)
+ off += 2
+ }
+ if _, err := w.Write(buf); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
+ if !predictor {
+ return writePix(w, pix, dy, dx*4, stride)
+ }
+ buf := make([]byte, dx*4)
+ for y := 0; y < dy; y++ {
+ min := y*stride + 0
+ max := y*stride + dx*4
+ off := 0
+ var r0, g0, b0, a0 uint8
+ for i := min; i < max; i += 4 {
+ r1, g1, b1, a1 := pix[i+0], pix[i+1], pix[i+2], pix[i+3]
+ buf[off+0] = r1 - r0
+ buf[off+1] = g1 - g0
+ buf[off+2] = b1 - b0
+ buf[off+3] = a1 - a0
+ off += 4
+ r0, g0, b0, a0 = r1, g1, b1, a1
+ }
+ if _, err := w.Write(buf); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func encodeRGBA64(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
+ buf := make([]byte, dx*8)
+ for y := 0; y < dy; y++ {
+ min := y*stride + 0
+ max := y*stride + dx*8
+ off := 0
+ var r0, g0, b0, a0 uint16
+ for i := min; i < max; i += 8 {
+ // An image.RGBA64's Pix is in big-endian order.
+ r1 := uint16(pix[i+0])<<8 | uint16(pix[i+1])
+ g1 := uint16(pix[i+2])<<8 | uint16(pix[i+3])
+ b1 := uint16(pix[i+4])<<8 | uint16(pix[i+5])
+ a1 := uint16(pix[i+6])<<8 | uint16(pix[i+7])
+ if predictor {
+ r0, r1 = r1, r1-r0
+ g0, g1 = g1, g1-g0
+ b0, b1 = b1, b1-b0
+ a0, a1 = a1, a1-a0
+ }
+ // We only write little-endian TIFF files.
+ buf[off+0] = byte(r1)
+ buf[off+1] = byte(r1 >> 8)
+ buf[off+2] = byte(g1)
+ buf[off+3] = byte(g1 >> 8)
+ buf[off+4] = byte(b1)
+ buf[off+5] = byte(b1 >> 8)
+ buf[off+6] = byte(a1)
+ buf[off+7] = byte(a1 >> 8)
+ off += 8
+ }
+ if _, err := w.Write(buf); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func encode(w io.Writer, m image.Image, predictor bool) error {
+ bounds := m.Bounds()
+ buf := make([]byte, 4*bounds.Dx())
+ for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+ off := 0
+ if predictor {
+ var r0, g0, b0, a0 uint8
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ r, g, b, a := m.At(x, y).RGBA()
+ r1 := uint8(r >> 8)
+ g1 := uint8(g >> 8)
+ b1 := uint8(b >> 8)
+ a1 := uint8(a >> 8)
+ buf[off+0] = r1 - r0
+ buf[off+1] = g1 - g0
+ buf[off+2] = b1 - b0
+ buf[off+3] = a1 - a0
+ off += 4
+ r0, g0, b0, a0 = r1, g1, b1, a1
+ }
+ } else {
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ r, g, b, a := m.At(x, y).RGBA()
+ buf[off+0] = uint8(r >> 8)
+ buf[off+1] = uint8(g >> 8)
+ buf[off+2] = uint8(b >> 8)
+ buf[off+3] = uint8(a >> 8)
+ off += 4
+ }
+ }
+ if _, err := w.Write(buf); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// writePix writes the internal byte array of an image to w. It is less general
+// but much faster then encode. writePix is used when pix directly
+// corresponds to one of the TIFF image types.
+func writePix(w io.Writer, pix []byte, nrows, length, stride int) error {
+ if length == stride {
+ _, err := w.Write(pix[:nrows*length])
+ return err
+ }
+ for ; nrows > 0; nrows-- {
+ if _, err := w.Write(pix[:length]); err != nil {
+ return err
+ }
+ pix = pix[stride:]
+ }
+ return nil
+}
+
+func writeIFD(w io.Writer, ifdOffset int, d []ifdEntry) error {
+ var buf [ifdLen]byte
+ // Make space for "pointer area" containing IFD entry data
+ // longer than 4 bytes.
+ parea := make([]byte, 1024)
+ pstart := ifdOffset + ifdLen*len(d) + 6
+ var o int // Current offset in parea.
+
+ // The IFD has to be written with the tags in ascending order.
+ sort.Sort(byTag(d))
+
+ // Write the number of entries in this IFD.
+ if err := binary.Write(w, enc, uint16(len(d))); err != nil {
+ return err
+ }
+ for _, ent := range d {
+ enc.PutUint16(buf[0:2], uint16(ent.tag))
+ enc.PutUint16(buf[2:4], uint16(ent.datatype))
+ count := uint32(len(ent.data))
+ if ent.datatype == dtRational {
+ count /= 2
+ }
+ enc.PutUint32(buf[4:8], count)
+ datalen := int(count * lengths[ent.datatype])
+ if datalen <= 4 {
+ ent.putData(buf[8:12])
+ } else {
+ if (o + datalen) > len(parea) {
+ newlen := len(parea) + 1024
+ for (o + datalen) > newlen {
+ newlen += 1024
+ }
+ newarea := make([]byte, newlen)
+ copy(newarea, parea)
+ parea = newarea
+ }
+ ent.putData(parea[o : o+datalen])
+ enc.PutUint32(buf[8:12], uint32(pstart+o))
+ o += datalen
+ }
+ if _, err := w.Write(buf[:]); err != nil {
+ return err
+ }
+ }
+ // The IFD ends with the offset of the next IFD in the file,
+ // or zero if it is the last one (page 14).
+ if err := binary.Write(w, enc, uint32(0)); err != nil {
+ return err
+ }
+ _, err := w.Write(parea[:o])
+ return err
+}
+
+// Options are the encoding parameters.
+type Options struct {
+ // Compression is the type of compression used.
+ Compression CompressionType
+ // Predictor determines whether a differencing predictor is used;
+ // if true, instead of each pixel's color, the color difference to the
+ // preceding one is saved. This improves the compression for certain
+ // types of images and compressors. For example, it works well for
+ // photos with Deflate compression.
+ Predictor bool
+}
+
+// Encode writes the image m to w. opt determines the options used for
+// encoding, such as the compression type. If opt is nil, an uncompressed
+// image is written.
+func Encode(w io.Writer, m image.Image, opt *Options) error {
+ d := m.Bounds().Size()
+
+ compression := uint32(cNone)
+ predictor := false
+ if opt != nil {
+ compression = opt.Compression.specValue()
+ // The predictor field is only used with LZW. See page 64 of the spec.
+ predictor = opt.Predictor && compression == cLZW
+ }
+
+ _, err := io.WriteString(w, leHeader)
+ if err != nil {
+ return err
+ }
+
+ // Compressed data is written into a buffer first, so that we
+ // know the compressed size.
+ var buf bytes.Buffer
+ // dst holds the destination for the pixel data of the image --
+ // either w or a writer to buf.
+ var dst io.Writer
+ // imageLen is the length of the pixel data in bytes.
+ // The offset of the IFD is imageLen + 8 header bytes.
+ var imageLen int
+
+ switch compression {
+ case cNone:
+ dst = w
+ // Write IFD offset before outputting pixel data.
+ switch m.(type) {
+ case *image.Paletted:
+ imageLen = d.X * d.Y * 1
+ case *image.Gray:
+ imageLen = d.X * d.Y * 1
+ case *image.Gray16:
+ imageLen = d.X * d.Y * 2
+ case *image.RGBA64:
+ imageLen = d.X * d.Y * 8
+ case *image.NRGBA64:
+ imageLen = d.X * d.Y * 8
+ default:
+ imageLen = d.X * d.Y * 4
+ }
+ err = binary.Write(w, enc, uint32(imageLen+8))
+ if err != nil {
+ return err
+ }
+ case cDeflate:
+ dst = zlib.NewWriter(&buf)
+ }
+
+ pr := uint32(prNone)
+ photometricInterpretation := uint32(pRGB)
+ samplesPerPixel := uint32(4)
+ bitsPerSample := []uint32{8, 8, 8, 8}
+ extraSamples := uint32(0)
+ colorMap := []uint32{}
+
+ if predictor {
+ pr = prHorizontal
+ }
+ switch m := m.(type) {
+ case *image.Paletted:
+ photometricInterpretation = pPaletted
+ samplesPerPixel = 1
+ bitsPerSample = []uint32{8}
+ colorMap = make([]uint32, 256*3)
+ for i := 0; i < 256 && i < len(m.Palette); i++ {
+ r, g, b, _ := m.Palette[i].RGBA()
+ colorMap[i+0*256] = uint32(r)
+ colorMap[i+1*256] = uint32(g)
+ colorMap[i+2*256] = uint32(b)
+ }
+ err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
+ case *image.Gray:
+ photometricInterpretation = pBlackIsZero
+ samplesPerPixel = 1
+ bitsPerSample = []uint32{8}
+ err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
+ case *image.Gray16:
+ photometricInterpretation = pBlackIsZero
+ samplesPerPixel = 1
+ bitsPerSample = []uint32{16}
+ err = encodeGray16(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
+ case *image.NRGBA:
+ extraSamples = 2 // Unassociated alpha.
+ err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
+ case *image.NRGBA64:
+ extraSamples = 2 // Unassociated alpha.
+ bitsPerSample = []uint32{16, 16, 16, 16}
+ err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
+ case *image.RGBA:
+ extraSamples = 1 // Associated alpha.
+ err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
+ case *image.RGBA64:
+ extraSamples = 1 // Associated alpha.
+ bitsPerSample = []uint32{16, 16, 16, 16}
+ err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
+ default:
+ extraSamples = 1 // Associated alpha.
+ err = encode(dst, m, predictor)
+ }
+ if err != nil {
+ return err
+ }
+
+ if compression != cNone {
+ if err = dst.(io.Closer).Close(); err != nil {
+ return err
+ }
+ imageLen = buf.Len()
+ if err = binary.Write(w, enc, uint32(imageLen+8)); err != nil {
+ return err
+ }
+ if _, err = buf.WriteTo(w); err != nil {
+ return err
+ }
+ }
+
+ ifd := []ifdEntry{
+ {tImageWidth, dtShort, []uint32{uint32(d.X)}},
+ {tImageLength, dtShort, []uint32{uint32(d.Y)}},
+ {tBitsPerSample, dtShort, bitsPerSample},
+ {tCompression, dtShort, []uint32{compression}},
+ {tPhotometricInterpretation, dtShort, []uint32{photometricInterpretation}},
+ {tStripOffsets, dtLong, []uint32{8}},
+ {tSamplesPerPixel, dtShort, []uint32{samplesPerPixel}},
+ {tRowsPerStrip, dtShort, []uint32{uint32(d.Y)}},
+ {tStripByteCounts, dtLong, []uint32{uint32(imageLen)}},
+ // There is currently no support for storing the image
+ // resolution, so give a bogus value of 72x72 dpi.
+ {tXResolution, dtRational, []uint32{72, 1}},
+ {tYResolution, dtRational, []uint32{72, 1}},
+ {tResolutionUnit, dtShort, []uint32{resPerInch}},
+ }
+ if pr != prNone {
+ ifd = append(ifd, ifdEntry{tPredictor, dtShort, []uint32{pr}})
+ }
+ if len(colorMap) != 0 {
+ ifd = append(ifd, ifdEntry{tColorMap, dtShort, colorMap})
+ }
+ if extraSamples > 0 {
+ ifd = append(ifd, ifdEntry{tExtraSamples, dtShort, []uint32{extraSamples}})
+ }
+
+ return writeIFD(w, imageLen+8, ifd)
+}