diff options
author | Christopher Speller <crspeller@gmail.com> | 2016-05-12 15:08:58 -0400 |
---|---|---|
committer | Christopher Speller <crspeller@gmail.com> | 2016-05-12 16:37:29 -0400 |
commit | 84d2482ddbff9564c9ad75b2d30af66e3ddfd44d (patch) | |
tree | 8bfa567d2b6381f4a996ada2deff8a16aa85a3ac /vendor/github.com/rwcarlsen/goexif/tiff | |
parent | d1efb66ad7b017f0fbfe6f0c20843b30f396e504 (diff) | |
download | chat-84d2482ddbff9564c9ad75b2d30af66e3ddfd44d.tar.gz chat-84d2482ddbff9564c9ad75b2d30af66e3ddfd44d.tar.bz2 chat-84d2482ddbff9564c9ad75b2d30af66e3ddfd44d.zip |
Updating go depencancies. Switching to go1.6 vendoring (#2949)
Diffstat (limited to 'vendor/github.com/rwcarlsen/goexif/tiff')
-rw-r--r-- | vendor/github.com/rwcarlsen/goexif/tiff/sample1.tif | bin | 0 -> 18382 bytes | |||
-rw-r--r-- | vendor/github.com/rwcarlsen/goexif/tiff/tag.go | 438 | ||||
-rw-r--r-- | vendor/github.com/rwcarlsen/goexif/tiff/tiff.go | 153 |
3 files changed, 591 insertions, 0 deletions
diff --git a/vendor/github.com/rwcarlsen/goexif/tiff/sample1.tif b/vendor/github.com/rwcarlsen/goexif/tiff/sample1.tif Binary files differnew file mode 100644 index 000000000..fe51399c5 --- /dev/null +++ b/vendor/github.com/rwcarlsen/goexif/tiff/sample1.tif diff --git a/vendor/github.com/rwcarlsen/goexif/tiff/tag.go b/vendor/github.com/rwcarlsen/goexif/tiff/tag.go new file mode 100644 index 000000000..66b68e334 --- /dev/null +++ b/vendor/github.com/rwcarlsen/goexif/tiff/tag.go @@ -0,0 +1,438 @@ +package tiff + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "math/big" + "strings" + "unicode" + "unicode/utf8" +) + +// Format specifies the Go type equivalent used to represent the basic +// tiff data types. +type Format int + +const ( + IntVal Format = iota + FloatVal + RatVal + StringVal + UndefVal + OtherVal +) + +var ErrShortReadTagValue = errors.New("tiff: short read of tag value") + +var formatNames = map[Format]string{ + IntVal: "int", + FloatVal: "float", + RatVal: "rational", + StringVal: "string", + UndefVal: "undefined", + OtherVal: "other", +} + +// DataType represents the basic tiff tag data types. +type DataType uint16 + +const ( + DTByte DataType = 1 + DTAscii = 2 + DTShort = 3 + DTLong = 4 + DTRational = 5 + DTSByte = 6 + DTUndefined = 7 + DTSShort = 8 + DTSLong = 9 + DTSRational = 10 + DTFloat = 11 + DTDouble = 12 +) + +var typeNames = map[DataType]string{ + DTByte: "byte", + DTAscii: "ascii", + DTShort: "short", + DTLong: "long", + DTRational: "rational", + DTSByte: "signed byte", + DTUndefined: "undefined", + DTSShort: "signed short", + DTSLong: "signed long", + DTSRational: "signed rational", + DTFloat: "float", + DTDouble: "double", +} + +// typeSize specifies the size in bytes of each type. +var typeSize = map[DataType]uint32{ + DTByte: 1, + DTAscii: 1, + DTShort: 2, + DTLong: 4, + DTRational: 8, + DTSByte: 1, + DTUndefined: 1, + DTSShort: 2, + DTSLong: 4, + DTSRational: 8, + DTFloat: 4, + DTDouble: 8, +} + +// Tag reflects the parsed content of a tiff IFD tag. +type Tag struct { + // Id is the 2-byte tiff tag identifier. + Id uint16 + // Type is an integer (1 through 12) indicating the tag value's data type. + Type DataType + // Count is the number of type Type stored in the tag's value (i.e. the + // tag's value is an array of type Type and length Count). + Count uint32 + // Val holds the bytes that represent the tag's value. + Val []byte + // ValOffset holds byte offset of the tag value w.r.t. the beginning of the + // reader it was decoded from. Zero if the tag value fit inside the offset + // field. + ValOffset uint32 + + order binary.ByteOrder + intVals []int64 + floatVals []float64 + ratVals [][]int64 + strVal string + format Format +} + +// DecodeTag parses a tiff-encoded IFD tag from r and returns a Tag object. The +// first read from r should be the first byte of the tag. ReadAt offsets should +// generally be relative to the beginning of the tiff structure (not relative +// to the beginning of the tag). +func DecodeTag(r ReadAtReader, order binary.ByteOrder) (*Tag, error) { + t := new(Tag) + t.order = order + + err := binary.Read(r, order, &t.Id) + if err != nil { + return nil, errors.New("tiff: tag id read failed: " + err.Error()) + } + + err = binary.Read(r, order, &t.Type) + if err != nil { + return nil, errors.New("tiff: tag type read failed: " + err.Error()) + } + + err = binary.Read(r, order, &t.Count) + if err != nil { + return nil, errors.New("tiff: tag component count read failed: " + err.Error()) + } + + // There seems to be a relatively common corrupt tag which has a Count of + // MaxUint32. This is probably not a valid value, so return early. + if t.Count == 1<<32-1 { + return t, errors.New("invalid Count offset in tag") + } + + valLen := typeSize[t.Type] * t.Count + if valLen == 0 { + return t, errors.New("zero length tag value") + } + + if valLen > 4 { + binary.Read(r, order, &t.ValOffset) + + // Use a bytes.Buffer so we don't allocate a huge slice if the tag + // is corrupt. + var buff bytes.Buffer + sr := io.NewSectionReader(r, int64(t.ValOffset), int64(valLen)) + n, err := io.Copy(&buff, sr) + if err != nil { + return t, errors.New("tiff: tag value read failed: " + err.Error()) + } else if n != int64(valLen) { + return t, ErrShortReadTagValue + } + t.Val = buff.Bytes() + + } else { + val := make([]byte, valLen) + if _, err = io.ReadFull(r, val); err != nil { + return t, errors.New("tiff: tag offset read failed: " + err.Error()) + } + // ignore padding. + if _, err = io.ReadFull(r, make([]byte, 4-valLen)); err != nil { + return t, errors.New("tiff: tag offset read failed: " + err.Error()) + } + + t.Val = val + } + + return t, t.convertVals() +} + +func (t *Tag) convertVals() error { + r := bytes.NewReader(t.Val) + + switch t.Type { + case DTAscii: + if len(t.Val) > 0 { + t.strVal = string(t.Val[:len(t.Val)-1]) // ignore the last byte (NULL). + } + case DTByte: + var v uint8 + t.intVals = make([]int64, int(t.Count)) + for i := range t.intVals { + err := binary.Read(r, t.order, &v) + if err != nil { + return err + } + t.intVals[i] = int64(v) + } + case DTShort: + var v uint16 + t.intVals = make([]int64, int(t.Count)) + for i := range t.intVals { + err := binary.Read(r, t.order, &v) + if err != nil { + return err + } + t.intVals[i] = int64(v) + } + case DTLong: + var v uint32 + t.intVals = make([]int64, int(t.Count)) + for i := range t.intVals { + err := binary.Read(r, t.order, &v) + if err != nil { + return err + } + t.intVals[i] = int64(v) + } + case DTSByte: + var v int8 + t.intVals = make([]int64, int(t.Count)) + for i := range t.intVals { + err := binary.Read(r, t.order, &v) + if err != nil { + return err + } + t.intVals[i] = int64(v) + } + case DTSShort: + var v int16 + t.intVals = make([]int64, int(t.Count)) + for i := range t.intVals { + err := binary.Read(r, t.order, &v) + if err != nil { + return err + } + t.intVals[i] = int64(v) + } + case DTSLong: + var v int32 + t.intVals = make([]int64, int(t.Count)) + for i := range t.intVals { + err := binary.Read(r, t.order, &v) + if err != nil { + return err + } + t.intVals[i] = int64(v) + } + case DTRational: + t.ratVals = make([][]int64, int(t.Count)) + for i := range t.ratVals { + var n, d uint32 + err := binary.Read(r, t.order, &n) + if err != nil { + return err + } + err = binary.Read(r, t.order, &d) + if err != nil { + return err + } + t.ratVals[i] = []int64{int64(n), int64(d)} + } + case DTSRational: + t.ratVals = make([][]int64, int(t.Count)) + for i := range t.ratVals { + var n, d int32 + err := binary.Read(r, t.order, &n) + if err != nil { + return err + } + err = binary.Read(r, t.order, &d) + if err != nil { + return err + } + t.ratVals[i] = []int64{int64(n), int64(d)} + } + case DTFloat: // float32 + t.floatVals = make([]float64, int(t.Count)) + for i := range t.floatVals { + var v float32 + err := binary.Read(r, t.order, &v) + if err != nil { + return err + } + t.floatVals[i] = float64(v) + } + case DTDouble: + t.floatVals = make([]float64, int(t.Count)) + for i := range t.floatVals { + var u float64 + err := binary.Read(r, t.order, &u) + if err != nil { + return err + } + t.floatVals[i] = u + } + } + + switch t.Type { + case DTByte, DTShort, DTLong, DTSByte, DTSShort, DTSLong: + t.format = IntVal + case DTRational, DTSRational: + t.format = RatVal + case DTFloat, DTDouble: + t.format = FloatVal + case DTAscii: + t.format = StringVal + case DTUndefined: + t.format = UndefVal + default: + t.format = OtherVal + } + + return nil +} + +// Format returns a value indicating which method can be called to retrieve the +// tag's value properly typed (e.g. integer, rational, etc.). +func (t *Tag) Format() Format { return t.format } + +func (t *Tag) typeErr(to Format) error { + return &wrongFmtErr{typeNames[t.Type], formatNames[to]} +} + +// Rat returns the tag's i'th value as a rational number. It returns a nil and +// an error if this tag's Format is not RatVal. It panics for zero deminators +// or if i is out of range. +func (t *Tag) Rat(i int) (*big.Rat, error) { + n, d, err := t.Rat2(i) + if err != nil { + return nil, err + } + return big.NewRat(n, d), nil +} + +// Rat2 returns the tag's i'th value as a rational number represented by a +// numerator-denominator pair. It returns an error if the tag's Format is not +// RatVal. It panics if i is out of range. +func (t *Tag) Rat2(i int) (num, den int64, err error) { + if t.format != RatVal { + return 0, 0, t.typeErr(RatVal) + } + return t.ratVals[i][0], t.ratVals[i][1], nil +} + +// Int64 returns the tag's i'th value as an integer. It returns an error if the +// tag's Format is not IntVal. It panics if i is out of range. +func (t *Tag) Int64(i int) (int64, error) { + if t.format != IntVal { + return 0, t.typeErr(IntVal) + } + return t.intVals[i], nil +} + +// Int returns the tag's i'th value as an integer. It returns an error if the +// tag's Format is not IntVal. It panics if i is out of range. +func (t *Tag) Int(i int) (int, error) { + if t.format != IntVal { + return 0, t.typeErr(IntVal) + } + return int(t.intVals[i]), nil +} + +// Float returns the tag's i'th value as a float. It returns an error if the +// tag's Format is not IntVal. It panics if i is out of range. +func (t *Tag) Float(i int) (float64, error) { + if t.format != FloatVal { + return 0, t.typeErr(FloatVal) + } + return t.floatVals[i], nil +} + +// StringVal returns the tag's value as a string. It returns an error if the +// tag's Format is not StringVal. It panics if i is out of range. +func (t *Tag) StringVal() (string, error) { + if t.format != StringVal { + return "", t.typeErr(StringVal) + } + return t.strVal, nil +} + +// String returns a nicely formatted version of the tag. +func (t *Tag) String() string { + data, err := t.MarshalJSON() + if err != nil { + return "ERROR: " + err.Error() + } + + if t.Count == 1 { + return strings.Trim(fmt.Sprintf("%s", data), "[]") + } + return fmt.Sprintf("%s", data) +} + +func (t *Tag) MarshalJSON() ([]byte, error) { + switch t.format { + case StringVal, UndefVal: + return nullString(t.Val), nil + case OtherVal: + return []byte(fmt.Sprintf("unknown tag type '%v'", t.Type)), nil + } + + rv := []string{} + for i := 0; i < int(t.Count); i++ { + switch t.format { + case RatVal: + n, d, _ := t.Rat2(i) + rv = append(rv, fmt.Sprintf(`"%v/%v"`, n, d)) + case FloatVal: + v, _ := t.Float(i) + rv = append(rv, fmt.Sprintf("%v", v)) + case IntVal: + v, _ := t.Int(i) + rv = append(rv, fmt.Sprintf("%v", v)) + } + } + return []byte(fmt.Sprintf(`[%s]`, strings.Join(rv, ","))), nil +} + +func nullString(in []byte) []byte { + rv := bytes.Buffer{} + rv.WriteByte('"') + for _, b := range in { + if unicode.IsPrint(rune(b)) { + rv.WriteByte(b) + } + } + rv.WriteByte('"') + rvb := rv.Bytes() + if utf8.Valid(rvb) { + return rvb + } + return []byte(`""`) +} + +type wrongFmtErr struct { + From, To string +} + +func (e *wrongFmtErr) Error() string { + return fmt.Sprintf("cannot convert tag type '%v' into '%v'", e.From, e.To) +} diff --git a/vendor/github.com/rwcarlsen/goexif/tiff/tiff.go b/vendor/github.com/rwcarlsen/goexif/tiff/tiff.go new file mode 100644 index 000000000..771e91878 --- /dev/null +++ b/vendor/github.com/rwcarlsen/goexif/tiff/tiff.go @@ -0,0 +1,153 @@ +// Package tiff implements TIFF decoding as defined in TIFF 6.0 specification at +// http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf +package tiff + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" +) + +// ReadAtReader is used when decoding Tiff tags and directories +type ReadAtReader interface { + io.Reader + io.ReaderAt +} + +// Tiff provides access to a decoded tiff data structure. +type Tiff struct { + // Dirs is an ordered slice of the tiff's Image File Directories (IFDs). + // The IFD at index 0 is IFD0. + Dirs []*Dir + // The tiff's byte-encoding (i.e. big/little endian). + Order binary.ByteOrder +} + +// Decode parses tiff-encoded data from r and returns a Tiff struct that +// reflects the structure and content of the tiff data. The first read from r +// should be the first byte of the tiff-encoded data and not necessarily the +// first byte of an os.File object. +func Decode(r io.Reader) (*Tiff, error) { + data, err := ioutil.ReadAll(r) + if err != nil { + return nil, errors.New("tiff: could not read data") + } + buf := bytes.NewReader(data) + + t := new(Tiff) + + // read byte order + bo := make([]byte, 2) + if _, err = io.ReadFull(buf, bo); err != nil { + return nil, errors.New("tiff: could not read tiff byte order") + } + if string(bo) == "II" { + t.Order = binary.LittleEndian + } else if string(bo) == "MM" { + t.Order = binary.BigEndian + } else { + return nil, errors.New("tiff: could not read tiff byte order") + } + + // check for special tiff marker + var sp int16 + err = binary.Read(buf, t.Order, &sp) + if err != nil || 42 != sp { + return nil, errors.New("tiff: could not find special tiff marker") + } + + // load offset to first IFD + var offset int32 + err = binary.Read(buf, t.Order, &offset) + if err != nil { + return nil, errors.New("tiff: could not read offset to first IFD") + } + + // load IFD's + var d *Dir + prev := offset + for offset != 0 { + // seek to offset + _, err := buf.Seek(int64(offset), 0) + if err != nil { + return nil, errors.New("tiff: seek to IFD failed") + } + + if buf.Len() == 0 { + return nil, errors.New("tiff: seek offset after EOF") + } + + // load the dir + d, offset, err = DecodeDir(buf, t.Order) + if err != nil { + return nil, err + } + + if offset == prev { + return nil, errors.New("tiff: recursive IFD") + } + prev = offset + + t.Dirs = append(t.Dirs, d) + } + + return t, nil +} + +func (tf *Tiff) String() string { + var buf bytes.Buffer + fmt.Fprint(&buf, "Tiff{") + for _, d := range tf.Dirs { + fmt.Fprintf(&buf, "%s, ", d.String()) + } + fmt.Fprintf(&buf, "}") + return buf.String() +} + +// Dir provides access to the parsed content of a tiff Image File Directory (IFD). +type Dir struct { + Tags []*Tag +} + +// DecodeDir parses a tiff-encoded IFD from r and returns a Dir object. offset +// is the offset to the next IFD. The first read from r should be at the first +// byte of the IFD. ReadAt offsets should generally be relative to the +// beginning of the tiff structure (not relative to the beginning of the IFD). +func DecodeDir(r ReadAtReader, order binary.ByteOrder) (d *Dir, offset int32, err error) { + d = new(Dir) + + // get num of tags in ifd + var nTags int16 + err = binary.Read(r, order, &nTags) + if err != nil { + return nil, 0, errors.New("tiff: failed to read IFD tag count: " + err.Error()) + } + + // load tags + for n := 0; n < int(nTags); n++ { + t, err := DecodeTag(r, order) + if err != nil { + return nil, 0, err + } + d.Tags = append(d.Tags, t) + } + + // get offset to next ifd + err = binary.Read(r, order, &offset) + if err != nil { + return nil, 0, errors.New("tiff: falied to read offset to next IFD: " + err.Error()) + } + + return d, offset, nil +} + +func (d *Dir) String() string { + s := "Dir{" + for _, t := range d.Tags { + s += t.String() + ", " + } + return s + "}" +} |