summaryrefslogtreecommitdiff
path: root/vendor/github.com/dsoprea/go-exif/utility.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/dsoprea/go-exif/utility.go')
-rw-r--r--vendor/github.com/dsoprea/go-exif/utility.go222
1 files changed, 222 insertions, 0 deletions
diff --git a/vendor/github.com/dsoprea/go-exif/utility.go b/vendor/github.com/dsoprea/go-exif/utility.go
new file mode 100644
index 000000000..3d1ea2489
--- /dev/null
+++ b/vendor/github.com/dsoprea/go-exif/utility.go
@@ -0,0 +1,222 @@
+package exif
+
+import (
+ "bytes"
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/dsoprea/go-logging"
+)
+
+func DumpBytes(data []byte) {
+ fmt.Printf("DUMP: ")
+ for _, x := range data {
+ fmt.Printf("%02x ", x)
+ }
+
+ fmt.Printf("\n")
+}
+
+func DumpBytesClause(data []byte) {
+ fmt.Printf("DUMP: ")
+
+ fmt.Printf("[]byte { ")
+
+ for i, x := range data {
+ fmt.Printf("0x%02x", x)
+
+ if i < len(data)-1 {
+ fmt.Printf(", ")
+ }
+ }
+
+ fmt.Printf(" }\n")
+}
+
+func DumpBytesToString(data []byte) string {
+ b := new(bytes.Buffer)
+
+ for i, x := range data {
+ _, err := b.WriteString(fmt.Sprintf("%02x", x))
+ log.PanicIf(err)
+
+ if i < len(data)-1 {
+ _, err := b.WriteRune(' ')
+ log.PanicIf(err)
+ }
+ }
+
+ return b.String()
+}
+
+func DumpBytesClauseToString(data []byte) string {
+ b := new(bytes.Buffer)
+
+ for i, x := range data {
+ _, err := b.WriteString(fmt.Sprintf("0x%02x", x))
+ log.PanicIf(err)
+
+ if i < len(data)-1 {
+ _, err := b.WriteString(", ")
+ log.PanicIf(err)
+ }
+ }
+
+ return b.String()
+}
+
+// ParseExifFullTimestamp parses dates like "2018:11:30 13:01:49" into a UTC
+// `time.Time` struct.
+func ParseExifFullTimestamp(fullTimestampPhrase string) (timestamp time.Time, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ parts := strings.Split(fullTimestampPhrase, " ")
+ datestampValue, timestampValue := parts[0], parts[1]
+
+ dateParts := strings.Split(datestampValue, ":")
+
+ year, err := strconv.ParseUint(dateParts[0], 10, 16)
+ if err != nil {
+ log.Panicf("could not parse year")
+ }
+
+ month, err := strconv.ParseUint(dateParts[1], 10, 8)
+ if err != nil {
+ log.Panicf("could not parse month")
+ }
+
+ day, err := strconv.ParseUint(dateParts[2], 10, 8)
+ if err != nil {
+ log.Panicf("could not parse day")
+ }
+
+ timeParts := strings.Split(timestampValue, ":")
+
+ hour, err := strconv.ParseUint(timeParts[0], 10, 8)
+ if err != nil {
+ log.Panicf("could not parse hour")
+ }
+
+ minute, err := strconv.ParseUint(timeParts[1], 10, 8)
+ if err != nil {
+ log.Panicf("could not parse minute")
+ }
+
+ second, err := strconv.ParseUint(timeParts[2], 10, 8)
+ if err != nil {
+ log.Panicf("could not parse second")
+ }
+
+ timestamp = time.Date(int(year), time.Month(month), int(day), int(hour), int(minute), int(second), 0, time.UTC)
+ return timestamp, nil
+}
+
+// ExifFullTimestampString produces a string like "2018:11:30 13:01:49" from a
+// `time.Time` struct. It will attempt to convert to UTC first.
+func ExifFullTimestampString(t time.Time) (fullTimestampPhrase string) {
+ t = t.UTC()
+
+ return fmt.Sprintf("%04d:%02d:%02d %02d:%02d:%02d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
+}
+
+// ExifTag is one simple representation of a tag in a flat list of all of them.
+type ExifTag struct {
+ IfdPath string `json:"ifd_path"`
+
+ TagId uint16 `json:"id"`
+ TagName string `json:"name"`
+
+ TagTypeId TagTypePrimitive `json:"type_id"`
+ TagTypeName string `json:"type_name"`
+ Value interface{} `json:"value"`
+ ValueBytes []byte `json:"value_bytes"`
+
+ ChildIfdPath string `json:"child_ifd_path"`
+}
+
+// String returns a string representation.
+func (et ExifTag) String() string {
+ return fmt.Sprintf("ExifTag<IFD-PATH=[%s] TAG-ID=(0x%02x) TAG-NAME=[%s] TAG-TYPE=[%s] VALUE=[%v] VALUE-BYTES=(%d) CHILD-IFD-PATH=[%s]", et.IfdPath, et.TagId, et.TagName, et.TagTypeName, et.Value, len(et.ValueBytes), et.ChildIfdPath)
+}
+
+// GetFlatExifData returns a simple, flat representation of all tags.
+func GetFlatExifData(exifData []byte) (exifTags []ExifTag, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ im := NewIfdMappingWithStandard()
+ ti := NewTagIndex()
+
+ _, index, err := Collect(im, ti, exifData)
+ log.PanicIf(err)
+
+ q := []*Ifd{index.RootIfd}
+
+ exifTags = make([]ExifTag, 0)
+
+ for len(q) > 0 {
+ var ifd *Ifd
+ ifd, q = q[0], q[1:]
+
+ ti := NewTagIndex()
+ for _, ite := range ifd.Entries {
+ tagName := ""
+
+ it, err := ti.Get(ifd.IfdPath, ite.TagId)
+ if err != nil {
+ // If it's a non-standard tag, just leave the name blank.
+ if log.Is(err, ErrTagNotFound) != true {
+ log.PanicIf(err)
+ }
+ } else {
+ tagName = it.Name
+ }
+
+ value, err := ifd.TagValue(ite)
+ if err != nil {
+ if err == ErrUnhandledUnknownTypedTag {
+ value = UnparseableUnknownTagValuePlaceholder
+ } else {
+ log.Panic(err)
+ }
+ }
+
+ valueBytes, err := ifd.TagValueBytes(ite)
+ if err != nil && err != ErrUnhandledUnknownTypedTag {
+ log.Panic(err)
+ }
+
+ et := ExifTag{
+ IfdPath: ifd.IfdPath,
+ TagId: ite.TagId,
+ TagName: tagName,
+ TagTypeId: ite.TagType,
+ TagTypeName: TypeNames[ite.TagType],
+ Value: value,
+ ValueBytes: valueBytes,
+ ChildIfdPath: ite.ChildIfdPath,
+ }
+
+ exifTags = append(exifTags, et)
+ }
+
+ for _, childIfd := range ifd.Children {
+ q = append(q, childIfd)
+ }
+
+ if ifd.NextIfd != nil {
+ q = append(q, ifd.NextIfd)
+ }
+ }
+
+ return exifTags, nil
+}