summaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com')
-rw-r--r--Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/README.md4
-rw-r--r--Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/example_test.go42
-rw-r--r--Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/exif.go619
-rw-r--r--Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/exif_test.go202
-rw-r--r--Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/fields.go293
-rw-r--r--Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/regen_regress.go79
-rw-r--r--Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/regress_expected_test.go2293
-rw-r--r--Godeps/_workspace/src/github.com/rwcarlsen/goexif/tiff/tag.go438
-rw-r--r--Godeps/_workspace/src/github.com/rwcarlsen/goexif/tiff/tiff.go153
-rw-r--r--Godeps/_workspace/src/github.com/rwcarlsen/goexif/tiff/tiff_test.go235
10 files changed, 4358 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/README.md b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/README.md
new file mode 100644
index 000000000..b3bf5fa0e
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/README.md
@@ -0,0 +1,4 @@
+
+To regenerate the regression test data, run `go generate` inside the exif
+package directory and commit the changes to *regress_expected_test.go*.
+
diff --git a/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/example_test.go b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/example_test.go
new file mode 100644
index 000000000..45fd5d4ad
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/example_test.go
@@ -0,0 +1,42 @@
+package exif_test
+
+import (
+ "fmt"
+ "log"
+ "os"
+
+ "github.com/rwcarlsen/goexif/exif"
+ "github.com/rwcarlsen/goexif/mknote"
+)
+
+func ExampleDecode() {
+ fname := "sample1.jpg"
+
+ f, err := os.Open(fname)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Optionally register camera makenote data parsing - currently Nikon and
+ // Canon are supported.
+ exif.RegisterParsers(mknote.All...)
+
+ x, err := exif.Decode(f)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ camModel, _ := x.Get(exif.Model) // normally, don't ignore errors!
+ fmt.Println(camModel.StringVal())
+
+ focal, _ := x.Get(exif.FocalLength)
+ numer, denom, _ := focal.Rat2(0) // retrieve first (only) rat. value
+ fmt.Printf("%v/%v", numer, denom)
+
+ // Two convenience functions exist for date/time taken and GPS coords:
+ tm, _ := x.DateTime()
+ fmt.Println("Taken: ", tm)
+
+ lat, long, _ := x.LatLong()
+ fmt.Println("lat, long: ", lat, ", ", long)
+}
diff --git a/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/exif.go b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/exif.go
new file mode 100644
index 000000000..b420729da
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/exif.go
@@ -0,0 +1,619 @@
+// Package exif implements decoding of EXIF data as defined in the EXIF 2.2
+// specification (http://www.exif.org/Exif2-2.PDF).
+package exif
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "math"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/rwcarlsen/goexif/tiff"
+)
+
+const (
+ jpeg_APP1 = 0xE1
+
+ exifPointer = 0x8769
+ gpsPointer = 0x8825
+ interopPointer = 0xA005
+)
+
+// A decodeError is returned when the image cannot be decoded as a tiff image.
+type decodeError struct {
+ cause error
+}
+
+func (de decodeError) Error() string {
+ return fmt.Sprintf("exif: decode failed (%v) ", de.cause.Error())
+}
+
+// IsShortReadTagValueError identifies a ErrShortReadTagValue error.
+func IsShortReadTagValueError(err error) bool {
+ de, ok := err.(decodeError)
+ if ok {
+ return de.cause == tiff.ErrShortReadTagValue
+ }
+ return false
+}
+
+// A TagNotPresentError is returned when the requested field is not
+// present in the EXIF.
+type TagNotPresentError FieldName
+
+func (tag TagNotPresentError) Error() string {
+ return fmt.Sprintf("exif: tag %q is not present", string(tag))
+}
+
+func IsTagNotPresentError(err error) bool {
+ _, ok := err.(TagNotPresentError)
+ return ok
+}
+
+// Parser allows the registration of custom parsing and field loading
+// in the Decode function.
+type Parser interface {
+ // Parse should read data from x and insert parsed fields into x via
+ // LoadTags.
+ Parse(x *Exif) error
+}
+
+var parsers []Parser
+
+func init() {
+ RegisterParsers(&parser{})
+}
+
+// RegisterParsers registers one or more parsers to be automatically called
+// when decoding EXIF data via the Decode function.
+func RegisterParsers(ps ...Parser) {
+ parsers = append(parsers, ps...)
+}
+
+type parser struct{}
+
+type tiffErrors map[tiffError]string
+
+func (te tiffErrors) Error() string {
+ var allErrors []string
+ for k, v := range te {
+ allErrors = append(allErrors, fmt.Sprintf("%s: %v\n", stagePrefix[k], v))
+ }
+ return strings.Join(allErrors, "\n")
+}
+
+// IsCriticalError, given the error returned by Decode, reports whether the
+// returned *Exif may contain usable information.
+func IsCriticalError(err error) bool {
+ _, ok := err.(tiffErrors)
+ return !ok
+}
+
+// IsExifError reports whether the error happened while decoding the EXIF
+// sub-IFD.
+func IsExifError(err error) bool {
+ if te, ok := err.(tiffErrors); ok {
+ _, isExif := te[loadExif]
+ return isExif
+ }
+ return false
+}
+
+// IsGPSError reports whether the error happened while decoding the GPS sub-IFD.
+func IsGPSError(err error) bool {
+ if te, ok := err.(tiffErrors); ok {
+ _, isGPS := te[loadExif]
+ return isGPS
+ }
+ return false
+}
+
+// IsInteroperabilityError reports whether the error happened while decoding the
+// Interoperability sub-IFD.
+func IsInteroperabilityError(err error) bool {
+ if te, ok := err.(tiffErrors); ok {
+ _, isInterop := te[loadInteroperability]
+ return isInterop
+ }
+ return false
+}
+
+type tiffError int
+
+const (
+ loadExif tiffError = iota
+ loadGPS
+ loadInteroperability
+)
+
+var stagePrefix = map[tiffError]string{
+ loadExif: "loading EXIF sub-IFD",
+ loadGPS: "loading GPS sub-IFD",
+ loadInteroperability: "loading Interoperability sub-IFD",
+}
+
+// Parse reads data from the tiff data in x and populates the tags
+// in x. If parsing a sub-IFD fails, the error is recorded and
+// parsing continues with the remaining sub-IFDs.
+func (p *parser) Parse(x *Exif) error {
+ x.LoadTags(x.Tiff.Dirs[0], exifFields, false)
+
+ // thumbnails
+ if len(x.Tiff.Dirs) >= 2 {
+ x.LoadTags(x.Tiff.Dirs[1], thumbnailFields, false)
+ }
+
+ te := make(tiffErrors)
+
+ // recurse into exif, gps, and interop sub-IFDs
+ if err := loadSubDir(x, ExifIFDPointer, exifFields); err != nil {
+ te[loadExif] = err.Error()
+ }
+ if err := loadSubDir(x, GPSInfoIFDPointer, gpsFields); err != nil {
+ te[loadGPS] = err.Error()
+ }
+
+ if err := loadSubDir(x, InteroperabilityIFDPointer, interopFields); err != nil {
+ te[loadInteroperability] = err.Error()
+ }
+ if len(te) > 0 {
+ return te
+ }
+ return nil
+}
+
+func loadSubDir(x *Exif, ptr FieldName, fieldMap map[uint16]FieldName) error {
+ r := bytes.NewReader(x.Raw)
+
+ tag, err := x.Get(ptr)
+ if err != nil {
+ return nil
+ }
+ offset, err := tag.Int64(0)
+ if err != nil {
+ return nil
+ }
+
+ _, err = r.Seek(offset, 0)
+ if err != nil {
+ return fmt.Errorf("exif: seek to sub-IFD %s failed: %v", ptr, err)
+ }
+ subDir, _, err := tiff.DecodeDir(r, x.Tiff.Order)
+ if err != nil {
+ return fmt.Errorf("exif: sub-IFD %s decode failed: %v", ptr, err)
+ }
+ x.LoadTags(subDir, fieldMap, false)
+ return nil
+}
+
+// Exif provides access to decoded EXIF metadata fields and values.
+type Exif struct {
+ Tiff *tiff.Tiff
+ main map[FieldName]*tiff.Tag
+ Raw []byte
+}
+
+// Decode parses EXIF-encoded data from r and returns a queryable Exif
+// object. After the exif data section is called and the tiff structure
+// decoded, each registered parser is called (in order of registration). If
+// one parser returns an error, decoding terminates and the remaining
+// parsers are not called.
+// The error can be inspected with functions such as IsCriticalError to
+// determine whether the returned object might still be usable.
+func Decode(r io.Reader) (*Exif, error) {
+ // EXIF data in JPEG is stored in the APP1 marker. EXIF data uses the TIFF
+ // format to store data.
+ // If we're parsing a TIFF image, we don't need to strip away any data.
+ // If we're parsing a JPEG image, we need to strip away the JPEG APP1
+ // marker and also the EXIF header.
+
+ header := make([]byte, 4)
+ n, err := r.Read(header)
+ if err != nil {
+ return nil, err
+ }
+ if n < len(header) {
+ return nil, errors.New("exif: short read on header")
+ }
+
+ var isTiff bool
+ switch string(header) {
+ case "II*\x00":
+ // TIFF - Little endian (Intel)
+ isTiff = true
+ case "MM\x00*":
+ // TIFF - Big endian (Motorola)
+ isTiff = true
+ default:
+ // Not TIFF, assume JPEG
+ }
+
+ // Put the header bytes back into the reader.
+ r = io.MultiReader(bytes.NewReader(header), r)
+ var (
+ er *bytes.Reader
+ tif *tiff.Tiff
+ )
+
+ if isTiff {
+ // Functions below need the IFDs from the TIFF data to be stored in a
+ // *bytes.Reader. We use TeeReader to get a copy of the bytes as a
+ // side-effect of tiff.Decode() doing its work.
+ b := &bytes.Buffer{}
+ tr := io.TeeReader(r, b)
+ tif, err = tiff.Decode(tr)
+ er = bytes.NewReader(b.Bytes())
+ } else {
+ // Locate the JPEG APP1 header.
+ var sec *appSec
+ sec, err = newAppSec(jpeg_APP1, r)
+ if err != nil {
+ return nil, err
+ }
+ // Strip away EXIF header.
+ er, err = sec.exifReader()
+ if err != nil {
+ return nil, err
+ }
+ tif, err = tiff.Decode(er)
+ }
+
+ if err != nil {
+ return nil, decodeError{cause: err}
+ }
+
+ er.Seek(0, 0)
+ raw, err := ioutil.ReadAll(er)
+ if err != nil {
+ return nil, decodeError{cause: err}
+ }
+
+ // build an exif structure from the tiff
+ x := &Exif{
+ main: map[FieldName]*tiff.Tag{},
+ Tiff: tif,
+ Raw: raw,
+ }
+
+ for i, p := range parsers {
+ if err := p.Parse(x); err != nil {
+ if _, ok := err.(tiffErrors); ok {
+ return x, err
+ }
+ // This should never happen, as Parse always returns a tiffError
+ // for now, but that could change.
+ return x, fmt.Errorf("exif: parser %v failed (%v)", i, err)
+ }
+ }
+
+ return x, nil
+}
+
+// LoadTags loads tags into the available fields from the tiff Directory
+// using the given tagid-fieldname mapping. Used to load makernote and
+// other meta-data. If showMissing is true, tags in d that are not in the
+// fieldMap will be loaded with the FieldName UnknownPrefix followed by the
+// tag ID (in hex format).
+func (x *Exif) LoadTags(d *tiff.Dir, fieldMap map[uint16]FieldName, showMissing bool) {
+ for _, tag := range d.Tags {
+ name := fieldMap[tag.Id]
+ if name == "" {
+ if !showMissing {
+ continue
+ }
+ name = FieldName(fmt.Sprintf("%v%x", UnknownPrefix, tag.Id))
+ }
+ x.main[name] = tag
+ }
+}
+
+// Get retrieves the EXIF tag for the given field name.
+//
+// If the tag is not known or not present, an error is returned. If the
+// tag name is known, the error will be a TagNotPresentError.
+func (x *Exif) Get(name FieldName) (*tiff.Tag, error) {
+ if tg, ok := x.main[name]; ok {
+ return tg, nil
+ }
+ return nil, TagNotPresentError(name)
+}
+
+// Walker is the interface used to traverse all fields of an Exif object.
+type Walker interface {
+ // Walk is called for each non-nil EXIF field. Returning a non-nil
+ // error aborts the walk/traversal.
+ Walk(name FieldName, tag *tiff.Tag) error
+}
+
+// Walk calls the Walk method of w with the name and tag for every non-nil
+// EXIF field. If w aborts the walk with an error, that error is returned.
+func (x *Exif) Walk(w Walker) error {
+ for name, tag := range x.main {
+ if err := w.Walk(name, tag); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// DateTime returns the EXIF's "DateTimeOriginal" field, which
+// is the creation time of the photo. If not found, it tries
+// the "DateTime" (which is meant as the modtime) instead.
+// The error will be TagNotPresentErr if none of those tags
+// were found, or a generic error if the tag value was
+// not a string, or the error returned by time.Parse.
+//
+// If the EXIF lacks timezone information or GPS time, the returned
+// time's Location will be time.Local.
+func (x *Exif) DateTime() (time.Time, error) {
+ var dt time.Time
+ tag, err := x.Get(DateTimeOriginal)
+ if err != nil {
+ tag, err = x.Get(DateTime)
+ if err != nil {
+ return dt, err
+ }
+ }
+ if tag.Format() != tiff.StringVal {
+ return dt, errors.New("DateTime[Original] not in string format")
+ }
+ exifTimeLayout := "2006:01:02 15:04:05"
+ dateStr := strings.TrimRight(string(tag.Val), "\x00")
+ // TODO(bradfitz,mpl): look for timezone offset, GPS time, etc.
+ // For now, just always return the time.Local timezone.
+ return time.ParseInLocation(exifTimeLayout, dateStr, time.Local)
+}
+
+func ratFloat(num, dem int64) float64 {
+ return float64(num) / float64(dem)
+}
+
+// Tries to parse a Geo degrees value from a string as it was found in some
+// EXIF data.
+// Supported formats so far:
+// - "52,00000,50,00000,34,01180" ==> 52 deg 50'34.0118"
+// Probably due to locale the comma is used as decimal mark as well as the
+// separator of three floats (degrees, minutes, seconds)
+// http://en.wikipedia.org/wiki/Decimal_mark#Hindu.E2.80.93Arabic_numeral_system
+// - "52.0,50.0,34.01180" ==> 52deg50'34.0118"
+// - "52,50,34.01180" ==> 52deg50'34.0118"
+func parseTagDegreesString(s string) (float64, error) {
+ const unparsableErrorFmt = "Unknown coordinate format: %s"
+ isSplitRune := func(c rune) bool {
+ return c == ',' || c == ';'
+ }
+ parts := strings.FieldsFunc(s, isSplitRune)
+ var degrees, minutes, seconds float64
+ var err error
+ switch len(parts) {
+ case 6:
+ degrees, err = strconv.ParseFloat(parts[0]+"."+parts[1], 64)
+ if err != nil {
+ return 0.0, fmt.Errorf(unparsableErrorFmt, s)
+ }
+ minutes, err = strconv.ParseFloat(parts[2]+"."+parts[3], 64)
+ if err != nil {
+ return 0.0, fmt.Errorf(unparsableErrorFmt, s)
+ }
+ minutes = math.Copysign(minutes, degrees)
+ seconds, err = strconv.ParseFloat(parts[4]+"."+parts[5], 64)
+ if err != nil {
+ return 0.0, fmt.Errorf(unparsableErrorFmt, s)
+ }
+ seconds = math.Copysign(seconds, degrees)
+ case 3:
+ degrees, err = strconv.ParseFloat(parts[0], 64)
+ if err != nil {
+ return 0.0, fmt.Errorf(unparsableErrorFmt, s)
+ }
+ minutes, err = strconv.ParseFloat(parts[1], 64)
+ if err != nil {
+ return 0.0, fmt.Errorf(unparsableErrorFmt, s)
+ }
+ minutes = math.Copysign(minutes, degrees)
+ seconds, err = strconv.ParseFloat(parts[2], 64)
+ if err != nil {
+ return 0.0, fmt.Errorf(unparsableErrorFmt, s)
+ }
+ seconds = math.Copysign(seconds, degrees)
+ default:
+ return 0.0, fmt.Errorf(unparsableErrorFmt, s)
+ }
+ return degrees + minutes/60.0 + seconds/3600.0, nil
+}
+
+func parse3Rat2(tag *tiff.Tag) ([3]float64, error) {
+ v := [3]float64{}
+ for i := range v {
+ num, den, err := tag.Rat2(i)
+ if err != nil {
+ return v, err
+ }
+ v[i] = ratFloat(num, den)
+ if tag.Count < uint32(i+2) {
+ break
+ }
+ }
+ return v, nil
+}
+
+func tagDegrees(tag *tiff.Tag) (float64, error) {
+ switch tag.Format() {
+ case tiff.RatVal:
+ // The usual case, according to the Exif spec
+ // (http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf,
+ // sec 4.6.6, p. 52 et seq.)
+ v, err := parse3Rat2(tag)
+ if err != nil {
+ return 0.0, err
+ }
+ return v[0] + v[1]/60 + v[2]/3600.0, nil
+ case tiff.StringVal:
+ // Encountered this weird case with a panorama picture taken with a HTC phone
+ s, err := tag.StringVal()
+ if err != nil {
+ return 0.0, err
+ }
+ return parseTagDegreesString(s)
+ default:
+ // don't know how to parse value, give up
+ return 0.0, fmt.Errorf("Malformed EXIF Tag Degrees")
+ }
+}
+
+// LatLong returns the latitude and longitude of the photo and
+// whether it was present.
+func (x *Exif) LatLong() (lat, long float64, err error) {
+ // All calls of x.Get might return an TagNotPresentError
+ longTag, err := x.Get(FieldName("GPSLongitude"))
+ if err != nil {
+ return
+ }
+ ewTag, err := x.Get(FieldName("GPSLongitudeRef"))
+ if err != nil {
+ return
+ }
+ latTag, err := x.Get(FieldName("GPSLatitude"))
+ if err != nil {
+ return
+ }
+ nsTag, err := x.Get(FieldName("GPSLatitudeRef"))
+ if err != nil {
+ return
+ }
+ if long, err = tagDegrees(longTag); err != nil {
+ return 0, 0, fmt.Errorf("Cannot parse longitude: %v", err)
+ }
+ if lat, err = tagDegrees(latTag); err != nil {
+ return 0, 0, fmt.Errorf("Cannot parse latitude: %v", err)
+ }
+ ew, err := ewTag.StringVal()
+ if err == nil && ew == "W" {
+ long *= -1.0
+ } else if err != nil {
+ return 0, 0, fmt.Errorf("Cannot parse longitude: %v", err)
+ }
+ ns, err := nsTag.StringVal()
+ if err == nil && ns == "S" {
+ lat *= -1.0
+ } else if err != nil {
+ return 0, 0, fmt.Errorf("Cannot parse longitude: %v", err)
+ }
+ return lat, long, nil
+}
+
+// String returns a pretty text representation of the decoded exif data.
+func (x *Exif) String() string {
+ var buf bytes.Buffer
+ for name, tag := range x.main {
+ fmt.Fprintf(&buf, "%s: %s\n", name, tag)
+ }
+ return buf.String()
+}
+
+// JpegThumbnail returns the jpeg thumbnail if it exists. If it doesn't exist,
+// TagNotPresentError will be returned
+func (x *Exif) JpegThumbnail() ([]byte, error) {
+ offset, err := x.Get(ThumbJPEGInterchangeFormat)
+ if err != nil {
+ return nil, err
+ }
+ start, err := offset.Int(0)
+ if err != nil {
+ return nil, err
+ }
+
+ length, err := x.Get(ThumbJPEGInterchangeFormatLength)
+ if err != nil {
+ return nil, err
+ }
+ l, err := length.Int(0)
+ if err != nil {
+ return nil, err
+ }
+
+ return x.Raw[start : start+l], nil
+}
+
+// MarshalJson implements the encoding/json.Marshaler interface providing output of
+// all EXIF fields present (names and values).
+func (x Exif) MarshalJSON() ([]byte, error) {
+ return json.Marshal(x.main)
+}
+
+type appSec struct {
+ marker byte
+ data []byte
+}
+
+// newAppSec finds marker in r and returns the corresponding application data
+// section.
+func newAppSec(marker byte, r io.Reader) (*appSec, error) {
+ br := bufio.NewReader(r)
+ app := &appSec{marker: marker}
+ var dataLen int
+
+ // seek to marker
+ for dataLen == 0 {
+ if _, err := br.ReadBytes(0xFF); err != nil {
+ return nil, err
+ }
+ c, err := br.ReadByte()
+ if err != nil {
+ return nil, err
+ } else if c != marker {
+ continue
+ }
+
+ dataLenBytes := make([]byte, 2)
+ for k,_ := range dataLenBytes {
+ c, err := br.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ dataLenBytes[k] = c
+ }
+ dataLen = int(binary.BigEndian.Uint16(dataLenBytes)) - 2
+ }
+
+ // read section data
+ nread := 0
+ for nread < dataLen {
+ s := make([]byte, dataLen-nread)
+ n, err := br.Read(s)
+ nread += n
+ if err != nil && nread < dataLen {
+ return nil, err
+ }
+ app.data = append(app.data, s[:n]...)
+ }
+ return app, nil
+}
+
+// reader returns a reader on this appSec.
+func (app *appSec) reader() *bytes.Reader {
+ return bytes.NewReader(app.data)
+}
+
+// exifReader returns a reader on this appSec with the read cursor advanced to
+// the start of the exif's tiff encoded portion.
+func (app *appSec) exifReader() (*bytes.Reader, error) {
+ if len(app.data) < 6 {
+ return nil, errors.New("exif: failed to find exif intro marker")
+ }
+
+ // read/check for exif special mark
+ exif := app.data[:6]
+ if !bytes.Equal(exif, append([]byte("Exif"), 0x00, 0x00)) {
+ return nil, errors.New("exif: failed to find exif intro marker")
+ }
+ return bytes.NewReader(app.data[6:]), nil
+}
diff --git a/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/exif_test.go b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/exif_test.go
new file mode 100644
index 000000000..c53f1ddda
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/exif_test.go
@@ -0,0 +1,202 @@
+package exif
+
+//go:generate go run regen_regress.go -- regress_expected_test.go
+//go:generate go fmt regress_expected_test.go
+
+import (
+ "flag"
+ "fmt"
+ "math"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/rwcarlsen/goexif/tiff"
+)
+
+var dataDir = flag.String("test_data_dir", ".", "Directory where the data files for testing are located")
+
+func TestDecode(t *testing.T) {
+ fpath := filepath.Join(*dataDir, "samples")
+ f, err := os.Open(fpath)
+ if err != nil {
+ t.Fatalf("Could not open sample directory '%s': %v", fpath, err)
+ }
+
+ names, err := f.Readdirnames(0)
+ if err != nil {
+ t.Fatalf("Could not read sample directory '%s': %v", fpath, err)
+ }
+
+ cnt := 0
+ for _, name := range names {
+ if !strings.HasSuffix(name, ".jpg") {
+ t.Logf("skipping non .jpg file %v", name)
+ continue
+ }
+ t.Logf("testing file %v", name)
+ f, err := os.Open(filepath.Join(fpath, name))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ x, err := Decode(f)
+ if err != nil {
+ t.Fatal(err)
+ } else if x == nil {
+ t.Fatalf("No error and yet %v was not decoded", name)
+ }
+
+ t.Logf("checking pic %v", name)
+ x.Walk(&walker{name, t})
+ cnt++
+ }
+ if cnt != len(regressExpected) {
+ t.Errorf("Did not process enough samples, got %d, want %d", cnt, len(regressExpected))
+ }
+}
+
+type walker struct {
+ picName string
+ t *testing.T
+}
+
+func (w *walker) Walk(field FieldName, tag *tiff.Tag) error {
+ // this needs to be commented out when regenerating regress expected vals
+ pic := regressExpected[w.picName]
+ if pic == nil {
+ w.t.Errorf(" regression data not found")
+ return nil
+ }
+
+ exp, ok := pic[field]
+ if !ok {
+ w.t.Errorf(" regression data does not have field %v", field)
+ return nil
+ }
+
+ s := tag.String()
+ if tag.Count == 1 && s != "\"\"" {
+ s = fmt.Sprintf("[%s]", s)
+ }
+ got := tag.String()
+
+ if exp != got {
+ fmt.Println("s: ", s)
+ fmt.Printf("len(s)=%v\n", len(s))
+ w.t.Errorf(" field %v bad tag: expected '%s', got '%s'", field, exp, got)
+ }
+ return nil
+}
+
+func TestMarshal(t *testing.T) {
+ name := filepath.Join(*dataDir, "sample1.jpg")
+ f, err := os.Open(name)
+ if err != nil {
+ t.Fatalf("%v\n", err)
+ }
+ defer f.Close()
+
+ x, err := Decode(f)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if x == nil {
+ t.Fatal("bad err")
+ }
+
+ b, err := x.MarshalJSON()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t.Logf("%s", b)
+}
+
+func testSingleParseDegreesString(t *testing.T, s string, w float64) {
+ g, err := parseTagDegreesString(s)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if math.Abs(w-g) > 1e-10 {
+ t.Errorf("Wrong parsing result %s: Want %.12f, got %.12f", s, w, g)
+ }
+}
+
+func TestParseTagDegreesString(t *testing.T) {
+ // semicolon as decimal mark
+ testSingleParseDegreesString(t, "52,00000,50,00000,34,01180", 52.842781055556) // comma as separator
+ testSingleParseDegreesString(t, "52,00000;50,00000;34,01180", 52.842781055556) // semicolon as separator
+
+ // point as decimal mark
+ testSingleParseDegreesString(t, "14.00000,44.00000,34.01180", 14.742781055556) // comma as separator
+ testSingleParseDegreesString(t, "14.00000;44.00000;34.01180", 14.742781055556) // semicolon as separator
+ testSingleParseDegreesString(t, "14.00000;44.00000,34.01180", 14.742781055556) // mixed separators
+
+ testSingleParseDegreesString(t, "-008.0,30.0,03.6", -8.501) // leading zeros
+
+ // no decimal places
+ testSingleParseDegreesString(t, "-10,15,54", -10.265)
+ testSingleParseDegreesString(t, "-10;15;54", -10.265)
+
+ // incorrect mix of comma and point as decimal mark
+ s := "-17,00000,15.00000,04.80000"
+ if _, err := parseTagDegreesString(s); err == nil {
+ t.Error("parseTagDegreesString: false positive for " + s)
+ }
+}
+
+// Make sure we error out early when a tag had a count of MaxUint32
+func TestMaxUint32CountError(t *testing.T) {
+ name := filepath.Join(*dataDir, "corrupt/max_uint32_exif.jpg")
+ f, err := os.Open(name)
+ if err != nil {
+ t.Fatalf("%v\n", err)
+ }
+ defer f.Close()
+
+ _, err = Decode(f)
+ if err == nil {
+ t.Fatal("no error on bad exif data")
+ }
+ if !strings.Contains(err.Error(), "invalid Count offset") {
+ t.Fatal("wrong error:", err.Error())
+ }
+}
+
+// Make sure we error out early with tag data sizes larger than the image file
+func TestHugeTagError(t *testing.T) {
+ name := filepath.Join(*dataDir, "corrupt/huge_tag_exif.jpg")
+ f, err := os.Open(name)
+ if err != nil {
+ t.Fatalf("%v\n", err)
+ }
+ defer f.Close()
+
+ _, err = Decode(f)
+ if err == nil {
+ t.Fatal("no error on bad exif data")
+ }
+ if !strings.Contains(err.Error(), "short read") {
+ t.Fatal("wrong error:", err.Error())
+ }
+}
+
+// Check for a 0-length tag value
+func TestZeroLengthTagError(t *testing.T) {
+ name := filepath.Join(*dataDir, "corrupt/infinite_loop_exif.jpg")
+ f, err := os.Open(name)
+ if err != nil {
+ t.Fatalf("%v\n", err)
+ }
+ defer f.Close()
+
+ _, err = Decode(f)
+ if err == nil {
+ t.Fatal("no error on bad exif data")
+ }
+ if !strings.Contains(err.Error(), "zero length tag value") {
+ t.Fatal("wrong error:", err.Error())
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/fields.go b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/fields.go
new file mode 100644
index 000000000..0388d2390
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/fields.go
@@ -0,0 +1,293 @@
+package exif
+
+type FieldName string
+
+// UnknownPrefix is used as the first part of field names for decoded tags for
+// which there is no known/supported EXIF field.
+const UnknownPrefix = "UnknownTag_"
+
+// Primary EXIF fields
+const (
+ ImageWidth FieldName = "ImageWidth"
+ ImageLength = "ImageLength" // Image height called Length by EXIF spec
+ BitsPerSample = "BitsPerSample"
+ Compression = "Compression"
+ PhotometricInterpretation = "PhotometricInterpretation"
+ Orientation = "Orientation"
+ SamplesPerPixel = "SamplesPerPixel"
+ PlanarConfiguration = "PlanarConfiguration"
+ YCbCrSubSampling = "YCbCrSubSampling"
+ YCbCrPositioning = "YCbCrPositioning"
+ XResolution = "XResolution"
+ YResolution = "YResolution"
+ ResolutionUnit = "ResolutionUnit"
+ DateTime = "DateTime"
+ ImageDescription = "ImageDescription"
+ Make = "Make"
+ Model = "Model"
+ Software = "Software"
+ Artist = "Artist"
+ Copyright = "Copyright"
+ ExifIFDPointer = "ExifIFDPointer"
+ GPSInfoIFDPointer = "GPSInfoIFDPointer"
+ InteroperabilityIFDPointer = "InteroperabilityIFDPointer"
+ ExifVersion = "ExifVersion"
+ FlashpixVersion = "FlashpixVersion"
+ ColorSpace = "ColorSpace"
+ ComponentsConfiguration = "ComponentsConfiguration"
+ CompressedBitsPerPixel = "CompressedBitsPerPixel"
+ PixelXDimension = "PixelXDimension"
+ PixelYDimension = "PixelYDimension"
+ MakerNote = "MakerNote"
+ UserComment = "UserComment"
+ RelatedSoundFile = "RelatedSoundFile"
+ DateTimeOriginal = "DateTimeOriginal"
+ DateTimeDigitized = "DateTimeDigitized"
+ SubSecTime = "SubSecTime"
+ SubSecTimeOriginal = "SubSecTimeOriginal"
+ SubSecTimeDigitized = "SubSecTimeDigitized"
+ ImageUniqueID = "ImageUniqueID"
+ ExposureTime = "ExposureTime"
+ FNumber = "FNumber"
+ ExposureProgram = "ExposureProgram"
+ SpectralSensitivity = "SpectralSensitivity"
+ ISOSpeedRatings = "ISOSpeedRatings"
+ OECF = "OECF"
+ ShutterSpeedValue = "ShutterSpeedValue"
+ ApertureValue = "ApertureValue"
+ BrightnessValue = "BrightnessValue"
+ ExposureBiasValue = "ExposureBiasValue"
+ MaxApertureValue = "MaxApertureValue"
+ SubjectDistance = "SubjectDistance"
+ MeteringMode = "MeteringMode"
+ LightSource = "LightSource"
+ Flash = "Flash"
+ FocalLength = "FocalLength"
+ SubjectArea = "SubjectArea"
+ FlashEnergy = "FlashEnergy"
+ SpatialFrequencyResponse = "SpatialFrequencyResponse"
+ FocalPlaneXResolution = "FocalPlaneXResolution"
+ FocalPlaneYResolution = "FocalPlaneYResolution"
+ FocalPlaneResolutionUnit = "FocalPlaneResolutionUnit"
+ SubjectLocation = "SubjectLocation"
+ ExposureIndex = "ExposureIndex"
+ SensingMethod = "SensingMethod"
+ FileSource = "FileSource"
+ SceneType = "SceneType"
+ CFAPattern = "CFAPattern"
+ CustomRendered = "CustomRendered"
+ ExposureMode = "ExposureMode"
+ WhiteBalance = "WhiteBalance"
+ DigitalZoomRatio = "DigitalZoomRatio"
+ FocalLengthIn35mmFilm = "FocalLengthIn35mmFilm"
+ SceneCaptureType = "SceneCaptureType"
+ GainControl = "GainControl"
+ Contrast = "Contrast"
+ Saturation = "Saturation"
+ Sharpness = "Sharpness"
+ DeviceSettingDescription = "DeviceSettingDescription"
+ SubjectDistanceRange = "SubjectDistanceRange"
+ LensMake = "LensMake"
+ LensModel = "LensModel"
+)
+
+// thumbnail fields
+const (
+ ThumbJPEGInterchangeFormat = "ThumbJPEGInterchangeFormat" // offset to thumb jpeg SOI
+ ThumbJPEGInterchangeFormatLength = "ThumbJPEGInterchangeFormatLength" // byte length of thumb
+)
+
+// GPS fields
+const (
+ GPSVersionID FieldName = "GPSVersionID"
+ GPSLatitudeRef = "GPSLatitudeRef"
+ GPSLatitude = "GPSLatitude"
+ GPSLongitudeRef = "GPSLongitudeRef"
+ GPSLongitude = "GPSLongitude"
+ GPSAltitudeRef = "GPSAltitudeRef"
+ GPSAltitude = "GPSAltitude"
+ GPSTimeStamp = "GPSTimeStamp"
+ GPSSatelites = "GPSSatelites"
+ GPSStatus = "GPSStatus"
+ GPSMeasureMode = "GPSMeasureMode"
+ GPSDOP = "GPSDOP"
+ GPSSpeedRef = "GPSSpeedRef"
+ GPSSpeed = "GPSSpeed"
+ GPSTrackRef = "GPSTrackRef"
+ GPSTrack = "GPSTrack"
+ GPSImgDirectionRef = "GPSImgDirectionRef"
+ GPSImgDirection = "GPSImgDirection"
+ GPSMapDatum = "GPSMapDatum"
+ GPSDestLatitudeRef = "GPSDestLatitudeRef"
+ GPSDestLatitude = "GPSDestLatitude"
+ GPSDestLongitudeRef = "GPSDestLongitudeRef"
+ GPSDestLongitude = "GPSDestLongitude"
+ GPSDestBearingRef = "GPSDestBearingRef"
+ GPSDestBearing = "GPSDestBearing"
+ GPSDestDistanceRef = "GPSDestDistanceRef"
+ GPSDestDistance = "GPSDestDistance"
+ GPSProcessingMethod = "GPSProcessingMethod"
+ GPSAreaInformation = "GPSAreaInformation"
+ GPSDateStamp = "GPSDateStamp"
+ GPSDifferential = "GPSDifferential"
+)
+
+// interoperability fields
+const (
+ InteroperabilityIndex FieldName = "InteroperabilityIndex"
+)
+
+var exifFields = map[uint16]FieldName{
+ /////////////////////////////////////
+ ////////// IFD 0 ////////////////////
+ /////////////////////////////////////
+
+ // image data structure for the thumbnail
+ 0x0100: ImageWidth,
+ 0x0101: ImageLength,
+ 0x0102: BitsPerSample,
+ 0x0103: Compression,
+ 0x0106: PhotometricInterpretation,
+ 0x0112: Orientation,
+ 0x0115: SamplesPerPixel,
+ 0x011C: PlanarConfiguration,
+ 0x0212: YCbCrSubSampling,
+ 0x0213: YCbCrPositioning,
+ 0x011A: XResolution,
+ 0x011B: YResolution,
+ 0x0128: ResolutionUnit,
+
+ // Other tags
+ 0x0132: DateTime,
+ 0x010E: ImageDescription,
+ 0x010F: Make,
+ 0x0110: Model,
+ 0x0131: Software,
+ 0x013B: Artist,
+ 0x8298: Copyright,
+
+ // private tags
+ exifPointer: ExifIFDPointer,
+
+ /////////////////////////////////////
+ ////////// Exif sub IFD /////////////
+ /////////////////////////////////////
+
+ gpsPointer: GPSInfoIFDPointer,
+ interopPointer: InteroperabilityIFDPointer,
+
+ 0x9000: ExifVersion,
+ 0xA000: FlashpixVersion,
+
+ 0xA001: ColorSpace,
+
+ 0x9101: ComponentsConfiguration,
+ 0x9102: CompressedBitsPerPixel,
+ 0xA002: PixelXDimension,
+ 0xA003: PixelYDimension,
+
+ 0x927C: MakerNote,
+ 0x9286: UserComment,
+
+ 0xA004: RelatedSoundFile,
+ 0x9003: DateTimeOriginal,
+ 0x9004: DateTimeDigitized,
+ 0x9290: SubSecTime,
+ 0x9291: SubSecTimeOriginal,
+ 0x9292: SubSecTimeDigitized,
+
+ 0xA420: ImageUniqueID,
+
+ // picture conditions
+ 0x829A: ExposureTime,
+ 0x829D: FNumber,
+ 0x8822: ExposureProgram,
+ 0x8824: SpectralSensitivity,
+ 0x8827: ISOSpeedRatings,
+ 0x8828: OECF,
+ 0x9201: ShutterSpeedValue,
+ 0x9202: ApertureValue,
+ 0x9203: BrightnessValue,
+ 0x9204: ExposureBiasValue,
+ 0x9205: MaxApertureValue,
+ 0x9206: SubjectDistance,
+ 0x9207: MeteringMode,
+ 0x9208: LightSource,
+ 0x9209: Flash,
+ 0x920A: FocalLength,
+ 0x9214: SubjectArea,
+ 0xA20B: FlashEnergy,
+ 0xA20C: SpatialFrequencyResponse,
+ 0xA20E: FocalPlaneXResolution,
+ 0xA20F: FocalPlaneYResolution,
+ 0xA210: FocalPlaneResolutionUnit,
+ 0xA214: SubjectLocation,
+ 0xA215: ExposureIndex,
+ 0xA217: SensingMethod,
+ 0xA300: FileSource,
+ 0xA301: SceneType,
+ 0xA302: CFAPattern,
+ 0xA401: CustomRendered,
+ 0xA402: ExposureMode,
+ 0xA403: WhiteBalance,
+ 0xA404: DigitalZoomRatio,
+ 0xA405: FocalLengthIn35mmFilm,
+ 0xA406: SceneCaptureType,
+ 0xA407: GainControl,
+ 0xA408: Contrast,
+ 0xA409: Saturation,
+ 0xA40A: Sharpness,
+ 0xA40B: DeviceSettingDescription,
+ 0xA40C: SubjectDistanceRange,
+ 0xA433: LensMake,
+ 0xA434: LensModel,
+}
+
+var gpsFields = map[uint16]FieldName{
+ /////////////////////////////////////
+ //// GPS sub-IFD ////////////////////
+ /////////////////////////////////////
+ 0x0: GPSVersionID,
+ 0x1: GPSLatitudeRef,
+ 0x2: GPSLatitude,
+ 0x3: GPSLongitudeRef,
+ 0x4: GPSLongitude,
+ 0x5: GPSAltitudeRef,
+ 0x6: GPSAltitude,
+ 0x7: GPSTimeStamp,
+ 0x8: GPSSatelites,
+ 0x9: GPSStatus,
+ 0xA: GPSMeasureMode,
+ 0xB: GPSDOP,
+ 0xC: GPSSpeedRef,
+ 0xD: GPSSpeed,
+ 0xE: GPSTrackRef,
+ 0xF: GPSTrack,
+ 0x10: GPSImgDirectionRef,
+ 0x11: GPSImgDirection,
+ 0x12: GPSMapDatum,
+ 0x13: GPSDestLatitudeRef,
+ 0x14: GPSDestLatitude,
+ 0x15: GPSDestLongitudeRef,
+ 0x16: GPSDestLongitude,
+ 0x17: GPSDestBearingRef,
+ 0x18: GPSDestBearing,
+ 0x19: GPSDestDistanceRef,
+ 0x1A: GPSDestDistance,
+ 0x1B: GPSProcessingMethod,
+ 0x1C: GPSAreaInformation,
+ 0x1D: GPSDateStamp,
+ 0x1E: GPSDifferential,
+}
+
+var interopFields = map[uint16]FieldName{
+ /////////////////////////////////////
+ //// Interoperability sub-IFD ///////
+ /////////////////////////////////////
+ 0x1: InteroperabilityIndex,
+}
+
+var thumbnailFields = map[uint16]FieldName{
+ 0x0201: ThumbJPEGInterchangeFormat,
+ 0x0202: ThumbJPEGInterchangeFormatLength,
+}
diff --git a/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/regen_regress.go b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/regen_regress.go
new file mode 100644
index 000000000..17bac5287
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/regen_regress.go
@@ -0,0 +1,79 @@
+// +build ignore
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/rwcarlsen/goexif/exif"
+ "github.com/rwcarlsen/goexif/tiff"
+)
+
+func main() {
+ flag.Parse()
+ fname := flag.Arg(0)
+
+ dst, err := os.Create(fname)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer dst.Close()
+
+ dir, err := os.Open("samples")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer dir.Close()
+
+ names, err := dir.Readdirnames(0)
+ if err != nil {
+ log.Fatal(err)
+ }
+ for i, name := range names {
+ names[i] = filepath.Join("samples", name)
+ }
+ makeExpected(names, dst)
+}
+
+func makeExpected(files []string, w io.Writer) {
+ fmt.Fprintf(w, "package exif\n\n")
+ fmt.Fprintf(w, "var regressExpected = map[string]map[FieldName]string{\n")
+
+ for _, name := range files {
+ f, err := os.Open(name)
+ if err != nil {
+ continue
+ }
+
+ x, err := exif.Decode(f)
+ if err != nil {
+ f.Close()
+ continue
+ }
+
+ fmt.Fprintf(w, "\"%v\": map[FieldName]string{\n", filepath.Base(name))
+ x.Walk(&regresswalk{w})
+ fmt.Fprintf(w, "},\n")
+ f.Close()
+ }
+ fmt.Fprintf(w, "}")
+}
+
+type regresswalk struct {
+ wr io.Writer
+}
+
+func (w *regresswalk) Walk(name exif.FieldName, tag *tiff.Tag) error {
+ if strings.HasPrefix(string(name), exif.UnknownPrefix) {
+ fmt.Fprintf(w.wr, "\"%v\": `%v`,\n", name, tag.String())
+ } else {
+ fmt.Fprintf(w.wr, "%v: `%v`,\n", name, tag.String())
+ }
+ return nil
+}
diff --git a/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/regress_expected_test.go b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/regress_expected_test.go
new file mode 100644
index 000000000..bf3998189
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/exif/regress_expected_test.go
@@ -0,0 +1,2293 @@
+package exif
+
+var regressExpected = map[string]map[FieldName]string{
+ "2004-01-11-22-45-15-sep-2004-01-11-22-45-15a.jpg": map[FieldName]string{
+ PixelXDimension: `1600`,
+ InteroperabilityIFDPointer: `1009`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"Samsung Techwin"`,
+ DateTimeOriginal: `"2004:01:11 22:45:15"`,
+ DateTimeDigitized: `"2004:01:11 22:45:15"`,
+ ImageDescription: `"SAMSUNG DIGITAL CAMERA "`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `2`,
+ Flash: `1`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormat: `1039`,
+ MaxApertureValue: `"32/10"`,
+ ExposureProgram: `2`,
+ Software: `"M5011S-1031"`,
+ DateTime: `"2004:01:11 22:45:19"`,
+ FNumber: `"320/100"`,
+ ISOSpeedRatings: `150`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"2/1"`,
+ RelatedSoundFile: `""`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `251`,
+ ExposureTime: `"1000/30000"`,
+ LightSource: `0`,
+ FocalLength: `"82/11"`,
+ ColorSpace: `1`,
+ PixelYDimension: `1200`,
+ FileSource: `""`,
+ Model: `"U-CA 501"`,
+ ThumbJPEGInterchangeFormatLength: `3530`,
+ ExposureBiasValue: `"95/10"`,
+ },
+ "2006-08-03-16-29-38-sep-2006-08-03-16-29-38a.jpg": map[FieldName]string{
+ ThumbJPEGInterchangeFormat: `5108`,
+ ThumbJPEGInterchangeFormatLength: `4323`,
+ MaxApertureValue: `"95/32"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `196`,
+ ExposureTime: `"1/1500"`,
+ InteroperabilityIndex: `"R98"`,
+ FocalPlaneXResolution: `"2816000/225"`,
+ YResolution: `"180/1"`,
+ DateTime: `"2006:08:03 16:29:38"`,
+ ShutterSpeedValue: `"338/32"`,
+ ApertureValue: `"95/32"`,
+ FocalLength: `"5800/1000"`,
+ FlashpixVersion: `"0100"`,
+ Make: `"Canon"`,
+ DateTimeOriginal: `"2006:08:03 16:29:38"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `2824`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ FNumber: `"28/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2006:08:03 16:29:38"`,
+ CompressedBitsPerPixel: `"5/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ UserComment: `""`,
+ PixelXDimension: `2816`,
+ Model: `"Canon PowerShot SD600"`,
+ ExposureBiasValue: `"0/3"`,
+ PixelYDimension: `2112`,
+ FocalPlaneResolutionUnit: `2`,
+ DigitalZoomRatio: `"2816/2816"`,
+ Orientation: `6`,
+ XResolution: `"180/1"`,
+ ExifVersion: `"0220"`,
+ Flash: `24`,
+ FocalPlaneYResolution: `"2112000/169"`,
+ CustomRendered: `0`,
+ },
+ "2006-11-11-19-17-56-sep-2006-11-11-19-17-56a.jpg": map[FieldName]string{
+ FNumber: `"28/10"`,
+ ExposureProgram: `2`,
+ Software: `"E3200v1.1"`,
+ DateTime: `"2006:11:11 19:17:56"`,
+ ExposureTime: `"10/601"`,
+ ISOSpeedRatings: `50`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"4/1"`,
+ Saturation: `0`,
+ XResolution: `"300/1"`,
+ ExifIFDPointer: `284`,
+ ExposureBiasValue: `"0/10"`,
+ LightSource: `0`,
+ FocalLength: `"58/10"`,
+ ColorSpace: `1`,
+ PixelYDimension: `1536`,
+ FileSource: `""`,
+ Model: `"E3200"`,
+ ThumbJPEGInterchangeFormatLength: `4546`,
+ DateTimeDigitized: `"2006:11:11 19:17:56"`,
+ PixelXDimension: `2048`,
+ InteroperabilityIFDPointer: `1026`,
+ SceneType: `""`,
+ DigitalZoomRatio: `"0/100"`,
+ GainControl: `0`,
+ Make: `"NIKON"`,
+ DateTimeOriginal: `"2006:11:11 19:17:56"`,
+ InteroperabilityIndex: `"R98"`,
+ ImageDescription: `" "`,
+ Sharpness: `0`,
+ YCbCrPositioning: `2`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `5`,
+ Flash: `25`,
+ FocalLengthIn35mmFilm: `38`,
+ SubjectDistanceRange: `0`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ MaxApertureValue: `"30/10"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `0`,
+ YResolution: `"300/1"`,
+ ThumbJPEGInterchangeFormat: `4596`,
+ CustomRendered: `1`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ MakerNote: `""`,
+ UserComment: `" "`,
+ },
+ "2006-12-10-23-58-20-sep-2006-12-10-23-58-20a.jpg": map[FieldName]string{
+ Model: `"Canon PowerShot A80"`,
+ ExposureBiasValue: `"0/3"`,
+ PixelYDimension: `1704`,
+ FocalPlaneResolutionUnit: `2`,
+ FocalPlaneYResolution: `"1704000/210"`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"2272/2272"`,
+ Orientation: `1`,
+ XResolution: `"180/1"`,
+ ExifVersion: `"0220"`,
+ Flash: `24`,
+ ThumbJPEGInterchangeFormat: `2036`,
+ ThumbJPEGInterchangeFormatLength: `6465`,
+ MaxApertureValue: `"95/32"`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `196`,
+ ExposureTime: `"1/80"`,
+ FocalLength: `"250/32"`,
+ FlashpixVersion: `"0100"`,
+ FocalPlaneXResolution: `"2272000/280"`,
+ YResolution: `"180/1"`,
+ DateTime: `"2006:12:10 23:58:20"`,
+ ShutterSpeedValue: `"202/32"`,
+ ApertureValue: `"95/32"`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Make: `"Canon"`,
+ DateTimeOriginal: `"2006:12:10 23:58:20"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `1844`,
+ FNumber: `"28/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ UserComment: `""`,
+ PixelXDimension: `2272`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2006:12:10 23:58:20"`,
+ CompressedBitsPerPixel: `"3/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ },
+ "2006-12-17-07-09-14-sep-2006-12-17-07-09-14a.jpg": map[FieldName]string{
+ WhiteBalance: `0`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormatLength: `7063`,
+ ExposureBiasValue: `"0/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1536`,
+ ExposureMode: `0`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"PENTAX Corporation"`,
+ DateTimeDigitized: `"2006:12:17 07:09:14"`,
+ PixelXDimension: `2048`,
+ InteroperabilityIFDPointer: `31048`,
+ CustomRendered: `0`,
+ DateTime: `"2006:12:17 07:09:14"`,
+ ExposureProgram: `2`,
+ FocalLengthIn35mmFilm: `38`,
+ Saturation: `0`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `64`,
+ ExifVersion: `"0220"`,
+ CompressedBitsPerPixel: `"5725504/3145728"`,
+ Flash: `24`,
+ Model: `"PENTAX Optio S6"`,
+ ThumbJPEGInterchangeFormat: `31172`,
+ MaxApertureValue: `"27/10"`,
+ FocalLength: `"62/10"`,
+ ColorSpace: `1`,
+ DateTimeOriginal: `"2006:12:17 07:09:14"`,
+ MakerNote: `""`,
+ DigitalZoomRatio: `"100/100"`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ Software: `"Optio S6 Ver 1.00"`,
+ FNumber: `"270/100"`,
+ Sharpness: `0`,
+ ComponentsConfiguration: `""`,
+ MeteringMode: `5`,
+ SubjectDistanceRange: `2`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `586`,
+ ExposureTime: `"1/160"`,
+ },
+ "2006-12-21-15-55-26-sep-2006-12-21-15-55-26a.jpg": map[FieldName]string{
+ DateTimeDigitized: `"2006:12:21 15:55:26"`,
+ CompressedBitsPerPixel: `"8/1"`,
+ MeteringMode: `3`,
+ MakerNote: `""`,
+ PixelXDimension: `2592`,
+ Saturation: `0`,
+ ImageDescription: `" "`,
+ Model: `"DSC-W15"`,
+ ExposureBiasValue: `"-20/10"`,
+ PixelYDimension: `1944`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `100`,
+ ExifVersion: `"0220"`,
+ Flash: `79`,
+ CustomRendered: `0`,
+ ThumbJPEGInterchangeFormat: `2484`,
+ ThumbJPEGInterchangeFormatLength: `13571`,
+ ExposureProgram: `2`,
+ MaxApertureValue: `"48/16"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `256`,
+ ExposureTime: `"10/400"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ YResolution: `"72/1"`,
+ DateTime: `"2006:12:21 15:55:26"`,
+ LightSource: `0`,
+ FocalLength: `"79/10"`,
+ FlashpixVersion: `"0100"`,
+ Contrast: `0`,
+ Make: `"SONY"`,
+ DateTimeOriginal: `"2006:12:21 15:55:26"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `2278`,
+ ExposureMode: `1`,
+ SceneCaptureType: `0`,
+ FNumber: `"28/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ },
+ "2007-01-01-12-00-00-sep-2007-01-01-12-00-00a.jpg": map[FieldName]string{
+ MaxApertureValue: `"286/100"`,
+ ExposureIndex: `"200/1"`,
+ ThumbJPEGInterchangeFormat: `13848`,
+ ThumbJPEGInterchangeFormatLength: `3436`,
+ ExposureProgram: `2`,
+ ExposureTime: `"8942/1000000"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `340`,
+ ApertureValue: `"286/100"`,
+ LightSource: `0`,
+ FocalLength: `"60/10"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"480/1"`,
+ Software: `"KODAK EASYSHARE C713 ZOOM DIGITAL CAMERA"`,
+ ShutterSpeedValue: `"680/100"`,
+ InteroperabilityIFDPointer: `13816`,
+ ExposureMode: `0`,
+ FocalLengthIn35mmFilm: `36`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ Make: `"EASTMAN KODAK COMPANY"`,
+ DateTimeOriginal: `"2007:01:01 12:00:00"`,
+ ComponentsConfiguration: `""`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ FNumber: `"270/100"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ PixelXDimension: `1280`,
+ SensingMethod: `2`,
+ GainControl: `2`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ DateTimeDigitized: `"2007:01:01 12:00:00"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ Model: `"KODAK EASYSHARE C713 ZOOM DIGITAL CAMERA"`,
+ ExposureBiasValue: `"0/10"`,
+ PixelYDimension: `960`,
+ ExifVersion: `"0221"`,
+ Flash: `25`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/10"`,
+ Orientation: `1`,
+ XResolution: `"480/1"`,
+ ISOSpeedRatings: `200`,
+ },
+ "2007-01-17-21-49-44-sep-2007-01-17-21-49-44a.jpg": map[FieldName]string{
+ XResolution: `"180/1"`,
+ ISOSpeedRatings: `50`,
+ ExifVersion: `"0220"`,
+ Flash: `24`,
+ CustomRendered: `0`,
+ Orientation: `1`,
+ ThumbJPEGInterchangeFormatLength: `7024`,
+ ExposureProgram: `2`,
+ MaxApertureValue: `"297/100"`,
+ ThumbJPEGInterchangeFormat: `956`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `266`,
+ ExposureTime: `"1/30"`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ Software: `"1.00.018PR "`,
+ DateTime: `"2007:01:17 21:49:44"`,
+ ShutterSpeedValue: `"491/100"`,
+ ApertureValue: `"33/10"`,
+ LightSource: `0`,
+ FocalLength: `"73/10"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"180/1"`,
+ DateTimeOriginal: `"2007:01:17 21:49:44"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `832`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Make: `"Digital Camera "`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ FNumber: `"33/10"`,
+ MeteringMode: `2`,
+ MakerNote: `"6106789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456"`,
+ PixelXDimension: `2816`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2007:01:17 21:49:44"`,
+ Model: `"6MP-9Y8 "`,
+ ExposureBiasValue: `"0/10"`,
+ PixelYDimension: `2112`,
+ ImageDescription: `"Digital image "`,
+ },
+ "2007-02-02-18-13-29-sep-2007-02-02-18-13-29a.jpg": map[FieldName]string{
+ Software: `"Optio S5z Ver 1.00 "`,
+ FNumber: `"26/10"`,
+ Sharpness: `0`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `586`,
+ ExposureTime: `"1/60"`,
+ ComponentsConfiguration: `""`,
+ MeteringMode: `5`,
+ SubjectDistanceRange: `2`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormatLength: `8800`,
+ ExposureBiasValue: `"0/3"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1920`,
+ WhiteBalance: `0`,
+ Make: `"PENTAX Corporation "`,
+ DateTimeDigitized: `"2007:02:02 18:13:29"`,
+ PixelXDimension: `2560`,
+ InteroperabilityIFDPointer: `30974`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ InteroperabilityIndex: `"R98"`,
+ DateTime: `"2007:02:02 18:13:29"`,
+ ExposureProgram: `2`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `200`,
+ ExifVersion: `"0220"`,
+ CompressedBitsPerPixel: `"27033600/4915200"`,
+ Flash: `25`,
+ FocalLengthIn35mmFilm: `35`,
+ Saturation: `0`,
+ Model: `"PENTAX Optio S5z "`,
+ ThumbJPEGInterchangeFormat: `31098`,
+ MaxApertureValue: `"28/10"`,
+ FocalLength: `"580/100"`,
+ ColorSpace: `1`,
+ DateTimeOriginal: `"2007:02:02 18:13:29"`,
+ MakerNote: `""`,
+ DigitalZoomRatio: `"0/0"`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ },
+ "2007-05-02-17-02-21-sep-2007-05-02-17-02-21a.jpg": map[FieldName]string{
+ UserComment: `""`,
+ PixelXDimension: `1600`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2007:05:02 17:02:21"`,
+ CompressedBitsPerPixel: `"3/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ Model: `"Canon IXY DIGITAL 55"`,
+ ExposureBiasValue: `"0/3"`,
+ PixelYDimension: `1200`,
+ FocalPlaneResolutionUnit: `2`,
+ FocalPlaneYResolution: `"1200000/168"`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"2592/2592"`,
+ Orientation: `1`,
+ XResolution: `"180/1"`,
+ ExifVersion: `"0220"`,
+ Flash: `9`,
+ ThumbJPEGInterchangeFormat: `5108`,
+ ThumbJPEGInterchangeFormatLength: `6306`,
+ MaxApertureValue: `"107/32"`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `196`,
+ ExposureTime: `"1/60"`,
+ FocalLength: `"7109/1000"`,
+ FlashpixVersion: `"0100"`,
+ FocalPlaneXResolution: `"1600000/225"`,
+ YResolution: `"180/1"`,
+ DateTime: `"2007:05:02 17:02:21"`,
+ ShutterSpeedValue: `"189/32"`,
+ ApertureValue: `"107/32"`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Make: `"Canon"`,
+ DateTimeOriginal: `"2007:05:02 17:02:21"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `2226`,
+ FNumber: `"32/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ },
+ "2007-05-12-08-19-07-sep-2007-05-12-08-19-07a.jpg": map[FieldName]string{
+ Model: `"EX-Z70 "`,
+ ExposureBiasValue: `"0/3"`,
+ PixelYDimension: `480`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/0"`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ExifVersion: `"0221"`,
+ Flash: `16`,
+ ThumbJPEGInterchangeFormat: `27422`,
+ ThumbJPEGInterchangeFormatLength: `8332`,
+ ExposureProgram: `2`,
+ MaxApertureValue: `"33/10"`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `282`,
+ ExposureTime: `"1/50"`,
+ FocalLength: `"630/100"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"72/1"`,
+ Software: `"1.00 "`,
+ DateTime: `"2007:06:17 22:56:38"`,
+ LightSource: `0`,
+ ExposureMode: `0`,
+ FocalLengthIn35mmFilm: `38`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ Make: `"CASIO COMPUTER CO.,LTD."`,
+ DateTimeOriginal: `"2007:05:12 08:19:07"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `27298`,
+ Sharpness: `0`,
+ FNumber: `"31/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ PixelXDimension: `640`,
+ GainControl: `2`,
+ Saturation: `0`,
+ DateTimeDigitized: `"2007:06:17 22:56:38"`,
+ CompressedBitsPerPixel: `"252746/307200"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ },
+ "2007-05-26-04-49-45-sep-2007-05-26-04-49-45a.jpg": map[FieldName]string{
+ ThumbJPEGInterchangeFormat: `4596`,
+ ThumbJPEGInterchangeFormatLength: `10120`,
+ ExposureProgram: `2`,
+ MaxApertureValue: `"34/10"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `284`,
+ ExposureTime: `"10/3486"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ YResolution: `"300/1"`,
+ Software: `"COOLPIX L3v1.2"`,
+ DateTime: `"2007:05:26 04:49:45"`,
+ LightSource: `0`,
+ FocalLength: `"63/10"`,
+ FlashpixVersion: `"0100"`,
+ Contrast: `0`,
+ Make: `"NIKON"`,
+ DateTimeOriginal: `"2007:05:26 04:49:45"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `1026`,
+ ExposureMode: `0`,
+ FocalLengthIn35mmFilm: `38`,
+ SceneCaptureType: `2`,
+ FNumber: `"32/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ Saturation: `0`,
+ DateTimeDigitized: `"2007:05:26 04:49:45"`,
+ CompressedBitsPerPixel: `"4/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ UserComment: `" "`,
+ PixelXDimension: `2592`,
+ GainControl: `0`,
+ SubjectDistanceRange: `0`,
+ ImageDescription: `" "`,
+ Model: `"COOLPIX L3"`,
+ ExposureBiasValue: `"0/10"`,
+ PixelYDimension: `1944`,
+ Orientation: `1`,
+ XResolution: `"300/1"`,
+ ISOSpeedRatings: `50`,
+ ExifVersion: `"0220"`,
+ Flash: `24`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/100"`,
+ },
+ "2007-05-30-14-28-01-sep-2007-05-30-14-28-01a.jpg": map[FieldName]string{
+ CompressedBitsPerPixel: `"2/1"`,
+ MeteringMode: `5`,
+ UserComment: `" "`,
+ GainControl: `1`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ ExifIFDPointer: `284`,
+ ExposureTime: `"10/40"`,
+ InteroperabilityIndex: `"R98"`,
+ Software: `"COOLPIX S6V1.0"`,
+ ImageDescription: `" "`,
+ Model: `"COOLPIX S6"`,
+ XResolution: `"300/1"`,
+ ISOSpeedRatings: `53`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `1026`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/100"`,
+ Make: `"NIKON"`,
+ Orientation: `1`,
+ Contrast: `0`,
+ FocalLengthIn35mmFilm: `35`,
+ SceneCaptureType: `0`,
+ FileSource: `""`,
+ FNumber: `"30/10"`,
+ ExposureProgram: `2`,
+ DateTimeDigitized: `"2007:05:30 14:28:01"`,
+ MakerNote: `""`,
+ PixelXDimension: `2816`,
+ SceneType: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExposureBiasValue: `"0/10"`,
+ LightSource: `0`,
+ FocalLength: `"58/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `2112`,
+ YResolution: `"300/1"`,
+ DateTime: `"2007:05:30 14:28:01"`,
+ Flash: `16`,
+ ExposureMode: `0`,
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2007:05:30 14:28:01"`,
+ MaxApertureValue: `"32/10"`,
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ThumbJPEGInterchangeFormat: `4596`,
+ ThumbJPEGInterchangeFormatLength: `5274`,
+ },
+ "2007-06-06-16-15-25-sep-2007-06-06-16-15-25a.jpg": map[FieldName]string{
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2007:06:06 16:15:25"`,
+ Flash: `24`,
+ ExposureMode: `0`,
+ ThumbJPEGInterchangeFormat: `4596`,
+ ThumbJPEGInterchangeFormatLength: `5967`,
+ MaxApertureValue: `"30/10"`,
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ExifIFDPointer: `284`,
+ ExposureTime: `"10/2870"`,
+ CompressedBitsPerPixel: `"2/1"`,
+ MeteringMode: `5`,
+ UserComment: `" "`,
+ GainControl: `0`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ InteroperabilityIndex: `"R98"`,
+ ImageDescription: `" "`,
+ Model: `"E3700"`,
+ Software: `"E3700v1.2"`,
+ Make: `"NIKON"`,
+ Orientation: `1`,
+ XResolution: `"300/1"`,
+ ISOSpeedRatings: `50`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `1026`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/100"`,
+ FocalLengthIn35mmFilm: `35`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ FNumber: `"48/10"`,
+ ExposureProgram: `2`,
+ FileSource: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ DateTimeDigitized: `"2007:06:06 16:15:25"`,
+ MakerNote: `""`,
+ PixelXDimension: `2048`,
+ SceneType: `""`,
+ YResolution: `"300/1"`,
+ DateTime: `"2007:06:06 16:15:25"`,
+ ExposureBiasValue: `"0/10"`,
+ LightSource: `0`,
+ FocalLength: `"54/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1536`,
+ },
+ "2007-06-26-10-13-04-sep-2007-06-26-10-13-04a.jpg": map[FieldName]string{
+ ColorSpace: `1`,
+ FileSource: `""`,
+ FNumber: `"3/1"`,
+ CompressedBitsPerPixel: `"6389872/3145728"`,
+ MeteringMode: `2`,
+ MakerNote: `""`,
+ PixelXDimension: `2048`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2007:06:26 10:13:04"`,
+ Model: `"DV"`,
+ Copyright: `"Copyright2004"`,
+ ExposureBiasValue: `"1/4"`,
+ PixelYDimension: `1536`,
+ ImageDescription: `"My beautiful picture"`,
+ XResolution: `"320/1"`,
+ ISOSpeedRatings: `100`,
+ ExifVersion: `"0210"`,
+ Flash: `0`,
+ Orientation: `1`,
+ ThumbJPEGInterchangeFormatLength: `6292`,
+ ExposureProgram: `3`,
+ MaxApertureValue: `"3/1"`,
+ ExposureIndex: `"146/1"`,
+ ThumbJPEGInterchangeFormat: `1306`,
+ YCbCrPositioning: `2`,
+ ExposureTime: `"23697424/268435456"`,
+ ExifIFDPointer: `262`,
+ RelatedSoundFile: `"RelatedSound"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ Software: `"DVWare 1.0"`,
+ DateTime: `"2007:06:26 10:13:04"`,
+ ShutterSpeedValue: `"7/1"`,
+ ApertureValue: `"3/1"`,
+ LightSource: `0`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"384/1"`,
+ DateTimeOriginal: `"2007:06:26 10:13:04"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `1170`,
+ Make: `"CEC"`,
+ },
+ "2007-07-13-17-02-30-sep-2007-07-13-17-02-30a.jpg": map[FieldName]string{
+ Software: `"Ver 1.00 "`,
+ DateTime: `"2007:07:13 17:02:30"`,
+ FNumber: `"48/10"`,
+ ExposureProgram: `2`,
+ RelatedSoundFile: `" "`,
+ Saturation: `0`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `266`,
+ ExposureTime: `"1/110"`,
+ ISOSpeedRatings: `64`,
+ ComponentsConfiguration: `""`,
+ ColorSpace: `1`,
+ PixelYDimension: `2736`,
+ FileSource: `""`,
+ Model: `"ViviCam X30 "`,
+ ThumbJPEGInterchangeFormatLength: `20544`,
+ ShutterSpeedValue: `"678/100"`,
+ ExposureBiasValue: `"0/10"`,
+ LightSource: `0`,
+ DigitalZoomRatio: `"100/100"`,
+ GainControl: `0`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"Vivitar"`,
+ DateTimeOriginal: `"2007:07:13 17:02:30"`,
+ DateTimeDigitized: `"2007:07:13 17:02:30"`,
+ PixelXDimension: `3648`,
+ InteroperabilityIFDPointer: `1010`,
+ ImageDescription: `"Digital StillCamera"`,
+ Sharpness: `0`,
+ Flash: `0`,
+ FocalLengthIn35mmFilm: `35`,
+ SubjectDistanceRange: `0`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `2`,
+ WhiteBalance: `0`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormat: `1156`,
+ ApertureValue: `"45/10"`,
+ MaxApertureValue: `"30/10"`,
+ FlashpixVersion: `"0100"`,
+ MakerNote: `""`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ },
+ "2007-08-15-14-42-46-sep-2007-08-15-14-42-46a.jpg": map[FieldName]string{
+ Model: `"KODAK C663 ZOOM DIGITAL CAMERA"`,
+ ShutterSpeedValue: `"73/10"`,
+ DigitalZoomRatio: `"0/100"`,
+ FocalLengthIn35mmFilm: `66`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ Make: `"EASTMAN KODAK COMPANY"`,
+ Orientation: `1`,
+ XResolution: `"230/1"`,
+ CustomRendered: `0`,
+ ISOSpeedRatings: `80`,
+ ComponentsConfiguration: `""`,
+ FNumber: `"36/10"`,
+ ExposureProgram: `2`,
+ FileSource: `""`,
+ PixelXDimension: `2832`,
+ SensingMethod: `2`,
+ SceneType: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ DateTimeDigitized: `"2007:08:15 14:42:46"`,
+ MakerNote: `""`,
+ FocalLength: `"110/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `2128`,
+ YResolution: `"230/1"`,
+ ApertureValue: `"37/10"`,
+ ExposureBiasValue: `"0/3"`,
+ LightSource: `0`,
+ ExposureMode: `0`,
+ ExifVersion: `"0221"`,
+ DateTimeOriginal: `"2007:08:15 14:42:46"`,
+ Flash: `24`,
+ MaxApertureValue: `"37/10"`,
+ ColorSpace: `1`,
+ ExposureIndex: `"80/1"`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ThumbJPEGInterchangeFormat: `8472`,
+ ThumbJPEGInterchangeFormatLength: `3060`,
+ ExposureTime: `"1/160"`,
+ MeteringMode: `5`,
+ ExifIFDPointer: `320`,
+ GainControl: `0`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ },
+ "2007-08-24-02-40-42-sep-2007-08-24-02-40-42a.jpg": map[FieldName]string{
+ ThumbJPEGInterchangeFormat: `5108`,
+ ThumbJPEGInterchangeFormatLength: `2084`,
+ MaxApertureValue: `"147/32"`,
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ ExifIFDPointer: `196`,
+ ExposureTime: `"1/400"`,
+ CompressedBitsPerPixel: `"5/1"`,
+ MeteringMode: `5`,
+ UserComment: `""`,
+ InteroperabilityIndex: `"R98"`,
+ Model: `"Canon PowerShot SD450"`,
+ ShutterSpeedValue: `"277/32"`,
+ FocalPlaneResolutionUnit: `2`,
+ DigitalZoomRatio: `"2592/2592"`,
+ Make: `"Canon"`,
+ Orientation: `1`,
+ XResolution: `"180/1"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `2206`,
+ FocalPlaneYResolution: `"1944000/168"`,
+ CustomRendered: `0`,
+ SceneCaptureType: `0`,
+ FNumber: `"100/10"`,
+ FileSource: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ DateTimeDigitized: `"2007:08:24 02:40:42"`,
+ MakerNote: `""`,
+ PixelXDimension: `2592`,
+ SensingMethod: `2`,
+ FocalPlaneXResolution: `"2592000/225"`,
+ YResolution: `"180/1"`,
+ DateTime: `"2007:08:24 02:40:42"`,
+ ApertureValue: `"213/32"`,
+ ExposureBiasValue: `"0/3"`,
+ FocalLength: `"17400/1000"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1944`,
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2007:08:24 02:40:42"`,
+ Flash: `24`,
+ ExposureMode: `0`,
+ },
+ "2007-11-07-11-40-44-sep-2007-11-07-11-40-44a.jpg": map[FieldName]string{
+ YResolution: `"72/1"`,
+ Copyright: `" "`,
+ ThumbJPEGInterchangeFormat: `1306`,
+ ApertureValue: `"600/100"`,
+ MaxApertureValue: `"360/100"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `0`,
+ MakerNote: `""`,
+ SensingMethod: `2`,
+ CustomRendered: `1`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Software: `"Digital Camera FinePix Z1 Ver1.00"`,
+ DateTime: `"2007:11:07 11:40:44"`,
+ FNumber: `"800/100"`,
+ ExposureProgram: `2`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `294`,
+ ExposureTime: `"10/2000"`,
+ ISOSpeedRatings: `64`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"20/10"`,
+ PixelYDimension: `1944`,
+ Model: `"FinePix Z1 "`,
+ ThumbJPEGInterchangeFormatLength: `9900`,
+ ShutterSpeedValue: `"764/100"`,
+ ExposureBiasValue: `"0/100"`,
+ LightSource: `0`,
+ FocalLength: `"610/100"`,
+ ColorSpace: `1`,
+ FocalPlaneXResolution: `"4442/1"`,
+ FileSource: `""`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"FUJIFILM"`,
+ DateTimeOriginal: `"2007:11:07 11:40:44"`,
+ DateTimeDigitized: `"2007:11:07 11:40:44"`,
+ BrightnessValue: `"906/100"`,
+ PixelXDimension: `2592`,
+ InteroperabilityIFDPointer: `1158`,
+ SceneType: `""`,
+ FocalPlaneResolutionUnit: `3`,
+ Sharpness: `0`,
+ SubjectDistanceRange: `0`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `5`,
+ Flash: `16`,
+ FocalPlaneYResolution: `"4442/1"`,
+ },
+ "2008-06-02-10-03-57-sep-2008-06-02-10-03-57a.jpg": map[FieldName]string{
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ FNumber: `"2800/1000"`,
+ CompressedBitsPerPixel: `"5896224/3145728"`,
+ MeteringMode: `4`,
+ MakerNote: `""`,
+ PixelXDimension: `2048`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2008:06:13 06:16:19"`,
+ Copyright: `"Copyright 2006"`,
+ ExposureBiasValue: `"0/10"`,
+ PixelYDimension: `1536`,
+ Model: `"i533"`,
+ XResolution: `"288/3"`,
+ ISOSpeedRatings: `100`,
+ ExifVersion: `"0220"`,
+ Flash: `65`,
+ DigitalZoomRatio: `"100/100"`,
+ Orientation: `1`,
+ ThumbJPEGInterchangeFormatLength: `5972`,
+ ExposureProgram: `7`,
+ MaxApertureValue: `"2970/1000"`,
+ ThumbJPEGInterchangeFormat: `3756`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `226`,
+ ExposureTime: `"10/600"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ Software: `"00.00.1240a"`,
+ DateTime: `"2008:06:13 06:16:19"`,
+ ShutterSpeedValue: `"5907/1000"`,
+ ApertureValue: `"2970/1000"`,
+ LightSource: `4`,
+ FocalLength: `"6200/1000"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"288/3"`,
+ DateTimeOriginal: `"2008:06:02 10:03:57"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `3620`,
+ ExposureMode: `0`,
+ Make: `"Polaroid"`,
+ },
+ "2008-06-06-13-29-29-sep-2008-06-06-13-29-29a.jpg": map[FieldName]string{
+ PixelXDimension: `1600`,
+ InteroperabilityIFDPointer: `3334`,
+ DigitalZoomRatio: `"3072/3072"`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"Canon"`,
+ DateTimeOriginal: `"2008:06:06 13:29:29"`,
+ DateTimeDigitized: `"2008:06:06 13:29:29"`,
+ FocalPlaneResolutionUnit: `2`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `5`,
+ Flash: `16`,
+ FocalPlaneYResolution: `"1200000/169"`,
+ Orientation: `6`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ MaxApertureValue: `"116/32"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `0`,
+ YResolution: `"180/1"`,
+ ThumbJPEGInterchangeFormat: `5108`,
+ ApertureValue: `"116/32"`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ MakerNote: `""`,
+ UserComment: `""`,
+ SensingMethod: `2`,
+ DateTime: `"2008:06:06 13:29:29"`,
+ FNumber: `"35/10"`,
+ ISOSpeedRatings: `80`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"5/1"`,
+ XResolution: `"180/1"`,
+ ExifIFDPointer: `196`,
+ ExposureTime: `"1/320"`,
+ ExposureBiasValue: `"0/3"`,
+ FocalLength: `"8462/1000"`,
+ ColorSpace: `1`,
+ PixelYDimension: `1200`,
+ FocalPlaneXResolution: `"1600000/225"`,
+ Model: `"Canon DIGITAL IXUS 75"`,
+ ThumbJPEGInterchangeFormatLength: `6594`,
+ ShutterSpeedValue: `"266/32"`,
+ FileSource: `""`,
+ },
+ "2008-06-17-01-21-30-sep-2008-06-17-01-21-30a.jpg": map[FieldName]string{
+ MaxApertureValue: `"30/10"`,
+ ThumbJPEGInterchangeFormat: `1041`,
+ ThumbJPEGInterchangeFormatLength: `13506`,
+ ExposureProgram: `2`,
+ ExposureTime: `"10/326"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `253`,
+ LightSource: `0`,
+ FocalLength: `"645/100"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"72/1"`,
+ Software: `"A520_CT019"`,
+ DateTime: `"2008:06:17 01:22:13"`,
+ InteroperabilityIFDPointer: `1011`,
+ Make: `"Polaroid"`,
+ DateTimeOriginal: `"2008:06:17 01:21:30"`,
+ ComponentsConfiguration: `""`,
+ FNumber: `"28/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ UserComment: `""`,
+ PixelXDimension: `2592`,
+ DateTimeDigitized: `"2008:06:17 01:21:30"`,
+ CompressedBitsPerPixel: `"2/1"`,
+ MeteringMode: `2`,
+ PixelYDimension: `1944`,
+ ImageDescription: `"DCFC1247.JPG "`,
+ Model: `"5MP Digital Camera"`,
+ ExposureBiasValue: `"0/10"`,
+ ExifVersion: `"0220"`,
+ Flash: `0`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `100`,
+ },
+ "2008-09-02-17-43-48-sep-2008-09-02-17-43-48a.jpg": map[FieldName]string{
+ ImageDescription: `" "`,
+ Model: `"Z550a"`,
+ YResolution: `"72/1"`,
+ Software: `"R6GA004 prgCXC1250583_GENERIC_M 2.0"`,
+ DateTime: `"2008:09:02 17:43:48"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1024`,
+ Make: `"Sony Ericsson"`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2008:09:02 17:43:48"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `612`,
+ ThumbJPEGInterchangeFormat: `748`,
+ ThumbJPEGInterchangeFormatLength: `4641`,
+ ColorSpace: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `302`,
+ DateTimeDigitized: `"2008:09:02 17:43:48"`,
+ PixelXDimension: `1280`,
+ InteroperabilityIndex: `"R98"`,
+ },
+ "2009-03-26-09-23-20-sep-2009-03-26-09-23-20a.jpg": map[FieldName]string{
+ FocalLength: `"5800/1000"`,
+ ColorSpace: `1`,
+ PixelYDimension: `2304`,
+ FocalPlaneXResolution: `"3072000/225"`,
+ Model: `"Canon PowerShot SD750"`,
+ ThumbJPEGInterchangeFormatLength: `5513`,
+ ShutterSpeedValue: `"287/32"`,
+ ExposureBiasValue: `"0/3"`,
+ FileSource: `""`,
+ InteroperabilityIFDPointer: `3334`,
+ DigitalZoomRatio: `"3072/3072"`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"Canon"`,
+ DateTimeOriginal: `"2009:03:26 09:23:20"`,
+ DateTimeDigitized: `"2009:03:26 09:23:20"`,
+ PixelXDimension: `3072`,
+ FocalPlaneResolutionUnit: `2`,
+ MeteringMode: `5`,
+ Flash: `24`,
+ FocalPlaneYResolution: `"2304000/169"`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifVersion: `"0220"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `0`,
+ YResolution: `"180/1"`,
+ ThumbJPEGInterchangeFormat: `5108`,
+ ApertureValue: `"95/32"`,
+ MaxApertureValue: `"95/32"`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ MakerNote: `""`,
+ UserComment: `""`,
+ SensingMethod: `2`,
+ CustomRendered: `0`,
+ DateTime: `"2009:03:26 09:23:20"`,
+ FNumber: `"28/10"`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"5/1"`,
+ XResolution: `"180/1"`,
+ ExifIFDPointer: `196`,
+ ExposureTime: `"1/500"`,
+ ISOSpeedRatings: `160`,
+ },
+ "2009-04-11-03-01-38-sep-2009-04-11-03-01-38a.jpg": map[FieldName]string{
+ ThumbJPEGInterchangeFormat: `33660`,
+ MaxApertureValue: `"30/10"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `0`,
+ YResolution: `"300/1"`,
+ UserComment: `" "`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ MakerNote: `""`,
+ DateTime: `"2009:04:11 03:01:38"`,
+ FNumber: `"28/10"`,
+ ExposureProgram: `2`,
+ Software: `"COOLPIX L18 V1.1"`,
+ ExifIFDPointer: `230`,
+ ExposureTime: `"1/250"`,
+ ISOSpeedRatings: `227`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"4/1"`,
+ Saturation: `0`,
+ XResolution: `"300/1"`,
+ ThumbJPEGInterchangeFormatLength: `9697`,
+ ExposureBiasValue: `"0/10"`,
+ LightSource: `0`,
+ FocalLength: `"5700/1000"`,
+ ColorSpace: `1`,
+ PixelYDimension: `2448`,
+ FileSource: `""`,
+ Model: `"COOLPIX L18"`,
+ DateTimeOriginal: `"2009:04:11 03:01:38"`,
+ DateTimeDigitized: `"2009:04:11 03:01:38"`,
+ PixelXDimension: `3264`,
+ InteroperabilityIFDPointer: `33536`,
+ SceneType: `""`,
+ DigitalZoomRatio: `"0/100"`,
+ GainControl: `1`,
+ Make: `"NIKON"`,
+ InteroperabilityIndex: `"R98"`,
+ Sharpness: `1`,
+ ImageDescription: `" "`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `5`,
+ Flash: `24`,
+ FocalLengthIn35mmFilm: `35`,
+ SubjectDistanceRange: `0`,
+ Orientation: `1`,
+ },
+ "2009-04-23-07-21-35-sep-2009-04-23-07-21-35a.jpg": map[FieldName]string{
+ Sharpness: `0`,
+ MeteringMode: `5`,
+ Flash: `9`,
+ FocalLengthIn35mmFilm: `35`,
+ SubjectDistanceRange: `3`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifVersion: `"0220"`,
+ WhiteBalance: `0`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormat: `31176`,
+ MaxApertureValue: `"28/10"`,
+ FlashpixVersion: `"0100"`,
+ Contrast: `0`,
+ MakerNote: `""`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Software: `"Optio S50 Ver 1.00"`,
+ DateTime: `"2009:04:23 07:21:35"`,
+ FNumber: `"26/10"`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"13301888/4915200"`,
+ Saturation: `0`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `590`,
+ ExposureTime: `"1/40"`,
+ ISOSpeedRatings: `100`,
+ ColorSpace: `1`,
+ PixelYDimension: `1920`,
+ Model: `"PENTAX Optio S50"`,
+ ThumbJPEGInterchangeFormatLength: `6015`,
+ ExposureBiasValue: `"0/10"`,
+ FocalLength: `"58/10"`,
+ InteroperabilityIFDPointer: `31040`,
+ DigitalZoomRatio: `"0/100"`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"PENTAX Corporation"`,
+ DateTimeOriginal: `"2009:04:23 07:21:35"`,
+ DateTimeDigitized: `"2009:04:23 07:21:35"`,
+ PixelXDimension: `2560`,
+ },
+ "2009-06-11-19-23-18-sep-2009-06-11-19-23-18a.jpg": map[FieldName]string{
+ ThumbJPEGInterchangeFormat: `606`,
+ ThumbJPEGInterchangeFormatLength: `7150`,
+ ExposureProgram: `1`,
+ ColorSpace: `65535`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `264`,
+ ExposureTime: `"1/4"`,
+ DateTimeDigitized: `"2009:06:11 19:23:18"`,
+ MeteringMode: `1`,
+ PixelXDimension: `1400`,
+ PixelYDimension: `2100`,
+ Model: `"Canon EOS DIGITAL REBEL XTi"`,
+ YResolution: `"3500000/10000"`,
+ Software: `"Adobe Photoshop CS3 Macintosh"`,
+ DateTime: `"2009:06:23 18:42:05"`,
+ ApertureValue: `"11257/1627"`,
+ ExposureBiasValue: `"0/1"`,
+ FocalLength: `"47/1"`,
+ Make: `"Canon"`,
+ Orientation: `1`,
+ XResolution: `"3500000/10000"`,
+ ISOSpeedRatings: `200`,
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2009:06:11 19:23:18"`,
+ Flash: `16`,
+ },
+ "2009-06-20-07-59-05-sep-2009-06-20-07-59-05a.jpg": map[FieldName]string{
+ DateTimeOriginal: `"2009:06:20 07:59:05"`,
+ Flash: `89`,
+ ExposureMode: `0`,
+ ExifVersion: `"0221"`,
+ ThumbJPEGInterchangeFormatLength: `4569`,
+ MaxApertureValue: `"36/10"`,
+ ColorSpace: `1`,
+ ExposureIndex: `"160/1"`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ThumbJPEGInterchangeFormat: `9032`,
+ ExposureTime: `"1/500"`,
+ MeteringMode: `5`,
+ GainControl: `2`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ InteroperabilityIndex: `"R98"`,
+ ExifIFDPointer: `514`,
+ ShutterSpeedValue: `"9/1"`,
+ Model: `"KODAK EASYSHARE Z710 ZOOM DIGITAL CAMERA"`,
+ Orientation: `1`,
+ XResolution: `"480/1"`,
+ ISOSpeedRatings: `160`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `8728`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/100"`,
+ Make: `"EASTMAN KODAK COMPANY"`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ FocalLengthIn35mmFilm: `337`,
+ ExposureProgram: `2`,
+ FileSource: `""`,
+ FNumber: `"35/10"`,
+ YCbCrPositioning: `1`,
+ DateTimeDigitized: `"2009:06:20 07:59:05"`,
+ MakerNote: `""`,
+ PixelXDimension: `3072`,
+ SensingMethod: `2`,
+ SceneType: `""`,
+ ResolutionUnit: `2`,
+ ApertureValue: `"36/10"`,
+ ExposureBiasValue: `"0/3"`,
+ LightSource: `0`,
+ FocalLength: `"559/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `2304`,
+ YResolution: `"480/1"`,
+ },
+ "2009-08-05-08-11-31-sep-2009-08-05-08-11-31a.jpg": map[FieldName]string{
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `100`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `1158`,
+ FocalPlaneYResolution: `"5292/1"`,
+ CustomRendered: `0`,
+ Make: `"FUJIFILM"`,
+ Orientation: `1`,
+ SceneCaptureType: `0`,
+ FileSource: `""`,
+ FNumber: `"400/100"`,
+ ExposureProgram: `2`,
+ DateTimeDigitized: `"2009:08:05 08:11:31"`,
+ MakerNote: `"FUJIFILM0130" !"#,012NORMAL d"`,
+ PixelXDimension: `2848`,
+ SensingMethod: `2`,
+ SceneType: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ Copyright: `" "`,
+ ApertureValue: `"400/100"`,
+ ExposureBiasValue: `"0/100"`,
+ LightSource: `0`,
+ FocalLength: `"720/100"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"72/1"`,
+ DateTime: `"2009:08:05 08:11:31"`,
+ PixelYDimension: `2136`,
+ FocalPlaneXResolution: `"5292/1"`,
+ Flash: `16`,
+ ExposureMode: `0`,
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2009:08:05 08:11:31"`,
+ MaxApertureValue: `"300/100"`,
+ ColorSpace: `1`,
+ WhiteBalance: `1`,
+ Sharpness: `0`,
+ ThumbJPEGInterchangeFormat: `1306`,
+ ThumbJPEGInterchangeFormatLength: `8596`,
+ CompressedBitsPerPixel: `"20/10"`,
+ BrightnessValue: `"719/100"`,
+ MeteringMode: `5`,
+ SubjectDistanceRange: `0`,
+ InteroperabilityIndex: `"R98"`,
+ ExifIFDPointer: `294`,
+ ExposureTime: `"10/3000"`,
+ ShutterSpeedValue: `"820/100"`,
+ FocalPlaneResolutionUnit: `3`,
+ Model: `"FinePix E550 "`,
+ Software: `"Digital Camera FinePix E550 Ver1.00"`,
+ },
+ "2010-06-08-04-44-24-sep-2010-06-08-04-44-24a.jpg": map[FieldName]string{
+ CompressedBitsPerPixel: `"8/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ PixelXDimension: `2816`,
+ Saturation: `0`,
+ DateTimeDigitized: `"2010:06:08 04:44:24"`,
+ Model: `"DSC-S600"`,
+ ExposureBiasValue: `"0/10"`,
+ PixelYDimension: `2112`,
+ ImageDescription: `" "`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `80`,
+ ExifVersion: `"0221"`,
+ Flash: `31`,
+ CustomRendered: `0`,
+ Orientation: `1`,
+ ThumbJPEGInterchangeFormatLength: `4029`,
+ ExposureProgram: `2`,
+ MaxApertureValue: `"48/16"`,
+ ThumbJPEGInterchangeFormat: `6892`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `2314`,
+ ExposureTime: `"10/400"`,
+ SceneType: `""`,
+ ResolutionUnit: `2`,
+ DateTime: `"2010:06:08 04:44:24"`,
+ LightSource: `0`,
+ FocalLength: `"51/10"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"72/1"`,
+ DateTimeOriginal: `"2010:06:08 04:44:24"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `6640`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ Make: `"SONY"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ FNumber: `"28/10"`,
+ },
+ "2010-06-20-20-07-39-sep-2010-06-20-20-07-39a.jpg": map[FieldName]string{
+ FocalPlaneYResolution: `"2736000/181"`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"3648/3648"`,
+ Orientation: `1`,
+ XResolution: `"4718592/65536"`,
+ ISOSpeedRatings: `800`,
+ ExifVersion: `"0220"`,
+ Flash: `16`,
+ ThumbJPEGInterchangeFormat: `3408`,
+ ThumbJPEGInterchangeFormatLength: `5126`,
+ MaxApertureValue: `"116/32"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `302`,
+ ExposureTime: `"1/10"`,
+ FocalLength: `"9681/1000"`,
+ FlashpixVersion: `"0100"`,
+ FocalPlaneXResolution: `"3648000/241"`,
+ YResolution: `"4718592/65536"`,
+ Software: `"QuickTime 7.6.6"`,
+ DateTime: `"2010:10:31 22:39:25"`,
+ ShutterSpeedValue: `"106/32"`,
+ ApertureValue: `"116/32"`,
+ Make: `"Canon"`,
+ DateTimeOriginal: `"2010:06:20 20:07:39"`,
+ ComponentsConfiguration: `""`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ FNumber: `"35/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ PixelXDimension: `3648`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2010:06:20 20:07:39"`,
+ CompressedBitsPerPixel: `"3/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ UserComment: `""`,
+ ImageDescription: `" "`,
+ Model: `"Canon PowerShot SD1200 IS"`,
+ ExposureBiasValue: `"0/3"`,
+ PixelYDimension: `2736`,
+ FocalPlaneResolutionUnit: `2`,
+ },
+ "2010-09-02-08-43-02-sep-2010-09-02-08-43-02a.jpg": map[FieldName]string{
+ DateTime: `"2010:09:02 08:43:02"`,
+ ExposureProgram: `5`,
+ ExifVersion: `"0221"`,
+ CompressedBitsPerPixel: `"1/1"`,
+ Flash: `65`,
+ Saturation: `0`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `800`,
+ MaxApertureValue: `"362/100"`,
+ LightSource: `0`,
+ FocalLength: `"210/10"`,
+ ColorSpace: `1`,
+ Model: `"FE370,X880,C575 "`,
+ ThumbJPEGInterchangeFormat: `9204`,
+ SceneType: `""`,
+ DigitalZoomRatio: `"0/100"`,
+ SceneCaptureType: `3`,
+ GainControl: `2`,
+ Contrast: `0`,
+ DateTimeOriginal: `"2010:09:02 08:43:02"`,
+ MakerNote: `""`,
+ FNumber: `"53/10"`,
+ Sharpness: `0`,
+ ImageDescription: `"OLYMPUS DIGITAL CAMERA "`,
+ Software: `"Version 1.0 "`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `996`,
+ ExposureTime: `"10/500"`,
+ ComponentsConfiguration: `""`,
+ MeteringMode: `5`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ ExposureBiasValue: `"0/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `2448`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormatLength: `3562`,
+ UserComment: `" "`,
+ PixelXDimension: `3264`,
+ InteroperabilityIFDPointer: `1714`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"OLYMPUS IMAGING CORP. "`,
+ DateTimeDigitized: `"2010:09:02 08:43:02"`,
+ },
+ "2011-01-24-22-06-02-sep-2011-01-24-22-06-02a.jpg": map[FieldName]string{
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ ThumbJPEGInterchangeFormat: `25601`,
+ ThumbJPEGInterchangeFormatLength: `3385`,
+ ExifIFDPointer: `157`,
+ PixelXDimension: `1200`,
+ MakerNote: `""`,
+ DateTimeDigitized: `"2011:01:24 22:06:02"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ Software: `"V 12.40"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1600`,
+ Model: `"6350"`,
+ YResolution: `"300/1"`,
+ XResolution: `"300/1"`,
+ ExifVersion: `"0220"`,
+ ComponentsConfiguration: `""`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Make: `"Nokia"`,
+ Orientation: `1`,
+ DigitalZoomRatio: `"1024/1024"`,
+ DateTimeOriginal: `"2011:01:24 22:06:02"`,
+ },
+ "2011-03-07-09-28-03-sep-2011-03-07-09-28-03a.jpg": map[FieldName]string{
+ Model: `"GU295"`,
+ Software: `"GU295-MSM1530032L-V10i-APR-22-2010-ATT-US"`,
+ Make: `"LG Elec."`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `538`,
+ CustomRendered: `1`,
+ DigitalZoomRatio: `"0/0"`,
+ Contrast: `0`,
+ ExposureProgram: `2`,
+ FileSource: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ DateTimeDigitized: `"2011:03:07 09:28:03"`,
+ PixelXDimension: `1280`,
+ SceneType: `""`,
+ YResolution: `"72/1"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `960`,
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2011:03:07 09:28:03"`,
+ ExposureMode: `0`,
+ ThumbJPEGInterchangeFormat: `662`,
+ ThumbJPEGInterchangeFormatLength: `9850`,
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ExifIFDPointer: `224`,
+ BrightnessValue: `"0/1024"`,
+ MeteringMode: `2`,
+ Saturation: `0`,
+ InteroperabilityIndex: `"R98"`,
+ },
+ "2011-05-07-13-02-49-sep-2011-05-07-13-02-49a.jpg": map[FieldName]string{
+ DateTimeOriginal: `"2011:05:07 13:02:49"`,
+ SceneType: `""`,
+ Contrast: `0`,
+ Software: `"M7500BSAAAAAAD3050"`,
+ GPSVersionID: `[2,2,0,0]`,
+ GPSLatitudeRef: `"N"`,
+ GPSAltitude: `"0/1"`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `218`,
+ GPSInfoIFDPointer: `502`,
+ ComponentsConfiguration: `""`,
+ GPSLongitudeRef: `"E"`,
+ GPSTimeStamp: `["19/1","3/1","43/1"]`,
+ GPSDateStamp: `"2011:05:07 "`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormatLength: `22806`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1536`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ GPSAltitudeRef: `0`,
+ Make: `"HTC"`,
+ DateTimeDigitized: `"2011:05:07 13:02:49"`,
+ PixelXDimension: `2048`,
+ InteroperabilityIFDPointer: `472`,
+ GPSLatitude: `["0/1","0/1","0/100"]`,
+ InteroperabilityIndex: `"R98"`,
+ GPSLongitude: `["0/1","0/1","0/100"]`,
+ XResolution: `"72/1"`,
+ ExifVersion: `"0220"`,
+ GPSProcessingMethod: `"ASCIIHYBRID-FIX"`,
+ Model: `"RAPH800"`,
+ ThumbJPEGInterchangeFormat: `920`,
+ ColorSpace: `1`,
+ GPSMapDatum: `"WGS-84"`,
+ },
+ "2011-08-07-19-22-57-sep-2011-08-07-19-22-57a.jpg": map[FieldName]string{
+ ResolutionUnit: `2`,
+ DateTimeDigitized: `"2011:08:07 19:22:57"`,
+ SensingMethod: `2`,
+ SceneType: `""`,
+ YResolution: `"300/1"`,
+ DateTime: `"2011:08:11 09:46:32"`,
+ ApertureValue: `"433985/100000"`,
+ ExposureBiasValue: `"2/6"`,
+ LightSource: `0`,
+ FocalLength: `"620/10"`,
+ ExifVersion: `"0221"`,
+ DateTimeOriginal: `"2011:08:07 19:22:57"`,
+ Flash: `7`,
+ ExposureMode: `0`,
+ ThumbJPEGInterchangeFormat: `802`,
+ ThumbJPEGInterchangeFormatLength: `9117`,
+ MaxApertureValue: `"43/10"`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ExifIFDPointer: `186`,
+ ExposureTime: `"1/30"`,
+ MeteringMode: `2`,
+ GainControl: `1`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ Model: `"NIKON D200"`,
+ Software: `"Ver.1.00"`,
+ ShutterSpeedValue: `"4906891/1000000"`,
+ SubSecTimeOriginal: `"65"`,
+ SubSecTimeDigitized: `"65"`,
+ FocalLengthIn35mmFilm: `93`,
+ SceneCaptureType: `0`,
+ Make: `"NIKON CORPORATION"`,
+ XResolution: `"300/1"`,
+ ISOSpeedRatings: `400`,
+ CFAPattern: `""`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"1/1"`,
+ Contrast: `0`,
+ FNumber: `"45/10"`,
+ ExposureProgram: `3`,
+ SubjectDistance: `"63/100"`,
+ FileSource: `""`,
+ },
+ "2011-10-28-17-50-18-sep-2011-10-28-17-50-18a.jpg": map[FieldName]string{
+ SubSecTime: `"92"`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ UserComment: `""`,
+ DateTime: `"2011:11:08 07:27:55"`,
+ FNumber: `"4/1"`,
+ ExposureProgram: `2`,
+ SubSecTimeOriginal: `"92"`,
+ GPSVersionID: `[2,2,0,0]`,
+ Software: `"Adobe Photoshop CS4 Macintosh"`,
+ ExifIFDPointer: `364`,
+ ExposureTime: `"1/60"`,
+ ISOSpeedRatings: `800`,
+ ComponentsConfiguration: `""`,
+ XResolution: `"720000/10000"`,
+ ThumbJPEGInterchangeFormatLength: `6186`,
+ ShutterSpeedValue: `"393216/65536"`,
+ ExposureBiasValue: `"0/1"`,
+ FocalLength: `"34/1"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `864`,
+ FocalPlaneXResolution: `"5616000/1459"`,
+ Model: `"Canon EOS 5D Mark II"`,
+ DateTimeOriginal: `"2011:10:28 17:50:18"`,
+ DateTimeDigitized: `"2011:10:28 17:50:18"`,
+ PixelXDimension: `576`,
+ InteroperabilityIFDPointer: `1120`,
+ InteroperabilityIndex: `"R03"`,
+ Make: `"Canon"`,
+ FocalPlaneResolutionUnit: `2`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ GPSInfoIFDPointer: `1152`,
+ ExifVersion: `"0221"`,
+ MeteringMode: `5`,
+ Flash: `9`,
+ FocalPlaneYResolution: `"3744000/958"`,
+ Orientation: `1`,
+ ThumbJPEGInterchangeFormat: `1266`,
+ ApertureValue: `"262144/65536"`,
+ SubSecTimeDigitized: `"92"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `1`,
+ YResolution: `"720000/10000"`,
+ },
+ "2011-10-28-18-25-43-sep-2011-10-28-18-25-43.jpg": map[FieldName]string{
+ SubSecTimeOriginal: `"50"`,
+ DateTime: `"2011:10:28 18:25:43"`,
+ ISOSpeedRatings: `1250`,
+ ComponentsConfiguration: `""`,
+ Saturation: `0`,
+ XResolution: `"300/1"`,
+ ExposureTime: `"10/600"`,
+ ColorSpace: `1`,
+ ThumbJPEGInterchangeFormatLength: `3670`,
+ LightSource: `0`,
+ FocalLength: `"800/10"`,
+ CFAPattern: `""`,
+ DigitalZoomRatio: `"1/1"`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"NIKON CORPORATION"`,
+ DateTimeOriginal: `"2011:10:28 18:25:43"`,
+ InteroperabilityIFDPointer: `3604`,
+ Sharpness: `0`,
+ ExifVersion: `"0221"`,
+ MeteringMode: `5`,
+ Flash: `31`,
+ FocalLengthIn35mmFilm: `120`,
+ Orientation: `1`,
+ YCbCrPositioning: `2`,
+ SubSecTimeDigitized: `"50"`,
+ WhiteBalance: `0`,
+ ThumbJPEGInterchangeFormat: `3728`,
+ SensingMethod: `2`,
+ CustomRendered: `0`,
+ SubSecTime: `"50"`,
+ ExposureProgram: `0`,
+ Software: `"Ver.1.11 "`,
+ FNumber: `"56/10"`,
+ CompressedBitsPerPixel: `"2/1"`,
+ ExifIFDPointer: `208`,
+ FileSource: `""`,
+ Model: `"NIKON D80"`,
+ ExposureBiasValue: `"0/6"`,
+ PixelYDimension: `537`,
+ GainControl: `2`,
+ DateTimeDigitized: `"2011:10:28 18:25:43"`,
+ PixelXDimension: `800`,
+ SceneType: `""`,
+ ImageUniqueID: `"7fa4f6d028df5f2fc1bad8102be81064"`,
+ SubjectDistanceRange: `0`,
+ ResolutionUnit: `2`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"300/1"`,
+ MaxApertureValue: `"50/10"`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ MakerNote: `""`,
+ UserComment: `"ASCII "`,
+ },
+ "2011-11-18-15-38-34-sep-Photo11181538.jpg": map[FieldName]string{
+ WhiteBalance: `0`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormat: `642`,
+ FlashpixVersion: `"0100"`,
+ CustomRendered: `1`,
+ ExposureMode: `0`,
+ Contrast: `1`,
+ Software: `"M6290A-KPVMZL-2.6.0140T"`,
+ ExposureProgram: `2`,
+ Saturation: `0`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `204`,
+ ComponentsConfiguration: `""`,
+ PixelYDimension: `1200`,
+ FileSource: `""`,
+ Model: `"P2020"`,
+ ThumbJPEGInterchangeFormatLength: `12226`,
+ ColorSpace: `1`,
+ BrightnessValue: `"0/1024"`,
+ PixelXDimension: `1600`,
+ InteroperabilityIFDPointer: `518`,
+ SceneType: `""`,
+ DigitalZoomRatio: `"0/0"`,
+ Make: `"PANTECH"`,
+ DateTimeOriginal: `"2011:11:18 15:38:34"`,
+ DateTimeDigitized: `"2011:11:18 15:38:34"`,
+ InteroperabilityIndex: `"R98"`,
+ Sharpness: `0`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `2`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ },
+ "2012-06-02-10-12-28-sep-2012-06-02-10-12-28.jpg": map[FieldName]string{
+ YResolution: `"180/1"`,
+ Software: `"Ver.1.0 "`,
+ DateTime: `"2012:06:02 10:12:28"`,
+ LightSource: `0`,
+ FocalLength: `"50/10"`,
+ FlashpixVersion: `"0100"`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ Make: `"Panasonic"`,
+ DateTimeOriginal: `"2012:06:02 10:12:28"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `10506`,
+ ExposureMode: `0`,
+ FocalLengthIn35mmFilm: `28`,
+ FNumber: `"33/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ GainControl: `0`,
+ Saturation: `0`,
+ DateTimeDigitized: `"2012:06:02 10:12:28"`,
+ CompressedBitsPerPixel: `"4/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ PixelXDimension: `4608`,
+ SensingMethod: `2`,
+ Model: `"DMC-FH25"`,
+ ExposureBiasValue: `"0/100"`,
+ PixelYDimension: `3456`,
+ DigitalZoomRatio: `"0/10"`,
+ Orientation: `1`,
+ XResolution: `"180/1"`,
+ ISOSpeedRatings: `100`,
+ ExifVersion: `"0230"`,
+ Flash: `16`,
+ CustomRendered: `0`,
+ ThumbJPEGInterchangeFormat: `11764`,
+ ThumbJPEGInterchangeFormatLength: `7486`,
+ ExposureProgram: `2`,
+ MaxApertureValue: `"441/128"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `636`,
+ ExposureTime: `"10/4000"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ },
+ "2012-09-21-22-07-34-sep-2012-09-21-22-07-34.jpg": map[FieldName]string{
+ ThumbJPEGInterchangeFormat: `5108`,
+ ThumbJPEGInterchangeFormatLength: `4855`,
+ MaxApertureValue: `"95/32"`,
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ ExifIFDPointer: `240`,
+ ExposureTime: `"1/60"`,
+ CompressedBitsPerPixel: `"3/1"`,
+ MeteringMode: `5`,
+ UserComment: `""`,
+ InteroperabilityIndex: `"R98"`,
+ ImageDescription: `" "`,
+ Model: `"Canon PowerShot SD940 IS"`,
+ ShutterSpeedValue: `"189/32"`,
+ FocalPlaneResolutionUnit: `2`,
+ CustomRendered: `0`,
+ Make: `"Canon"`,
+ Orientation: `1`,
+ XResolution: `"180/1"`,
+ ISOSpeedRatings: `500`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `3288`,
+ FocalPlaneYResolution: `"2448000/183"`,
+ DigitalZoomRatio: `"4000/4000"`,
+ SceneCaptureType: `2`,
+ FNumber: `"28/10"`,
+ FileSource: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ DateTimeDigitized: `"2012:09:21 22:07:34"`,
+ MakerNote: `""`,
+ PixelXDimension: `3264`,
+ SensingMethod: `2`,
+ FocalPlaneXResolution: `"3264000/244"`,
+ YResolution: `"180/1"`,
+ DateTime: `"2012:09:21 22:07:34"`,
+ ApertureValue: `"95/32"`,
+ ExposureBiasValue: `"0/3"`,
+ FocalLength: `"5000/1000"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `2448`,
+ ExifVersion: `"0221"`,
+ DateTimeOriginal: `"2012:09:21 22:07:34"`,
+ Flash: `25`,
+ ExposureMode: `0`,
+ },
+ "2012-12-19-21-38-40-sep-temple_square1.jpg": map[FieldName]string{
+ InteroperabilityIFDPointer: `322`,
+ GPSLatitude: `["40/1","46/1","1322/100"]`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"HTC"`,
+ DateTimeOriginal: `"2012:12:19 21:38:40"`,
+ DateTimeDigitized: `"2012:12:19 21:38:40"`,
+ PixelXDimension: `3264`,
+ GPSLatitudeRef: `"N"`,
+ GPSLongitude: `["111/1","53/1","2840/100"]`,
+ GPSLongitudeRef: `"W"`,
+ GPSProcessingMethod: `"ASCIIGPS"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ GPSInfoIFDPointer: `352`,
+ ExifVersion: `"0220"`,
+ GPSMapDatum: `"WGS-84"`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormat: `696`,
+ FlashpixVersion: `"0100"`,
+ GPSAltitudeRef: `0`,
+ GPSVersionID: `[2,2,0]`,
+ GPSAltitude: `"1334/1"`,
+ GPSTimeStamp: `["4/1","38/1","40/1"]`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `136`,
+ ISOSpeedRatings: `801`,
+ ComponentsConfiguration: `""`,
+ PixelYDimension: `1952`,
+ GPSDateStamp: `"2012:12:20"`,
+ Model: `"ADR6400L"`,
+ ThumbJPEGInterchangeFormatLength: `38469`,
+ FocalLength: `"457/100"`,
+ ColorSpace: `1`,
+ },
+ "2012-12-21-11-15-19-sep-IMG_0001.jpg": map[FieldName]string{
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `360`,
+ ExposureTime: `"1/30"`,
+ InteroperabilityIndex: `"R98"`,
+ SubSecTimeDigitized: `"00"`,
+ FlashpixVersion: `"0100"`,
+ FocalPlaneXResolution: `"5184000/894"`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:12:21 11:15:19"`,
+ ShutterSpeedValue: `"327680/65536"`,
+ ApertureValue: `"286720/65536"`,
+ FocalLength: `"24/1"`,
+ LensModel: `"EF-S18-55mm f/3.5-5.6 IS II"`,
+ GPSVersionID: `[2,3,0,0]`,
+ InteroperabilityIFDPointer: `8806`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Make: `"Canon"`,
+ GPSInfoIFDPointer: `9034`,
+ DateTimeOriginal: `"2012:12:21 11:15:19"`,
+ ComponentsConfiguration: `""`,
+ SubSecTime: `"00"`,
+ Artist: `""`,
+ FNumber: `"45/10"`,
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ DateTimeDigitized: `"2012:12:21 11:15:19"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ UserComment: `""`,
+ PixelXDimension: `5184`,
+ FocalPlaneResolutionUnit: `2`,
+ Model: `"Canon EOS REBEL T4i"`,
+ Copyright: `""`,
+ ExposureBiasValue: `"0/1"`,
+ SubSecTimeOriginal: `"00"`,
+ PixelYDimension: `3456`,
+ FocalPlaneYResolution: `"3456000/597"`,
+ CustomRendered: `0`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `1600`,
+ ExifVersion: `"0230"`,
+ Flash: `16`,
+ ThumbJPEGInterchangeFormat: `10924`,
+ ThumbJPEGInterchangeFormatLength: `14327`,
+ ExposureProgram: `0`,
+ },
+ "2013-02-05-23-12-09-sep-DSCI0001.jpg": map[FieldName]string{
+ ApertureValue: `"3072/1000"`,
+ ExposureBiasValue: `"0/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1200`,
+ FileSource: `""`,
+ YResolution: `"288/3"`,
+ ThumbJPEGInterchangeFormatLength: `5863`,
+ ShutterSpeedValue: `"5907/1000"`,
+ WhiteBalance: `0`,
+ InteroperabilityIFDPointer: `4838`,
+ ExposureMode: `0`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"Polaroid"`,
+ DateTimeDigitized: `"2013:02:05 23:12:09"`,
+ PixelXDimension: `1600`,
+ DateTime: `"2013:02:05 23:12:09"`,
+ ExposureProgram: `2`,
+ CompressedBitsPerPixel: `"3766184/1920000"`,
+ Flash: `1`,
+ FocalLengthIn35mmFilm: `35`,
+ XResolution: `"288/3"`,
+ ISOSpeedRatings: `100`,
+ ExifVersion: `"0210"`,
+ MaxApertureValue: `"3072/1000"`,
+ LightSource: `0`,
+ FocalLength: `"5954/1000"`,
+ ColorSpace: `1`,
+ Model: `"Polaroid i532"`,
+ Copyright: `"Copyright 2005"`,
+ ThumbJPEGInterchangeFormat: `4974`,
+ SceneType: `""`,
+ DigitalZoomRatio: `"100/100"`,
+ SceneCaptureType: `0`,
+ DateTimeOriginal: `"2013:02:05 23:12:09"`,
+ MakerNote: `" BARCODE:A265KS008000; ZP:812; FP:124; AWB:235,679; PWB:476,304; PMF:12,11610; LV:493; LUM:3-8-9-8-1-11;20;26;19;10;A:1,F1:6,F2:18;ET:145, W:2, F:3 ;FV: 41FV: 36FV: 43FV: 223FV: 258FV: 9FV: 466FV: 216FP: 10FP: 8FP: 6FP: 6FP: 6FP: 0FP: 8FP: 8AFS: 110"`,
+ SensingMethod: `2`,
+ Sharpness: `0`,
+ ImageDescription: `""`,
+ Software: `" 1.0"`,
+ FNumber: `"28/10"`,
+ ExifIFDPointer: `240`,
+ ExposureTime: `"1/60"`,
+ ComponentsConfiguration: `""`,
+ MeteringMode: `3`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ },
+ "2099-08-12-19-59-29-sep-2099-08-12-19-59-29a.jpg": map[FieldName]string{
+ Model: `"NIKON D70s"`,
+ ExposureBiasValue: `"0/6"`,
+ SubSecTimeOriginal: `"00"`,
+ PixelYDimension: `2000`,
+ CFAPattern: `""`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"1/1"`,
+ Orientation: `1`,
+ XResolution: `"300/1"`,
+ ExifVersion: `"0221"`,
+ Flash: `31`,
+ ThumbJPEGInterchangeFormat: `28588`,
+ ThumbJPEGInterchangeFormatLength: `8886`,
+ ExposureProgram: `0`,
+ MaxApertureValue: `"36/10"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `216`,
+ ExposureTime: `"10/600"`,
+ FocalLength: `"180/10"`,
+ SubSecTimeDigitized: `"00"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"300/1"`,
+ Software: `"Ver.1.00 "`,
+ DateTime: `"2099:08:12 19:59:29"`,
+ LightSource: `0`,
+ InteroperabilityIFDPointer: `28448`,
+ ExposureMode: `0`,
+ FocalLengthIn35mmFilm: `27`,
+ SceneCaptureType: `0`,
+ Make: `"NIKON CORPORATION"`,
+ DateTimeOriginal: `"2099:08:12 19:59:29"`,
+ ComponentsConfiguration: `""`,
+ SubSecTime: `"00"`,
+ Contrast: `1`,
+ Sharpness: `0`,
+ FNumber: `"35/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ UserComment: `"ASCII "`,
+ PixelXDimension: `3008`,
+ SensingMethod: `2`,
+ GainControl: `0`,
+ DateTimeDigitized: `"2099:08:12 19:59:29"`,
+ CompressedBitsPerPixel: `"2/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ },
+ "2216-11-15-11-46-51-sep-2216-11-15-11-46-51a.jpg": map[FieldName]string{
+ ExposureProgram: `2`,
+ FileSource: `""`,
+ FNumber: `"480/100"`,
+ YCbCrPositioning: `2`,
+ DateTimeDigitized: `"2216:11:15 11:46:51"`,
+ MakerNote: `""`,
+ PixelXDimension: `3296`,
+ SensingMethod: `2`,
+ SceneType: `""`,
+ ResolutionUnit: `2`,
+ ApertureValue: `"452/100"`,
+ ExposureBiasValue: `"0/10"`,
+ LightSource: `0`,
+ FocalLength: `"60/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `2472`,
+ YResolution: `"480/1"`,
+ DateTimeOriginal: `"2216:11:15 11:46:51"`,
+ Flash: `24`,
+ ExposureMode: `0`,
+ ExifVersion: `"0221"`,
+ ThumbJPEGInterchangeFormatLength: `5175`,
+ MaxApertureValue: `"286/100"`,
+ ColorSpace: `1`,
+ ExposureIndex: `"80/1"`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ThumbJPEGInterchangeFormat: `17818`,
+ ExposureTime: `"1016/1000000"`,
+ MeteringMode: `5`,
+ GainControl: `0`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ ExifIFDPointer: `2316`,
+ Software: `"KODAK EASYSHARE C813 ZOOM DIGITAL CAMERA"`,
+ ShutterSpeedValue: `"994/100"`,
+ Model: `"KODAK EASYSHARE C813 ZOOM DIGITAL CAMERA"`,
+ Orientation: `1`,
+ XResolution: `"480/1"`,
+ ISOSpeedRatings: `80`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `17674`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/10"`,
+ Make: `"EASTMAN KODAK COMPANY"`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ FocalLengthIn35mmFilm: `36`,
+ },
+ "FailedHash-NoDate-sep-remembory.jpg": map[FieldName]string{
+ Model: `"MFC-7840W"`,
+ YResolution: `"150/1"`,
+ Software: `"Apple Image Capture"`,
+ PixelYDimension: `1626`,
+ ExifIFDPointer: `192`,
+ PixelXDimension: `1232`,
+ Make: `"Brother"`,
+ Orientation: `1`,
+ XResolution: `"150/1"`,
+ ResolutionUnit: `2`,
+ },
+ "f1-exif.jpg": map[FieldName]string{
+ PixelXDimension: `0`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `134`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:02"`,
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `0`,
+ },
+ "f2-exif.jpg": map[FieldName]string{
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `0`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `134`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `2`,
+ XResolution: `"72/1"`,
+ },
+ "f3-exif.jpg": map[FieldName]string{
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `0`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `134`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `3`,
+ XResolution: `"72/1"`,
+ },
+ "f4-exif.jpg": map[FieldName]string{
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `4`,
+ XResolution: `"72/1"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `134`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `0`,
+ },
+ "f5-exif.jpg": map[FieldName]string{
+ ExifIFDPointer: `134`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `5`,
+ XResolution: `"72/1"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ PixelYDimension: `0`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ },
+ "f6-exif.jpg": map[FieldName]string{
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `0`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `6`,
+ XResolution: `"72/1"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `134`,
+ },
+ "f7-exif.jpg": map[FieldName]string{
+ ExifIFDPointer: `134`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `7`,
+ XResolution: `"72/1"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ PixelYDimension: `0`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ },
+ "f8-exif.jpg": map[FieldName]string{
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `134`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `8`,
+ XResolution: `"72/1"`,
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `0`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ },
+ "geodegrees_as_string.jpg": map[FieldName]string{
+ GPSAltitudeRef: `0`,
+ ThumbJPEGInterchangeFormat: `539`,
+ ThumbJPEGInterchangeFormatLength: `13132`,
+ WhiteBalance: `0`,
+ ExposureProgram: `0`,
+ Sharpness: `2`,
+ ExifIFDPointer: `114`,
+ ExposureTime: `"0/1024"`,
+ Saturation: `0`,
+ GPSLatitude: `"52,00000,50,00000,34,01180"`,
+ GPSTimeStamp: `"17,00000,8,00000,29,00000"`,
+ Model: `"HTC One_M8"`,
+ ApertureValue: `"2048/1024"`,
+ FocalLength: `"3072/1024"`,
+ GPSLatitudeRef: `"N"`,
+ GPSLongitude: `"11,00000,10,00000,58,28360"`,
+ GPSAltitude: `"0/1024"`,
+ GPSLongitudeRef: `"E"`,
+ GPSProcessingMethod: `"ASCII"`,
+ GPSInfoIFDPointer: `317`,
+ Make: `"HTC"`,
+ DateTimeOriginal: `"2014:04:26 19:09:19"`,
+ ISOSpeedRatings: `125`,
+ Contrast: `0`,
+ },
+ "has-lens-info.jpg": map[FieldName]string{
+ LensModel: `"iPhone 4S back camera 4.28mm f/2.4"`,
+ Model: `"iPhone 4S"`,
+ ThumbJPEGInterchangeFormatLength: `10875`,
+ ShutterSpeedValue: `"106906/10353"`,
+ FocalLength: `"107/25"`,
+ SubjectArea: `[1631,1223,881,881]`,
+ ColorSpace: `1`,
+ PixelYDimension: `2448`,
+ GPSLatitude: `["59/1","19/1","5717/100"]`,
+ Make: `"Apple"`,
+ DateTimeOriginal: `"2014:09:01 15:03:47"`,
+ DateTimeDigitized: `"2014:09:01 15:03:47"`,
+ BrightnessValue: `"3927/419"`,
+ PixelXDimension: `3264`,
+ SceneType: `""`,
+ LensMake: `"Apple"`,
+ GPSLatitudeRef: `"N"`,
+ GPSLongitude: `["18/1","3/1","5379/100"]`,
+ FocalLengthIn35mmFilm: `35`,
+ Orientation: `6`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ GPSInfoIFDPointer: `948`,
+ ExifVersion: `"0221"`,
+ MeteringMode: `5`,
+ Flash: `16`,
+ GPSLongitudeRef: `"E"`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormat: `1244`,
+ ApertureValue: `"4845/1918"`,
+ SubSecTimeDigitized: `"880"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `0`,
+ GPSAltitudeRef: `0`,
+ MakerNote: `""`,
+ SensingMethod: `2`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ GPSImgDirection: `"18329/175"`,
+ Software: `"7.1.1"`,
+ DateTime: `"2014:09:01 15:03:47"`,
+ FNumber: `"12/5"`,
+ ExposureProgram: `2`,
+ SubSecTimeOriginal: `"880"`,
+ GPSImgDirectionRef: `"T"`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `204`,
+ ExposureTime: `"1/1284"`,
+ ISOSpeedRatings: `50`,
+ ComponentsConfiguration: `""`,
+ GPSAltitude: `"29/1"`,
+ GPSTimeStamp: `["13/1","3/1","4279/100"]`,
+ },
+}
diff --git a/Godeps/_workspace/src/github.com/rwcarlsen/goexif/tiff/tag.go b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/tiff/tag.go
new file mode 100644
index 000000000..66b68e334
--- /dev/null
+++ b/Godeps/_workspace/src/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/Godeps/_workspace/src/github.com/rwcarlsen/goexif/tiff/tiff.go b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/tiff/tiff.go
new file mode 100644
index 000000000..771e91878
--- /dev/null
+++ b/Godeps/_workspace/src/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 + "}"
+}
diff --git a/Godeps/_workspace/src/github.com/rwcarlsen/goexif/tiff/tiff_test.go b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/tiff/tiff_test.go
new file mode 100644
index 000000000..5db348dc8
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/rwcarlsen/goexif/tiff/tiff_test.go
@@ -0,0 +1,235 @@
+package tiff
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/hex"
+ "flag"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+var dataDir = flag.String("test_data_dir", ".", "Directory where the data files for testing are located")
+
+type input struct {
+ tgId string
+ tpe string
+ nVals string
+ offset string
+ val string
+}
+
+type output struct {
+ id uint16
+ typ DataType
+ count uint32
+ val []byte
+}
+
+type tagTest struct {
+ big input // big endian
+ little input // little endian
+ out output
+}
+
+///////////////////////////////////////////////
+//// Big endian Tests /////////////////////////
+///////////////////////////////////////////////
+var set1 = []tagTest{
+ //////////// string type //////////////
+ tagTest{
+ // {"TgId", "TYPE", "N-VALUES", "OFFSET--", "VAL..."},
+ input{"0003", "0002", "00000002", "11000000", ""},
+ input{"0300", "0200", "02000000", "11000000", ""},
+ output{0x0003, DataType(0x0002), 0x0002, []byte{0x11, 0x00}},
+ },
+ tagTest{
+ input{"0001", "0002", "00000006", "00000012", "111213141516"},
+ input{"0100", "0200", "06000000", "12000000", "111213141516"},
+ output{0x0001, DataType(0x0002), 0x0006, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16}},
+ },
+ //////////// int (1-byte) type ////////////////
+ tagTest{
+ input{"0001", "0001", "00000001", "11000000", ""},
+ input{"0100", "0100", "01000000", "11000000", ""},
+ output{0x0001, DataType(0x0001), 0x0001, []byte{0x11}},
+ },
+ tagTest{
+ input{"0001", "0001", "00000005", "00000010", "1112131415"},
+ input{"0100", "0100", "05000000", "10000000", "1112131415"},
+ output{0x0001, DataType(0x0001), 0x0005, []byte{0x11, 0x12, 0x13, 0x14, 0x15}},
+ },
+ tagTest{
+ input{"0001", "0006", "00000001", "11000000", ""},
+ input{"0100", "0600", "01000000", "11000000", ""},
+ output{0x0001, DataType(0x0006), 0x0001, []byte{0x11}},
+ },
+ tagTest{
+ input{"0001", "0006", "00000005", "00000010", "1112131415"},
+ input{"0100", "0600", "05000000", "10000000", "1112131415"},
+ output{0x0001, DataType(0x0006), 0x0005, []byte{0x11, 0x12, 0x13, 0x14, 0x15}},
+ },
+ //////////// int (2-byte) types ////////////////
+ tagTest{
+ input{"0001", "0003", "00000002", "11111212", ""},
+ input{"0100", "0300", "02000000", "11111212", ""},
+ output{0x0001, DataType(0x0003), 0x0002, []byte{0x11, 0x11, 0x12, 0x12}},
+ },
+ tagTest{
+ input{"0001", "0003", "00000003", "00000010", "111213141516"},
+ input{"0100", "0300", "03000000", "10000000", "111213141516"},
+ output{0x0001, DataType(0x0003), 0x0003, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16}},
+ },
+ tagTest{
+ input{"0001", "0008", "00000001", "11120000", ""},
+ input{"0100", "0800", "01000000", "11120000", ""},
+ output{0x0001, DataType(0x0008), 0x0001, []byte{0x11, 0x12}},
+ },
+ tagTest{
+ input{"0001", "0008", "00000003", "00000100", "111213141516"},
+ input{"0100", "0800", "03000000", "00100000", "111213141516"},
+ output{0x0001, DataType(0x0008), 0x0003, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16}},
+ },
+ //////////// int (4-byte) types ////////////////
+ tagTest{
+ input{"0001", "0004", "00000001", "11121314", ""},
+ input{"0100", "0400", "01000000", "11121314", ""},
+ output{0x0001, DataType(0x0004), 0x0001, []byte{0x11, 0x12, 0x13, 0x14}},
+ },
+ tagTest{
+ input{"0001", "0004", "00000002", "00000010", "1112131415161718"},
+ input{"0100", "0400", "02000000", "10000000", "1112131415161718"},
+ output{0x0001, DataType(0x0004), 0x0002, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}},
+ },
+ tagTest{
+ input{"0001", "0009", "00000001", "11121314", ""},
+ input{"0100", "0900", "01000000", "11121314", ""},
+ output{0x0001, DataType(0x0009), 0x0001, []byte{0x11, 0x12, 0x13, 0x14}},
+ },
+ tagTest{
+ input{"0001", "0009", "00000002", "00000011", "1112131415161819"},
+ input{"0100", "0900", "02000000", "11000000", "1112131415161819"},
+ output{0x0001, DataType(0x0009), 0x0002, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18, 0x19}},
+ },
+ //////////// rational types ////////////////////
+ tagTest{
+ input{"0001", "0005", "00000001", "00000010", "1112131415161718"},
+ input{"0100", "0500", "01000000", "10000000", "1112131415161718"},
+ output{0x0001, DataType(0x0005), 0x0001, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}},
+ },
+ tagTest{
+ input{"0001", "000A", "00000001", "00000011", "1112131415161819"},
+ input{"0100", "0A00", "01000000", "11000000", "1112131415161819"},
+ output{0x0001, DataType(0x000A), 0x0001, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18, 0x19}},
+ },
+ //////////// float types ///////////////////////
+ tagTest{
+ input{"0001", "0005", "00000001", "00000010", "1112131415161718"},
+ input{"0100", "0500", "01000000", "10000000", "1112131415161718"},
+ output{0x0001, DataType(0x0005), 0x0001, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}},
+ },
+ tagTest{
+ input{"0101", "000A", "00000001", "00000011", "1112131415161819"},
+ input{"0101", "0A00", "01000000", "11000000", "1112131415161819"},
+ output{0x0101, DataType(0x000A), 0x0001, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18, 0x19}},
+ },
+}
+
+func TestDecodeTag(t *testing.T) {
+ for i, tst := range set1 {
+ testSingle(t, binary.BigEndian, tst.big, tst.out, i)
+ testSingle(t, binary.LittleEndian, tst.little, tst.out, i)
+ }
+}
+
+func testSingle(t *testing.T, order binary.ByteOrder, in input, out output, i int) {
+ data := buildInput(in, order)
+ buf := bytes.NewReader(data)
+ tg, err := DecodeTag(buf, order)
+ if err != nil {
+ t.Errorf("(%v) tag %v%+v decode failed: %v", order, i, in, err)
+ return
+ }
+
+ if tg.Id != out.id {
+ t.Errorf("(%v) tag %v id decode: expected %v, got %v", order, i, out.id, tg.Id)
+ }
+ if tg.Type != out.typ {
+ t.Errorf("(%v) tag %v type decode: expected %v, got %v", order, i, out.typ, tg.Type)
+ }
+ if tg.Count != out.count {
+ t.Errorf("(%v) tag %v component count decode: expected %v, got %v", order, i, out.count, tg.Count)
+ }
+ if !bytes.Equal(tg.Val, out.val) {
+ t.Errorf("(%v) tag %v value decode: expected %v, got %v", order, i, out.val, tg.Val)
+ }
+}
+
+// buildInputBig creates a byte-slice based on big-endian ordered input
+func buildInput(in input, order binary.ByteOrder) []byte {
+ data := make([]byte, 0)
+ d, _ := hex.DecodeString(in.tgId)
+ data = append(data, d...)
+ d, _ = hex.DecodeString(in.tpe)
+ data = append(data, d...)
+ d, _ = hex.DecodeString(in.nVals)
+ data = append(data, d...)
+ d, _ = hex.DecodeString(in.offset)
+ data = append(data, d...)
+
+ if in.val != "" {
+ off := order.Uint32(d)
+ for i := 0; i < int(off)-12; i++ {
+ data = append(data, 0xFF)
+ }
+
+ d, _ = hex.DecodeString(in.val)
+ data = append(data, d...)
+ }
+
+ return data
+}
+
+func TestDecode(t *testing.T) {
+ name := filepath.Join(*dataDir, "sample1.tif")
+ f, err := os.Open(name)
+ if err != nil {
+ t.Fatalf("%v\n", err)
+ }
+
+ tif, err := Decode(f)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t.Log(tif)
+}
+
+func TestDecodeTag_blob(t *testing.T) {
+ buf := bytes.NewReader(data())
+ buf.Seek(10, 1)
+ tg, err := DecodeTag(buf, binary.LittleEndian)
+ if err != nil {
+ t.Fatalf("tag decode failed: %v", err)
+ }
+
+ t.Logf("tag: %v+\n", tg)
+ n, d, err := tg.Rat2(0)
+ if err != nil {
+ t.Fatalf("tag decoded wrong type: %v", err)
+ }
+ t.Logf("tag rat val: %v/%v\n", n, d)
+}
+
+func data() []byte {
+ s1 := "49492A000800000002001A0105000100"
+ s1 += "00002600000069870400010000001102"
+ s1 += "0000000000004800000001000000"
+
+ dat, err := hex.DecodeString(s1)
+ if err != nil {
+ panic("invalid string fixture")
+ }
+ return dat
+}