mirror of https://github.com/dsoprea/go-exif.git
We now have to pass a specific tag-index in from the top.
- This will allow us to handle custom tags and, with a little more work, custom IFDs.pull/3/head
parent
d8cdf29fa6
commit
d3b45fae77
|
@ -14,134 +14,133 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"fmt"
|
||||
"flag"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"io/ioutil"
|
||||
"encoding/json"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-exif"
|
||||
"github.com/dsoprea/go-exif"
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
var (
|
||||
filepathArg = ""
|
||||
printAsJsonArg = false
|
||||
filepathArg = ""
|
||||
printAsJsonArg = false
|
||||
)
|
||||
|
||||
|
||||
type IfdEntry struct {
|
||||
IfdName string `json:"ifd_name"`
|
||||
ParentIfdName string `json:"parent_ifd_name"`
|
||||
IfdIndex int `json:"ifd_index"`
|
||||
TagId uint16 `json:"tag_id"`
|
||||
TagName string `json:"tag_name"`
|
||||
TagTypeId uint16 `json:"tag_type_id"`
|
||||
TagTypeName string `json:"tag_type_name"`
|
||||
UnitCount uint32 `json:"unit_count"`
|
||||
Value interface{} `json:"value"`
|
||||
ValueString string `json:"value_string"`
|
||||
IfdName string `json:"ifd_name"`
|
||||
ParentIfdName string `json:"parent_ifd_name"`
|
||||
IfdIndex int `json:"ifd_index"`
|
||||
TagId uint16 `json:"tag_id"`
|
||||
TagName string `json:"tag_name"`
|
||||
TagTypeId uint16 `json:"tag_type_id"`
|
||||
TagTypeName string `json:"tag_type_name"`
|
||||
UnitCount uint32 `json:"unit_count"`
|
||||
Value interface{} `json:"value"`
|
||||
ValueString string `json:"value_string"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Program error.")
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Program error.")
|
||||
}
|
||||
}()
|
||||
|
||||
flag.StringVar(&filepathArg, "filepath", "", "File-path of image")
|
||||
flag.BoolVar(&printAsJsonArg, "json", false, "Print JSON")
|
||||
flag.StringVar(&filepathArg, "filepath", "", "File-path of image")
|
||||
flag.BoolVar(&printAsJsonArg, "json", false, "Print JSON")
|
||||
|
||||
flag.Parse()
|
||||
flag.Parse()
|
||||
|
||||
if filepathArg == "" {
|
||||
fmt.Printf("Please provide a file-path for an image.\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
if filepathArg == "" {
|
||||
fmt.Printf("Please provide a file-path for an image.\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
f, err := os.Open(filepathArg)
|
||||
log.PanicIf(err)
|
||||
f, err := os.Open(filepathArg)
|
||||
log.PanicIf(err)
|
||||
|
||||
data, err := ioutil.ReadAll(f)
|
||||
log.PanicIf(err)
|
||||
data, err := ioutil.ReadAll(f)
|
||||
log.PanicIf(err)
|
||||
|
||||
rawExif, err := exif.SearchAndExtractExif(data)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := exif.SearchAndExtractExif(data)
|
||||
log.PanicIf(err)
|
||||
|
||||
// Run the parse.
|
||||
// Run the parse.
|
||||
|
||||
entries := make([]IfdEntry, 0)
|
||||
entries := make([]IfdEntry, 0)
|
||||
|
||||
ti := exif.NewTagIndex()
|
||||
visitor := func(ii exif.IfdIdentity, ifdIndex int, tagId uint16, tagType exif.TagType, valueContext exif.ValueContext) (err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
log.Panic(err)
|
||||
}
|
||||
}()
|
||||
ti := exif.NewTagIndex()
|
||||
visitor := func(ii exif.IfdIdentity, ifdIndex int, tagId uint16, tagType exif.TagType, valueContext exif.ValueContext) (err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
log.Panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
it, err := ti.Get(ii, tagId)
|
||||
if err != nil {
|
||||
if log.Is(err, exif.ErrTagNotFound) {
|
||||
fmt.Printf("WARNING: Unknown tag: [%s] (%04x)\n", ii, tagId)
|
||||
return nil
|
||||
} else {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
it, err := ti.Get(ii, tagId)
|
||||
if err != nil {
|
||||
if log.Is(err, exif.ErrTagNotFound) {
|
||||
fmt.Printf("WARNING: Unknown tag: [%s] (%04x)\n", ii, tagId)
|
||||
return nil
|
||||
} else {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
valueString := ""
|
||||
var value interface{}
|
||||
if tagType.Type() == exif.TypeUndefined {
|
||||
var err error
|
||||
value, err = exif.UndefinedValue(ii, tagId, valueContext, tagType.ByteOrder())
|
||||
if log.Is(err, exif.ErrUnhandledUnknownTypedTag) {
|
||||
value = nil
|
||||
} else if err != nil {
|
||||
log.Panic(err)
|
||||
} else {
|
||||
valueString = fmt.Sprintf("%v", value)
|
||||
}
|
||||
} else {
|
||||
valueString, err = tagType.ResolveAsString(valueContext, true)
|
||||
log.PanicIf(err)
|
||||
valueString := ""
|
||||
var value interface{}
|
||||
if tagType.Type() == exif.TypeUndefined {
|
||||
var err error
|
||||
value, err = exif.UndefinedValue(ii, tagId, valueContext, tagType.ByteOrder())
|
||||
if log.Is(err, exif.ErrUnhandledUnknownTypedTag) {
|
||||
value = nil
|
||||
} else if err != nil {
|
||||
log.Panic(err)
|
||||
} else {
|
||||
valueString = fmt.Sprintf("%v", value)
|
||||
}
|
||||
} else {
|
||||
valueString, err = tagType.ResolveAsString(valueContext, true)
|
||||
log.PanicIf(err)
|
||||
|
||||
value = valueString
|
||||
}
|
||||
value = valueString
|
||||
}
|
||||
|
||||
entry := IfdEntry{
|
||||
IfdName: ii.IfdName,
|
||||
ParentIfdName: ii.ParentIfdName,
|
||||
IfdIndex: ifdIndex,
|
||||
TagId: tagId,
|
||||
TagName: it.Name,
|
||||
TagTypeId: tagType.Type(),
|
||||
TagTypeName: tagType.Name(),
|
||||
UnitCount: valueContext.UnitCount,
|
||||
Value: value,
|
||||
ValueString: valueString,
|
||||
}
|
||||
entry := IfdEntry{
|
||||
IfdName: ii.IfdName,
|
||||
ParentIfdName: ii.ParentIfdName,
|
||||
IfdIndex: ifdIndex,
|
||||
TagId: tagId,
|
||||
TagName: it.Name,
|
||||
TagTypeId: tagType.Type(),
|
||||
TagTypeName: tagType.Name(),
|
||||
UnitCount: valueContext.UnitCount,
|
||||
Value: value,
|
||||
ValueString: valueString,
|
||||
}
|
||||
|
||||
entries = append(entries, entry)
|
||||
entries = append(entries, entry)
|
||||
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = exif.Visit(rawExif, visitor)
|
||||
log.PanicIf(err)
|
||||
_, err = exif.Visit(ti, rawExif, visitor)
|
||||
log.PanicIf(err)
|
||||
|
||||
if printAsJsonArg == true {
|
||||
data, err := json.MarshalIndent(entries, "", " ")
|
||||
log.PanicIf(err)
|
||||
if printAsJsonArg == true {
|
||||
data, err := json.MarshalIndent(entries, "", " ")
|
||||
log.PanicIf(err)
|
||||
|
||||
fmt.Println(string(data))
|
||||
} else {
|
||||
for _, entry := range entries {
|
||||
fmt.Printf("IFD=[%s] ID=(0x%04x) NAME=[%s] COUNT=(%d) TYPE=[%s] VALUE=[%s]\n", entry.IfdName, entry.TagId, entry.TagName, entry.UnitCount, entry.TagTypeName, entry.ValueString)
|
||||
}
|
||||
}
|
||||
fmt.Println(string(data))
|
||||
} else {
|
||||
for _, entry := range entries {
|
||||
fmt.Printf("IFD=[%s] ID=(0x%04x) NAME=[%s] COUNT=(%d) TYPE=[%s] VALUE=[%s]\n", entry.IfdName, entry.TagId, entry.TagName, entry.UnitCount, entry.TagTypeName, entry.ValueString)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
8
exif.go
8
exif.go
|
@ -168,7 +168,7 @@ func ParseExifHeader(data []byte) (eh ExifHeader, err error) {
|
|||
}
|
||||
|
||||
// Visit recursively invokes a callback for every tag.
|
||||
func Visit(exifData []byte, visitor RawTagVisitor) (eh ExifHeader, err error) {
|
||||
func Visit(tagIndex *TagIndex, exifData []byte, visitor RawTagVisitor) (eh ExifHeader, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -178,7 +178,7 @@ func Visit(exifData []byte, visitor RawTagVisitor) (eh ExifHeader, err error) {
|
|||
eh, err = ParseExifHeader(exifData)
|
||||
log.PanicIf(err)
|
||||
|
||||
ie := NewIfdEnumerate(exifData, eh.ByteOrder)
|
||||
ie := NewIfdEnumerate(tagIndex, exifData, eh.ByteOrder)
|
||||
|
||||
err = ie.Scan(eh.FirstIfdOffset, visitor, true)
|
||||
log.PanicIf(err)
|
||||
|
@ -187,7 +187,7 @@ func Visit(exifData []byte, visitor RawTagVisitor) (eh ExifHeader, err error) {
|
|||
}
|
||||
|
||||
// Collect recursively builds a static structure of all IFDs and tags.
|
||||
func Collect(exifData []byte) (eh ExifHeader, index IfdIndex, err error) {
|
||||
func Collect(tagIndex *TagIndex, exifData []byte) (eh ExifHeader, index IfdIndex, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -197,7 +197,7 @@ func Collect(exifData []byte) (eh ExifHeader, index IfdIndex, err error) {
|
|||
eh, err = ParseExifHeader(exifData)
|
||||
log.PanicIf(err)
|
||||
|
||||
ie := NewIfdEnumerate(exifData, eh.ByteOrder)
|
||||
ie := NewIfdEnumerate(tagIndex, exifData, eh.ByteOrder)
|
||||
|
||||
index, err = ie.Collect(eh.FirstIfdOffset, true)
|
||||
log.PanicIf(err)
|
||||
|
|
602
exif_test.go
602
exif_test.go
|
@ -1,383 +1,385 @@
|
|||
package exif
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"os"
|
||||
"path"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"bytes"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"io/ioutil"
|
||||
"encoding/binary"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
|
||||
func TestVisit(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Exif failure.")
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Exif failure.")
|
||||
}
|
||||
}()
|
||||
|
||||
// Open the file.
|
||||
ti := NewTagIndex()
|
||||
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
f, err := os.Open(filepath)
|
||||
log.PanicIf(err)
|
||||
// Open the file.
|
||||
|
||||
defer f.Close()
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
f, err := os.Open(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
data, err := ioutil.ReadAll(f)
|
||||
log.PanicIf(err)
|
||||
defer f.Close()
|
||||
|
||||
// Search for the beginning of the EXIF information. The EXIF is near the
|
||||
// very beginning of our/most JPEGs, so this has a very low cost.
|
||||
data, err := ioutil.ReadAll(f)
|
||||
log.PanicIf(err)
|
||||
|
||||
foundAt := -1
|
||||
for i := 0; i < len(data); i++ {
|
||||
if _, err := ParseExifHeader(data[i:]); err == nil {
|
||||
foundAt = i
|
||||
break
|
||||
} else if log.Is(err, ErrNoExif) == false {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
// Search for the beginning of the EXIF information. The EXIF is near the
|
||||
// very beginning of our/most JPEGs, so this has a very low cost.
|
||||
|
||||
if foundAt == -1 {
|
||||
log.Panicf("EXIF start not found")
|
||||
}
|
||||
foundAt := -1
|
||||
for i := 0; i < len(data); i++ {
|
||||
if _, err := ParseExifHeader(data[i:]); err == nil {
|
||||
foundAt = i
|
||||
break
|
||||
} else if log.Is(err, ErrNoExif) == false {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Run the parse.
|
||||
if foundAt == -1 {
|
||||
log.Panicf("EXIF start not found")
|
||||
}
|
||||
|
||||
tags := make([]string, 0)
|
||||
// Run the parse.
|
||||
|
||||
visitor := func(ii IfdIdentity, ifdIndex int, tagId uint16, tagType TagType, valueContext ValueContext) (err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
log.Panic(err)
|
||||
}
|
||||
}()
|
||||
tags := make([]string, 0)
|
||||
|
||||
it, err := tagIndex.Get(ii, tagId)
|
||||
if err != nil {
|
||||
if log.Is(err, ErrTagNotFound) {
|
||||
fmt.Printf("Unknown tag: [%v] (%04x)\n", ii, tagId)
|
||||
return nil
|
||||
} else {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
visitor := func(ii IfdIdentity, ifdIndex int, tagId uint16, tagType TagType, valueContext ValueContext) (err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
log.Panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
valueString := ""
|
||||
if tagType.Type() == TypeUndefined {
|
||||
value, err := UndefinedValue(ii, tagId, valueContext, tagType.ByteOrder())
|
||||
if log.Is(err, ErrUnhandledUnknownTypedTag) {
|
||||
valueString = "!UNDEFINED!"
|
||||
} else if err != nil {
|
||||
log.Panic(err)
|
||||
} else {
|
||||
valueString = fmt.Sprintf("%v", value)
|
||||
}
|
||||
} else {
|
||||
valueString, err = tagType.ResolveAsString(valueContext, true)
|
||||
log.PanicIf(err)
|
||||
}
|
||||
it, err := ti.Get(ii, tagId)
|
||||
if err != nil {
|
||||
if log.Is(err, ErrTagNotFound) {
|
||||
fmt.Printf("Unknown tag: [%v] (%04x)\n", ii, tagId)
|
||||
return nil
|
||||
} else {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
description := fmt.Sprintf("IFD=[%s] ID=(0x%04x) NAME=[%s] COUNT=(%d) TYPE=[%s] VALUE=[%s]", ii.IfdName, tagId, it.Name, valueContext.UnitCount, tagType.Name(), valueString)
|
||||
tags = append(tags, description)
|
||||
valueString := ""
|
||||
if tagType.Type() == TypeUndefined {
|
||||
value, err := UndefinedValue(ii, tagId, valueContext, tagType.ByteOrder())
|
||||
if log.Is(err, ErrUnhandledUnknownTypedTag) {
|
||||
valueString = "!UNDEFINED!"
|
||||
} else if err != nil {
|
||||
log.Panic(err)
|
||||
} else {
|
||||
valueString = fmt.Sprintf("%v", value)
|
||||
}
|
||||
} else {
|
||||
valueString, err = tagType.ResolveAsString(valueContext, true)
|
||||
log.PanicIf(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
description := fmt.Sprintf("IFD=[%s] ID=(0x%04x) NAME=[%s] COUNT=(%d) TYPE=[%s] VALUE=[%s]", ii.IfdName, tagId, it.Name, valueContext.UnitCount, tagType.Name(), valueString)
|
||||
tags = append(tags, description)
|
||||
|
||||
_, err = Visit(data[foundAt:], visitor)
|
||||
log.PanicIf(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// for _, line := range tags {
|
||||
// fmt.Printf("TAGS: %s\n", line)
|
||||
// }
|
||||
_, err = Visit(ti, data[foundAt:], visitor)
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []string {
|
||||
"IFD=[IFD] ID=(0x010f) NAME=[Make] COUNT=(6) TYPE=[ASCII] VALUE=[Canon]",
|
||||
"IFD=[IFD] ID=(0x0110) NAME=[Model] COUNT=(22) TYPE=[ASCII] VALUE=[Canon EOS 5D Mark III]",
|
||||
"IFD=[IFD] ID=(0x0112) NAME=[Orientation] COUNT=(1) TYPE=[SHORT] VALUE=[1]",
|
||||
"IFD=[IFD] ID=(0x011a) NAME=[XResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[72/1]",
|
||||
"IFD=[IFD] ID=(0x011b) NAME=[YResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[72/1]",
|
||||
"IFD=[IFD] ID=(0x0128) NAME=[ResolutionUnit] COUNT=(1) TYPE=[SHORT] VALUE=[2]",
|
||||
"IFD=[IFD] ID=(0x0132) NAME=[DateTime] COUNT=(20) TYPE=[ASCII] VALUE=[2017:12:02 08:18:50]",
|
||||
"IFD=[IFD] ID=(0x013b) NAME=[Artist] COUNT=(1) TYPE=[ASCII] VALUE=[]",
|
||||
"IFD=[IFD] ID=(0x0213) NAME=[YCbCrPositioning] COUNT=(1) TYPE=[SHORT] VALUE=[2]",
|
||||
"IFD=[IFD] ID=(0x8298) NAME=[Copyright] COUNT=(1) TYPE=[ASCII] VALUE=[]",
|
||||
"IFD=[IFD] ID=(0x8769) NAME=[ExifTag] COUNT=(1) TYPE=[LONG] VALUE=[360]",
|
||||
"IFD=[Exif] ID=(0x829a) NAME=[ExposureTime] COUNT=(1) TYPE=[RATIONAL] VALUE=[1/640]",
|
||||
"IFD=[Exif] ID=(0x829d) NAME=[FNumber] COUNT=(1) TYPE=[RATIONAL] VALUE=[4/1]",
|
||||
"IFD=[Exif] ID=(0x8822) NAME=[ExposureProgram] COUNT=(1) TYPE=[SHORT] VALUE=[4]",
|
||||
"IFD=[Exif] ID=(0x8827) NAME=[ISOSpeedRatings] COUNT=(1) TYPE=[SHORT] VALUE=[1600]",
|
||||
"IFD=[Exif] ID=(0x8830) NAME=[SensitivityType] COUNT=(1) TYPE=[SHORT] VALUE=[2]",
|
||||
"IFD=[Exif] ID=(0x8832) NAME=[RecommendedExposureIndex] COUNT=(1) TYPE=[LONG] VALUE=[1600]",
|
||||
"IFD=[Exif] ID=(0x9000) NAME=[ExifVersion] COUNT=(4) TYPE=[UNDEFINED] VALUE=[0230]",
|
||||
"IFD=[Exif] ID=(0x9003) NAME=[DateTimeOriginal] COUNT=(20) TYPE=[ASCII] VALUE=[2017:12:02 08:18:50]",
|
||||
"IFD=[Exif] ID=(0x9004) NAME=[DateTimeDigitized] COUNT=(20) TYPE=[ASCII] VALUE=[2017:12:02 08:18:50]",
|
||||
"IFD=[Exif] ID=(0x9101) NAME=[ComponentsConfiguration] COUNT=(4) TYPE=[UNDEFINED] VALUE=[ComponentsConfiguration<ID=[YCBCR] BYTES=[1 2 3 0]>]",
|
||||
"IFD=[Exif] ID=(0x9201) NAME=[ShutterSpeedValue] COUNT=(1) TYPE=[SRATIONAL] VALUE=[614400/65536]",
|
||||
"IFD=[Exif] ID=(0x9202) NAME=[ApertureValue] COUNT=(1) TYPE=[RATIONAL] VALUE=[262144/65536]",
|
||||
"IFD=[Exif] ID=(0x9204) NAME=[ExposureBiasValue] COUNT=(1) TYPE=[SRATIONAL] VALUE=[0/1]",
|
||||
"IFD=[Exif] ID=(0x9207) NAME=[MeteringMode] COUNT=(1) TYPE=[SHORT] VALUE=[5]",
|
||||
"IFD=[Exif] ID=(0x9209) NAME=[Flash] COUNT=(1) TYPE=[SHORT] VALUE=[16]",
|
||||
"IFD=[Exif] ID=(0x920a) NAME=[FocalLength] COUNT=(1) TYPE=[RATIONAL] VALUE=[16/1]",
|
||||
"IFD=[Exif] ID=(0x927c) NAME=[MakerNote] COUNT=(8152) TYPE=[UNDEFINED] VALUE=[MakerNote<TYPE-ID=[28 00 01 00 03 00 31 00 00 00 74 05 00 00 02 00 03 00 04 00]>]",
|
||||
"IFD=[Exif] ID=(0x9286) NAME=[UserComment] COUNT=(264) TYPE=[UNDEFINED] VALUE=[UserComment<SIZE=(256) ENCODING=[UNDEFINED] V=[0 0 0 0 0 0 0 0]... LEN=(256)>]",
|
||||
"IFD=[Exif] ID=(0x9290) NAME=[SubSecTime] COUNT=(3) TYPE=[ASCII] VALUE=[00]",
|
||||
"IFD=[Exif] ID=(0x9291) NAME=[SubSecTimeOriginal] COUNT=(3) TYPE=[ASCII] VALUE=[00]",
|
||||
"IFD=[Exif] ID=(0x9292) NAME=[SubSecTimeDigitized] COUNT=(3) TYPE=[ASCII] VALUE=[00]",
|
||||
"IFD=[Exif] ID=(0xa000) NAME=[FlashpixVersion] COUNT=(4) TYPE=[UNDEFINED] VALUE=[0100]",
|
||||
"IFD=[Exif] ID=(0xa001) NAME=[ColorSpace] COUNT=(1) TYPE=[SHORT] VALUE=[1]",
|
||||
"IFD=[Exif] ID=(0xa002) NAME=[PixelXDimension] COUNT=(1) TYPE=[SHORT] VALUE=[3840]",
|
||||
"IFD=[Exif] ID=(0xa003) NAME=[PixelYDimension] COUNT=(1) TYPE=[SHORT] VALUE=[2560]",
|
||||
"IFD=[Exif] ID=(0xa005) NAME=[InteroperabilityTag] COUNT=(1) TYPE=[LONG] VALUE=[9326]",
|
||||
"IFD=[Iop] ID=(0x0001) NAME=[InteroperabilityIndex] COUNT=(4) TYPE=[ASCII] VALUE=[R98]",
|
||||
"IFD=[Iop] ID=(0x0002) NAME=[InteroperabilityVersion] COUNT=(4) TYPE=[UNDEFINED] VALUE=[0100]",
|
||||
"IFD=[Exif] ID=(0xa20e) NAME=[FocalPlaneXResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[3840000/1461]",
|
||||
"IFD=[Exif] ID=(0xa20f) NAME=[FocalPlaneYResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[2560000/972]",
|
||||
"IFD=[Exif] ID=(0xa210) NAME=[FocalPlaneResolutionUnit] COUNT=(1) TYPE=[SHORT] VALUE=[2]",
|
||||
"IFD=[Exif] ID=(0xa401) NAME=[CustomRendered] COUNT=(1) TYPE=[SHORT] VALUE=[0]",
|
||||
"IFD=[Exif] ID=(0xa402) NAME=[ExposureMode] COUNT=(1) TYPE=[SHORT] VALUE=[0]",
|
||||
"IFD=[Exif] ID=(0xa403) NAME=[WhiteBalance] COUNT=(1) TYPE=[SHORT] VALUE=[0]",
|
||||
"IFD=[Exif] ID=(0xa406) NAME=[SceneCaptureType] COUNT=(1) TYPE=[SHORT] VALUE=[0]",
|
||||
"IFD=[Exif] ID=(0xa430) NAME=[CameraOwnerName] COUNT=(1) TYPE=[ASCII] VALUE=[]",
|
||||
"IFD=[Exif] ID=(0xa431) NAME=[BodySerialNumber] COUNT=(13) TYPE=[ASCII] VALUE=[063024020097]",
|
||||
"IFD=[Exif] ID=(0xa432) NAME=[LensSpecification] COUNT=(4) TYPE=[RATIONAL] VALUE=[16/1]",
|
||||
"IFD=[Exif] ID=(0xa434) NAME=[LensModel] COUNT=(22) TYPE=[ASCII] VALUE=[EF16-35mm f/4L IS USM]",
|
||||
"IFD=[Exif] ID=(0xa435) NAME=[LensSerialNumber] COUNT=(11) TYPE=[ASCII] VALUE=[2400001068]",
|
||||
"IFD=[IFD] ID=(0x8825) NAME=[GPSTag] COUNT=(1) TYPE=[LONG] VALUE=[9554]",
|
||||
"IFD=[GPSInfo] ID=(0x0000) NAME=[GPSVersionID] COUNT=(4) TYPE=[BYTE] VALUE=[0x02]",
|
||||
"IFD=[IFD] ID=(0x0103) NAME=[Compression] COUNT=(1) TYPE=[SHORT] VALUE=[6]",
|
||||
"IFD=[IFD] ID=(0x011a) NAME=[XResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[72/1]",
|
||||
"IFD=[IFD] ID=(0x011b) NAME=[YResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[72/1]",
|
||||
"IFD=[IFD] ID=(0x0128) NAME=[ResolutionUnit] COUNT=(1) TYPE=[SHORT] VALUE=[2]",
|
||||
}
|
||||
// for _, line := range tags {
|
||||
// fmt.Printf("TAGS: %s\n", line)
|
||||
// }
|
||||
|
||||
if reflect.DeepEqual(tags, expected) == false {
|
||||
fmt.Printf("\n")
|
||||
fmt.Printf("ACTUAL:\n")
|
||||
fmt.Printf("\n")
|
||||
expected := []string{
|
||||
"IFD=[IFD] ID=(0x010f) NAME=[Make] COUNT=(6) TYPE=[ASCII] VALUE=[Canon]",
|
||||
"IFD=[IFD] ID=(0x0110) NAME=[Model] COUNT=(22) TYPE=[ASCII] VALUE=[Canon EOS 5D Mark III]",
|
||||
"IFD=[IFD] ID=(0x0112) NAME=[Orientation] COUNT=(1) TYPE=[SHORT] VALUE=[1]",
|
||||
"IFD=[IFD] ID=(0x011a) NAME=[XResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[72/1]",
|
||||
"IFD=[IFD] ID=(0x011b) NAME=[YResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[72/1]",
|
||||
"IFD=[IFD] ID=(0x0128) NAME=[ResolutionUnit] COUNT=(1) TYPE=[SHORT] VALUE=[2]",
|
||||
"IFD=[IFD] ID=(0x0132) NAME=[DateTime] COUNT=(20) TYPE=[ASCII] VALUE=[2017:12:02 08:18:50]",
|
||||
"IFD=[IFD] ID=(0x013b) NAME=[Artist] COUNT=(1) TYPE=[ASCII] VALUE=[]",
|
||||
"IFD=[IFD] ID=(0x0213) NAME=[YCbCrPositioning] COUNT=(1) TYPE=[SHORT] VALUE=[2]",
|
||||
"IFD=[IFD] ID=(0x8298) NAME=[Copyright] COUNT=(1) TYPE=[ASCII] VALUE=[]",
|
||||
"IFD=[IFD] ID=(0x8769) NAME=[ExifTag] COUNT=(1) TYPE=[LONG] VALUE=[360]",
|
||||
"IFD=[Exif] ID=(0x829a) NAME=[ExposureTime] COUNT=(1) TYPE=[RATIONAL] VALUE=[1/640]",
|
||||
"IFD=[Exif] ID=(0x829d) NAME=[FNumber] COUNT=(1) TYPE=[RATIONAL] VALUE=[4/1]",
|
||||
"IFD=[Exif] ID=(0x8822) NAME=[ExposureProgram] COUNT=(1) TYPE=[SHORT] VALUE=[4]",
|
||||
"IFD=[Exif] ID=(0x8827) NAME=[ISOSpeedRatings] COUNT=(1) TYPE=[SHORT] VALUE=[1600]",
|
||||
"IFD=[Exif] ID=(0x8830) NAME=[SensitivityType] COUNT=(1) TYPE=[SHORT] VALUE=[2]",
|
||||
"IFD=[Exif] ID=(0x8832) NAME=[RecommendedExposureIndex] COUNT=(1) TYPE=[LONG] VALUE=[1600]",
|
||||
"IFD=[Exif] ID=(0x9000) NAME=[ExifVersion] COUNT=(4) TYPE=[UNDEFINED] VALUE=[0230]",
|
||||
"IFD=[Exif] ID=(0x9003) NAME=[DateTimeOriginal] COUNT=(20) TYPE=[ASCII] VALUE=[2017:12:02 08:18:50]",
|
||||
"IFD=[Exif] ID=(0x9004) NAME=[DateTimeDigitized] COUNT=(20) TYPE=[ASCII] VALUE=[2017:12:02 08:18:50]",
|
||||
"IFD=[Exif] ID=(0x9101) NAME=[ComponentsConfiguration] COUNT=(4) TYPE=[UNDEFINED] VALUE=[ComponentsConfiguration<ID=[YCBCR] BYTES=[1 2 3 0]>]",
|
||||
"IFD=[Exif] ID=(0x9201) NAME=[ShutterSpeedValue] COUNT=(1) TYPE=[SRATIONAL] VALUE=[614400/65536]",
|
||||
"IFD=[Exif] ID=(0x9202) NAME=[ApertureValue] COUNT=(1) TYPE=[RATIONAL] VALUE=[262144/65536]",
|
||||
"IFD=[Exif] ID=(0x9204) NAME=[ExposureBiasValue] COUNT=(1) TYPE=[SRATIONAL] VALUE=[0/1]",
|
||||
"IFD=[Exif] ID=(0x9207) NAME=[MeteringMode] COUNT=(1) TYPE=[SHORT] VALUE=[5]",
|
||||
"IFD=[Exif] ID=(0x9209) NAME=[Flash] COUNT=(1) TYPE=[SHORT] VALUE=[16]",
|
||||
"IFD=[Exif] ID=(0x920a) NAME=[FocalLength] COUNT=(1) TYPE=[RATIONAL] VALUE=[16/1]",
|
||||
"IFD=[Exif] ID=(0x927c) NAME=[MakerNote] COUNT=(8152) TYPE=[UNDEFINED] VALUE=[MakerNote<TYPE-ID=[28 00 01 00 03 00 31 00 00 00 74 05 00 00 02 00 03 00 04 00]>]",
|
||||
"IFD=[Exif] ID=(0x9286) NAME=[UserComment] COUNT=(264) TYPE=[UNDEFINED] VALUE=[UserComment<SIZE=(256) ENCODING=[UNDEFINED] V=[0 0 0 0 0 0 0 0]... LEN=(256)>]",
|
||||
"IFD=[Exif] ID=(0x9290) NAME=[SubSecTime] COUNT=(3) TYPE=[ASCII] VALUE=[00]",
|
||||
"IFD=[Exif] ID=(0x9291) NAME=[SubSecTimeOriginal] COUNT=(3) TYPE=[ASCII] VALUE=[00]",
|
||||
"IFD=[Exif] ID=(0x9292) NAME=[SubSecTimeDigitized] COUNT=(3) TYPE=[ASCII] VALUE=[00]",
|
||||
"IFD=[Exif] ID=(0xa000) NAME=[FlashpixVersion] COUNT=(4) TYPE=[UNDEFINED] VALUE=[0100]",
|
||||
"IFD=[Exif] ID=(0xa001) NAME=[ColorSpace] COUNT=(1) TYPE=[SHORT] VALUE=[1]",
|
||||
"IFD=[Exif] ID=(0xa002) NAME=[PixelXDimension] COUNT=(1) TYPE=[SHORT] VALUE=[3840]",
|
||||
"IFD=[Exif] ID=(0xa003) NAME=[PixelYDimension] COUNT=(1) TYPE=[SHORT] VALUE=[2560]",
|
||||
"IFD=[Exif] ID=(0xa005) NAME=[InteroperabilityTag] COUNT=(1) TYPE=[LONG] VALUE=[9326]",
|
||||
"IFD=[Iop] ID=(0x0001) NAME=[InteroperabilityIndex] COUNT=(4) TYPE=[ASCII] VALUE=[R98]",
|
||||
"IFD=[Iop] ID=(0x0002) NAME=[InteroperabilityVersion] COUNT=(4) TYPE=[UNDEFINED] VALUE=[0100]",
|
||||
"IFD=[Exif] ID=(0xa20e) NAME=[FocalPlaneXResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[3840000/1461]",
|
||||
"IFD=[Exif] ID=(0xa20f) NAME=[FocalPlaneYResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[2560000/972]",
|
||||
"IFD=[Exif] ID=(0xa210) NAME=[FocalPlaneResolutionUnit] COUNT=(1) TYPE=[SHORT] VALUE=[2]",
|
||||
"IFD=[Exif] ID=(0xa401) NAME=[CustomRendered] COUNT=(1) TYPE=[SHORT] VALUE=[0]",
|
||||
"IFD=[Exif] ID=(0xa402) NAME=[ExposureMode] COUNT=(1) TYPE=[SHORT] VALUE=[0]",
|
||||
"IFD=[Exif] ID=(0xa403) NAME=[WhiteBalance] COUNT=(1) TYPE=[SHORT] VALUE=[0]",
|
||||
"IFD=[Exif] ID=(0xa406) NAME=[SceneCaptureType] COUNT=(1) TYPE=[SHORT] VALUE=[0]",
|
||||
"IFD=[Exif] ID=(0xa430) NAME=[CameraOwnerName] COUNT=(1) TYPE=[ASCII] VALUE=[]",
|
||||
"IFD=[Exif] ID=(0xa431) NAME=[BodySerialNumber] COUNT=(13) TYPE=[ASCII] VALUE=[063024020097]",
|
||||
"IFD=[Exif] ID=(0xa432) NAME=[LensSpecification] COUNT=(4) TYPE=[RATIONAL] VALUE=[16/1]",
|
||||
"IFD=[Exif] ID=(0xa434) NAME=[LensModel] COUNT=(22) TYPE=[ASCII] VALUE=[EF16-35mm f/4L IS USM]",
|
||||
"IFD=[Exif] ID=(0xa435) NAME=[LensSerialNumber] COUNT=(11) TYPE=[ASCII] VALUE=[2400001068]",
|
||||
"IFD=[IFD] ID=(0x8825) NAME=[GPSTag] COUNT=(1) TYPE=[LONG] VALUE=[9554]",
|
||||
"IFD=[GPSInfo] ID=(0x0000) NAME=[GPSVersionID] COUNT=(4) TYPE=[BYTE] VALUE=[0x02]",
|
||||
"IFD=[IFD] ID=(0x0103) NAME=[Compression] COUNT=(1) TYPE=[SHORT] VALUE=[6]",
|
||||
"IFD=[IFD] ID=(0x011a) NAME=[XResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[72/1]",
|
||||
"IFD=[IFD] ID=(0x011b) NAME=[YResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[72/1]",
|
||||
"IFD=[IFD] ID=(0x0128) NAME=[ResolutionUnit] COUNT=(1) TYPE=[SHORT] VALUE=[2]",
|
||||
}
|
||||
|
||||
for _, line := range tags {
|
||||
fmt.Println(line)
|
||||
}
|
||||
if reflect.DeepEqual(tags, expected) == false {
|
||||
fmt.Printf("\n")
|
||||
fmt.Printf("ACTUAL:\n")
|
||||
fmt.Printf("\n")
|
||||
|
||||
fmt.Printf("\n")
|
||||
fmt.Printf("EXPECTED:\n")
|
||||
fmt.Printf("\n")
|
||||
for _, line := range tags {
|
||||
fmt.Println(line)
|
||||
}
|
||||
|
||||
for _, line := range expected {
|
||||
fmt.Println(line)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
fmt.Printf("EXPECTED:\n")
|
||||
fmt.Printf("\n")
|
||||
|
||||
fmt.Printf("\n")
|
||||
for _, line := range expected {
|
||||
fmt.Println(line)
|
||||
}
|
||||
|
||||
t.Fatalf("tags not correct.")
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
t.Fatalf("tags not correct.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchFileAndExtractExif(t *testing.T) {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
// Returns a slice starting with the EXIF data and going to the end of the
|
||||
// image.
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
// Returns a slice starting with the EXIF data and going to the end of the
|
||||
// image.
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(rawExif[:len(testExifData)], testExifData) != 0 {
|
||||
t.Fatalf("found EXIF data not correct")
|
||||
}
|
||||
if bytes.Compare(rawExif[:len(testExifData)], testExifData) != 0 {
|
||||
t.Fatalf("found EXIF data not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchAndExtractExif(t *testing.T) {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
imageData, err := ioutil.ReadFile(filepath)
|
||||
log.PanicIf(err)
|
||||
imageData, err := ioutil.ReadFile(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
rawExif, err := SearchAndExtractExif(imageData)
|
||||
log.PanicIf(err)
|
||||
|
||||
rawExif, err := SearchAndExtractExif(imageData)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(rawExif[:len(testExifData)], testExifData) != 0 {
|
||||
t.Fatalf("found EXIF data not correct")
|
||||
}
|
||||
if bytes.Compare(rawExif[:len(testExifData)], testExifData) != 0 {
|
||||
t.Fatalf("found EXIF data not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCollect(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Exif failure.")
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Exif failure.")
|
||||
}
|
||||
}()
|
||||
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
rootIfd := index.RootIfd
|
||||
ifds := index.Ifds
|
||||
tree := index.Tree
|
||||
lookup := index.Lookup
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
if rootIfd.Offset != uint32(0x0008) {
|
||||
t.Fatalf("Root-IFD not correct: (0x%04d).", rootIfd.Offset)
|
||||
} else if rootIfd.Id != 0 {
|
||||
t.Fatalf("Root-IFD does not have the right ID: (%d)", rootIfd.Id)
|
||||
} else if tree[0] != rootIfd {
|
||||
t.Fatalf("Root-IFD is not indexed properly.")
|
||||
} else if len(ifds) != 5 {
|
||||
t.Fatalf("The IFD list is not the right size: (%d)", len(ifds))
|
||||
} else if len(tree) != 5 {
|
||||
t.Fatalf("The IFD tree is not the right size: (%d)", len(tree))
|
||||
} else if len(lookup) != 4 {
|
||||
t.Fatalf("The IFD lookup is not the right size: (%d)", len(lookup))
|
||||
}
|
||||
rootIfd := index.RootIfd
|
||||
ifds := index.Ifds
|
||||
tree := index.Tree
|
||||
lookup := index.Lookup
|
||||
|
||||
if rootIfd.NextIfdOffset != 0x2c54 {
|
||||
t.Fatalf("Root IFD does not continue correctly: (0x%04x)", rootIfd.NextIfdOffset)
|
||||
} else if rootIfd.NextIfd.Offset != rootIfd.NextIfdOffset {
|
||||
t.Fatalf("Root IFD neighbor object does not have the right offset: (0x%04x != 0x%04x)", rootIfd.NextIfd.Offset, rootIfd.NextIfdOffset)
|
||||
} else if rootIfd.NextIfd.NextIfdOffset != 0 {
|
||||
t.Fatalf("Root IFD chain not terminated correctly (1).")
|
||||
} else if rootIfd.NextIfd.NextIfd != nil {
|
||||
t.Fatalf("Root IFD chain not terminated correctly (2).")
|
||||
}
|
||||
if rootIfd.Offset != uint32(0x0008) {
|
||||
t.Fatalf("Root-IFD not correct: (0x%04d).", rootIfd.Offset)
|
||||
} else if rootIfd.Id != 0 {
|
||||
t.Fatalf("Root-IFD does not have the right ID: (%d)", rootIfd.Id)
|
||||
} else if tree[0] != rootIfd {
|
||||
t.Fatalf("Root-IFD is not indexed properly.")
|
||||
} else if len(ifds) != 5 {
|
||||
t.Fatalf("The IFD list is not the right size: (%d)", len(ifds))
|
||||
} else if len(tree) != 5 {
|
||||
t.Fatalf("The IFD tree is not the right size: (%d)", len(tree))
|
||||
} else if len(lookup) != 4 {
|
||||
t.Fatalf("The IFD lookup is not the right size: (%d)", len(lookup))
|
||||
}
|
||||
|
||||
if rootIfd.Name != IfdStandard {
|
||||
t.Fatalf("Root IFD is not labeled correctly: [%s]", rootIfd.Name)
|
||||
} else if rootIfd.NextIfd.Name != IfdStandard {
|
||||
t.Fatalf("Root IFD sibling is not labeled correctly: [%s]", rootIfd.Name)
|
||||
} else if rootIfd.Children[0].Name != IfdExif {
|
||||
t.Fatalf("Root IFD child (0) is not labeled correctly: [%s]", rootIfd.Children[0].Name)
|
||||
} else if rootIfd.Children[1].Name != IfdGps {
|
||||
t.Fatalf("Root IFD child (1) is not labeled correctly: [%s]", rootIfd.Children[1].Name)
|
||||
} else if rootIfd.Children[0].Children[0].Name != IfdIop {
|
||||
t.Fatalf("Exif IFD child is not an IOP IFD: [%s]", rootIfd.Children[0].Children[0].Name)
|
||||
}
|
||||
if rootIfd.NextIfdOffset != 0x2c54 {
|
||||
t.Fatalf("Root IFD does not continue correctly: (0x%04x)", rootIfd.NextIfdOffset)
|
||||
} else if rootIfd.NextIfd.Offset != rootIfd.NextIfdOffset {
|
||||
t.Fatalf("Root IFD neighbor object does not have the right offset: (0x%04x != 0x%04x)", rootIfd.NextIfd.Offset, rootIfd.NextIfdOffset)
|
||||
} else if rootIfd.NextIfd.NextIfdOffset != 0 {
|
||||
t.Fatalf("Root IFD chain not terminated correctly (1).")
|
||||
} else if rootIfd.NextIfd.NextIfd != nil {
|
||||
t.Fatalf("Root IFD chain not terminated correctly (2).")
|
||||
}
|
||||
|
||||
rootIi, _ := IfdIdOrFail("", IfdStandard)
|
||||
if rootIfd.Name != IfdStandard {
|
||||
t.Fatalf("Root IFD is not labeled correctly: [%s]", rootIfd.Name)
|
||||
} else if rootIfd.NextIfd.Name != IfdStandard {
|
||||
t.Fatalf("Root IFD sibling is not labeled correctly: [%s]", rootIfd.Name)
|
||||
} else if rootIfd.Children[0].Name != IfdExif {
|
||||
t.Fatalf("Root IFD child (0) is not labeled correctly: [%s]", rootIfd.Children[0].Name)
|
||||
} else if rootIfd.Children[1].Name != IfdGps {
|
||||
t.Fatalf("Root IFD child (1) is not labeled correctly: [%s]", rootIfd.Children[1].Name)
|
||||
} else if rootIfd.Children[0].Children[0].Name != IfdIop {
|
||||
t.Fatalf("Exif IFD child is not an IOP IFD: [%s]", rootIfd.Children[0].Children[0].Name)
|
||||
}
|
||||
|
||||
if lookup[rootIi][0].Name != IfdStandard {
|
||||
t.Fatalf("Lookup for standard IFD not correct.")
|
||||
} else if lookup[rootIi][1].Name != IfdStandard {
|
||||
t.Fatalf("Lookup for standard IFD not correct.")
|
||||
}
|
||||
rootIi, _ := IfdIdOrFail("", IfdStandard)
|
||||
|
||||
exifIi, _ := IfdIdOrFail(IfdStandard, IfdExif)
|
||||
if lookup[rootIi][0].Name != IfdStandard {
|
||||
t.Fatalf("Lookup for standard IFD not correct.")
|
||||
} else if lookup[rootIi][1].Name != IfdStandard {
|
||||
t.Fatalf("Lookup for standard IFD not correct.")
|
||||
}
|
||||
|
||||
if lookup[exifIi][0].Name != IfdExif {
|
||||
t.Fatalf("Lookup for EXIF IFD not correct.")
|
||||
}
|
||||
exifIi, _ := IfdIdOrFail(IfdStandard, IfdExif)
|
||||
|
||||
gpsIi, _ := IfdIdOrFail(IfdStandard, IfdGps)
|
||||
if lookup[exifIi][0].Name != IfdExif {
|
||||
t.Fatalf("Lookup for EXIF IFD not correct.")
|
||||
}
|
||||
|
||||
if lookup[gpsIi][0].Name != IfdGps {
|
||||
t.Fatalf("Lookup for EXIF IFD not correct.")
|
||||
}
|
||||
gpsIi, _ := IfdIdOrFail(IfdStandard, IfdGps)
|
||||
|
||||
iopIi, _ := IfdIdOrFail(IfdExif, IfdIop)
|
||||
if lookup[gpsIi][0].Name != IfdGps {
|
||||
t.Fatalf("Lookup for EXIF IFD not correct.")
|
||||
}
|
||||
|
||||
if lookup[iopIi][0].Name != IfdIop {
|
||||
t.Fatalf("Lookup for EXIF IFD not correct.")
|
||||
}
|
||||
iopIi, _ := IfdIdOrFail(IfdExif, IfdIop)
|
||||
|
||||
foundExif := 0
|
||||
foundGps := 0
|
||||
for _, ite := range lookup[rootIi][0].Entries {
|
||||
if ite.ChildIfdName == IfdExif {
|
||||
foundExif++
|
||||
if lookup[iopIi][0].Name != IfdIop {
|
||||
t.Fatalf("Lookup for EXIF IFD not correct.")
|
||||
}
|
||||
|
||||
name, found := IfdTagNameWithId(IfdStandard, ite.TagId)
|
||||
if found != true {
|
||||
t.Fatalf("could not find tag-ID for EXIF IFD")
|
||||
} else if name != IfdExif {
|
||||
t.Fatalf("EXIF IFD tag-ID mismatch: (0x%02x) [%s] != [%s]", ite.TagId, name, IfdExif)
|
||||
}
|
||||
}
|
||||
foundExif := 0
|
||||
foundGps := 0
|
||||
for _, ite := range lookup[rootIi][0].Entries {
|
||||
if ite.ChildIfdName == IfdExif {
|
||||
foundExif++
|
||||
|
||||
if ite.ChildIfdName == IfdGps {
|
||||
foundGps++
|
||||
name, found := IfdTagNameWithId(IfdStandard, ite.TagId)
|
||||
if found != true {
|
||||
t.Fatalf("could not find tag-ID for EXIF IFD")
|
||||
} else if name != IfdExif {
|
||||
t.Fatalf("EXIF IFD tag-ID mismatch: (0x%02x) [%s] != [%s]", ite.TagId, name, IfdExif)
|
||||
}
|
||||
}
|
||||
|
||||
name, found := IfdTagNameWithId(IfdStandard, ite.TagId)
|
||||
if found != true {
|
||||
t.Fatalf("could not find tag-ID for GPS IFD")
|
||||
} else if name != IfdGps {
|
||||
t.Fatalf("GPS IFD tag-ID mismatch: (0x%02x) [%s] != [%s]", ite.TagId, name, IfdGps)
|
||||
}
|
||||
}
|
||||
}
|
||||
if ite.ChildIfdName == IfdGps {
|
||||
foundGps++
|
||||
|
||||
if foundExif != 1 {
|
||||
t.Fatalf("Exactly one EXIF IFD tag wasn't found: (%d)", foundExif)
|
||||
} else if foundGps != 1 {
|
||||
t.Fatalf("Exactly one GPS IFD tag wasn't found: (%d)", foundGps)
|
||||
}
|
||||
name, found := IfdTagNameWithId(IfdStandard, ite.TagId)
|
||||
if found != true {
|
||||
t.Fatalf("could not find tag-ID for GPS IFD")
|
||||
} else if name != IfdGps {
|
||||
t.Fatalf("GPS IFD tag-ID mismatch: (0x%02x) [%s] != [%s]", ite.TagId, name, IfdGps)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foundIop := 0
|
||||
for _, ite := range lookup[exifIi][0].Entries {
|
||||
if ite.ChildIfdName == IfdIop {
|
||||
foundIop++
|
||||
if foundExif != 1 {
|
||||
t.Fatalf("Exactly one EXIF IFD tag wasn't found: (%d)", foundExif)
|
||||
} else if foundGps != 1 {
|
||||
t.Fatalf("Exactly one GPS IFD tag wasn't found: (%d)", foundGps)
|
||||
}
|
||||
|
||||
name, found := IfdTagNameWithId(IfdExif, ite.TagId)
|
||||
if found != true {
|
||||
t.Fatalf("could not find tag-ID for IOP IFD")
|
||||
} else if name != IfdIop {
|
||||
t.Fatalf("IOP IFD tag-ID mismatch: (0x%02x) [%s] != [%s]", ite.TagId, name, IfdIop)
|
||||
}
|
||||
}
|
||||
}
|
||||
foundIop := 0
|
||||
for _, ite := range lookup[exifIi][0].Entries {
|
||||
if ite.ChildIfdName == IfdIop {
|
||||
foundIop++
|
||||
|
||||
if foundIop != 1 {
|
||||
t.Fatalf("Exactly one IOP IFD tag wasn't found: (%d)", foundIop)
|
||||
}
|
||||
name, found := IfdTagNameWithId(IfdExif, ite.TagId)
|
||||
if found != true {
|
||||
t.Fatalf("could not find tag-ID for IOP IFD")
|
||||
} else if name != IfdIop {
|
||||
t.Fatalf("IOP IFD tag-ID mismatch: (0x%02x) [%s] != [%s]", ite.TagId, name, IfdIop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if foundIop != 1 {
|
||||
t.Fatalf("Exactly one IOP IFD tag wasn't found: (%d)", foundIop)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseExifHeader(t *testing.T) {
|
||||
eh, err := ParseExifHeader(testExifData)
|
||||
log.PanicIf(err)
|
||||
eh, err := ParseExifHeader(testExifData)
|
||||
log.PanicIf(err)
|
||||
|
||||
if eh.ByteOrder != binary.LittleEndian {
|
||||
t.Fatalf("Byte-order of EXIF header not correct.")
|
||||
} else if eh.FirstIfdOffset != 0x8 {
|
||||
t.Fatalf("First IFD offset not correct.")
|
||||
}
|
||||
if eh.ByteOrder != binary.LittleEndian {
|
||||
t.Fatalf("Byte-order of EXIF header not correct.")
|
||||
} else if eh.FirstIfdOffset != 0x8 {
|
||||
t.Fatalf("First IFD offset not correct.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExif_BuildAndParseExifHeader(t *testing.T) {
|
||||
headerBytes, err := BuildExifHeader(TestDefaultByteOrder, 0x11223344)
|
||||
log.PanicIf(err)
|
||||
headerBytes, err := BuildExifHeader(TestDefaultByteOrder, 0x11223344)
|
||||
log.PanicIf(err)
|
||||
|
||||
eh, err := ParseExifHeader(headerBytes)
|
||||
log.PanicIf(err)
|
||||
eh, err := ParseExifHeader(headerBytes)
|
||||
log.PanicIf(err)
|
||||
|
||||
if eh.ByteOrder != TestDefaultByteOrder {
|
||||
t.Fatalf("Byte-order of EXIF header not correct.")
|
||||
} else if eh.FirstIfdOffset != 0x11223344 {
|
||||
t.Fatalf("First IFD offset not correct.")
|
||||
}
|
||||
if eh.ByteOrder != TestDefaultByteOrder {
|
||||
t.Fatalf("Byte-order of EXIF header not correct.")
|
||||
} else if eh.FirstIfdOffset != 0x11223344 {
|
||||
t.Fatalf("First IFD offset not correct.")
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleBuildExifHeader() {
|
||||
headerBytes, err := BuildExifHeader(TestDefaultByteOrder, 0x11223344)
|
||||
log.PanicIf(err)
|
||||
headerBytes, err := BuildExifHeader(TestDefaultByteOrder, 0x11223344)
|
||||
log.PanicIf(err)
|
||||
|
||||
eh, err := ParseExifHeader(headerBytes)
|
||||
log.PanicIf(err)
|
||||
eh, err := ParseExifHeader(headerBytes)
|
||||
log.PanicIf(err)
|
||||
|
||||
fmt.Printf("%v\n", eh)
|
||||
// Output: ExifHeader<BYTE-ORDER=[BigEndian] FIRST-IFD-OFFSET=(0x11223344)>
|
||||
fmt.Printf("%v\n", eh)
|
||||
// Output: ExifHeader<BYTE-ORDER=[BigEndian] FIRST-IFD-OFFSET=(0x11223344)>
|
||||
}
|
||||
|
|
1508
ifd_builder.go
1508
ifd_builder.go
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -12,7 +12,8 @@ import (
|
|||
)
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -98,8 +99,10 @@ func TestAdd(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSetNextIb(t *testing.T) {
|
||||
ib1 := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ib2 := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
|
||||
ib1 := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
ib2 := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
if ib1.nextIb != nil {
|
||||
t.Fatalf("Next-IFD for IB1 not initially terminal.")
|
||||
|
@ -117,7 +120,8 @@ func TestSetNextIb(t *testing.T) {
|
|||
|
||||
func TestAddChildIb(t *testing.T) {
|
||||
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -131,7 +135,7 @@ func TestAddChildIb(t *testing.T) {
|
|||
|
||||
exifIi, _ := IfdIdOrFail(IfdStandard, IfdExif)
|
||||
|
||||
ibChild := NewIfdBuilder(exifIi, TestDefaultByteOrder)
|
||||
ibChild := NewIfdBuilder(ti, exifIi, TestDefaultByteOrder)
|
||||
err = ib.AddChildIb(ibChild)
|
||||
log.PanicIf(err)
|
||||
|
||||
|
@ -164,7 +168,8 @@ func TestAddTagsFromExisting(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
entries := make([]*IfdTagEntry, 3)
|
||||
|
||||
|
@ -192,8 +197,9 @@ func TestAddTagsFromExisting(t *testing.T) {
|
|||
}
|
||||
|
||||
ifd := &Ifd{
|
||||
Ii: RootIi,
|
||||
Entries: entries,
|
||||
Ii: RootIi,
|
||||
Entries: entries,
|
||||
tagIndex: ti,
|
||||
}
|
||||
|
||||
err := ib.AddTagsFromExisting(ifd, nil, nil, nil)
|
||||
|
@ -211,7 +217,8 @@ func TestAddTagsFromExisting(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAddTagsFromExisting__Includes(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
entries := make([]*IfdTagEntry, 3)
|
||||
|
||||
|
@ -235,8 +242,9 @@ func TestAddTagsFromExisting__Includes(t *testing.T) {
|
|||
}
|
||||
|
||||
ifd := &Ifd{
|
||||
Ii: RootIi,
|
||||
Entries: entries,
|
||||
Ii: RootIi,
|
||||
Entries: entries,
|
||||
tagIndex: ti,
|
||||
}
|
||||
|
||||
err := ib.AddTagsFromExisting(ifd, nil, []uint16{0x33}, nil)
|
||||
|
@ -250,7 +258,8 @@ func TestAddTagsFromExisting__Includes(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAddTagsFromExisting__Excludes(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
entries := make([]*IfdTagEntry, 3)
|
||||
|
||||
|
@ -274,8 +283,9 @@ func TestAddTagsFromExisting__Excludes(t *testing.T) {
|
|||
}
|
||||
|
||||
ifd := &Ifd{
|
||||
Ii: RootIi,
|
||||
Entries: entries,
|
||||
Ii: RootIi,
|
||||
Entries: entries,
|
||||
tagIndex: ti,
|
||||
}
|
||||
|
||||
err := ib.AddTagsFromExisting(ifd, nil, nil, []uint16{0x11})
|
||||
|
@ -289,7 +299,8 @@ func TestAddTagsFromExisting__Excludes(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFindN_First_1(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -339,7 +350,8 @@ func TestFindN_First_1(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFindN_First_2_1Returned(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -389,7 +401,8 @@ func TestFindN_First_2_1Returned(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFindN_First_2_2Returned(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -466,7 +479,8 @@ func TestFindN_First_2_2Returned(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFindN_Middle_WithDuplicates(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -546,7 +560,8 @@ func TestFindN_Middle_WithDuplicates(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFindN_Middle_NoDuplicates(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -606,7 +621,8 @@ func TestFindN_Middle_NoDuplicates(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFindN_Miss(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
found, err := ib.FindN(0x11, 1)
|
||||
log.PanicIf(err)
|
||||
|
@ -617,7 +633,8 @@ func TestFindN_Miss(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFind_Hit(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -675,7 +692,8 @@ func TestFind_Hit(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFind_Miss(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -726,7 +744,8 @@ func TestFind_Miss(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestReplace(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -788,7 +807,8 @@ func TestReplace(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestReplaceN(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -850,7 +870,8 @@ func TestReplaceN(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDeleteFirst(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -946,7 +967,8 @@ func TestDeleteFirst(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDeleteN(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -1042,7 +1064,8 @@ func TestDeleteN(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDeleteN_Two(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -1122,7 +1145,8 @@ func TestDeleteN_Two(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDeleteAll(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: RootIi,
|
||||
|
@ -1216,7 +1240,9 @@ func Test_IfdBuilder_CreateIfdBuilderFromExistingChain(t *testing.T) {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
itevr := NewIfdTagEntryValueResolver(rawExif, index.RootIfd.ByteOrder)
|
||||
|
@ -1296,7 +1322,9 @@ func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
|||
|
||||
// Decode from binary.
|
||||
|
||||
_, originalIndex, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, originalIndex, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
originalThumbnailData, err := originalIndex.RootIfd.NextIfd.Thumbnail()
|
||||
|
@ -1316,7 +1344,7 @@ func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
|||
|
||||
// Parse again.
|
||||
|
||||
_, recoveredIndex, err := Collect(updatedExif)
|
||||
_, recoveredIndex, err := Collect(ti, updatedExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
recoveredTags := recoveredIndex.RootIfd.DumpTags()
|
||||
|
@ -1400,143 +1428,145 @@ func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData_WithUpdate(t *testing.T) {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
// func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData_WithUpdate(t *testing.T) {
|
||||
// filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
// rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
// log.PanicIf(err)
|
||||
|
||||
// Decode from binary.
|
||||
// // Decode from binary.
|
||||
|
||||
_, originalIndex, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
// ti := NewTagIndex()
|
||||
|
||||
originalThumbnailData, err := originalIndex.RootIfd.NextIfd.Thumbnail()
|
||||
log.PanicIf(err)
|
||||
// _, originalIndex, err := Collect(ti, rawExif)
|
||||
// log.PanicIf(err)
|
||||
|
||||
originalTags := originalIndex.RootIfd.DumpTags()
|
||||
// originalThumbnailData, err := originalIndex.RootIfd.NextIfd.Thumbnail()
|
||||
// log.PanicIf(err)
|
||||
|
||||
// Encode back to binary.
|
||||
// originalTags := originalIndex.RootIfd.DumpTags()
|
||||
|
||||
ibe := NewIfdByteEncoder()
|
||||
// // Encode back to binary.
|
||||
|
||||
itevr := NewIfdTagEntryValueResolver(rawExif, originalIndex.RootIfd.ByteOrder)
|
||||
rootIb := NewIfdBuilderFromExistingChain(originalIndex.RootIfd, itevr)
|
||||
// ibe := NewIfdByteEncoder()
|
||||
|
||||
// Update a tag,.
|
||||
// itevr := NewIfdTagEntryValueResolver(rawExif, originalIndex.RootIfd.ByteOrder)
|
||||
// rootIb := NewIfdBuilderFromExistingChain(originalIndex.RootIfd, itevr)
|
||||
|
||||
exifBt, err := rootIb.FindTagWithName("ExifTag")
|
||||
log.PanicIf(err)
|
||||
// // Update a tag,.
|
||||
|
||||
ucBt, err := exifBt.value.Ib().FindTagWithName("UserComment")
|
||||
log.PanicIf(err)
|
||||
// exifBt, err := rootIb.FindTagWithName("ExifTag")
|
||||
// log.PanicIf(err)
|
||||
|
||||
uc := TagUnknownType_9298_UserComment{
|
||||
EncodingType: TagUnknownType_9298_UserComment_Encoding_ASCII,
|
||||
EncodingBytes: []byte("TEST COMMENT"),
|
||||
}
|
||||
// ucBt, err := exifBt.value.Ib().FindTagWithName("UserComment")
|
||||
// log.PanicIf(err)
|
||||
|
||||
err = ucBt.SetValue(rootIb.byteOrder, uc)
|
||||
log.PanicIf(err)
|
||||
// uc := TagUnknownType_9298_UserComment{
|
||||
// EncodingType: TagUnknownType_9298_UserComment_Encoding_ASCII,
|
||||
// EncodingBytes: []byte("TEST COMMENT"),
|
||||
// }
|
||||
|
||||
// Encode.
|
||||
// err = ucBt.SetValue(rootIb.byteOrder, uc)
|
||||
// log.PanicIf(err)
|
||||
|
||||
updatedExif, err := ibe.EncodeToExif(rootIb)
|
||||
log.PanicIf(err)
|
||||
// // Encode.
|
||||
|
||||
// Parse again.
|
||||
// updatedExif, err := ibe.EncodeToExif(rootIb)
|
||||
// log.PanicIf(err)
|
||||
|
||||
_, recoveredIndex, err := Collect(updatedExif)
|
||||
log.PanicIf(err)
|
||||
// // Parse again.
|
||||
|
||||
recoveredTags := recoveredIndex.RootIfd.DumpTags()
|
||||
// _, recoveredIndex, err := Collect(ti, updatedExif)
|
||||
// log.PanicIf(err)
|
||||
|
||||
recoveredThumbnailData, err := recoveredIndex.RootIfd.NextIfd.Thumbnail()
|
||||
log.PanicIf(err)
|
||||
// recoveredTags := recoveredIndex.RootIfd.DumpTags()
|
||||
|
||||
// Check the thumbnail.
|
||||
// recoveredThumbnailData, err := recoveredIndex.RootIfd.NextIfd.Thumbnail()
|
||||
// log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(recoveredThumbnailData, originalThumbnailData) != 0 {
|
||||
t.Fatalf("recovered thumbnail does not match original")
|
||||
}
|
||||
// // Check the thumbnail.
|
||||
|
||||
// Validate that all of the same IFDs were presented.
|
||||
// if bytes.Compare(recoveredThumbnailData, originalThumbnailData) != 0 {
|
||||
// t.Fatalf("recovered thumbnail does not match original")
|
||||
// }
|
||||
|
||||
originalIfdTags := make([][2]interface{}, 0)
|
||||
for _, ite := range originalTags {
|
||||
if ite.ChildIfdName != "" {
|
||||
originalIfdTags = append(originalIfdTags, [2]interface{}{ite.Ii, ite.TagId})
|
||||
}
|
||||
}
|
||||
// // Validate that all of the same IFDs were presented.
|
||||
|
||||
recoveredIfdTags := make([][2]interface{}, 0)
|
||||
for _, ite := range recoveredTags {
|
||||
if ite.ChildIfdName != "" {
|
||||
recoveredIfdTags = append(recoveredIfdTags, [2]interface{}{ite.Ii, ite.TagId})
|
||||
}
|
||||
}
|
||||
// originalIfdTags := make([][2]interface{}, 0)
|
||||
// for _, ite := range originalTags {
|
||||
// if ite.ChildIfdName != "" {
|
||||
// originalIfdTags = append(originalIfdTags, [2]interface{}{ite.Ii, ite.TagId})
|
||||
// }
|
||||
// }
|
||||
|
||||
if reflect.DeepEqual(recoveredIfdTags, originalIfdTags) != true {
|
||||
fmt.Printf("Original IFD tags:\n\n")
|
||||
// recoveredIfdTags := make([][2]interface{}, 0)
|
||||
// for _, ite := range recoveredTags {
|
||||
// if ite.ChildIfdName != "" {
|
||||
// recoveredIfdTags = append(recoveredIfdTags, [2]interface{}{ite.Ii, ite.TagId})
|
||||
// }
|
||||
// }
|
||||
|
||||
for i, x := range originalIfdTags {
|
||||
fmt.Printf(" %02d %v\n", i, x)
|
||||
}
|
||||
// if reflect.DeepEqual(recoveredIfdTags, originalIfdTags) != true {
|
||||
// fmt.Printf("Original IFD tags:\n\n")
|
||||
|
||||
fmt.Printf("\nRecovered IFD tags:\n\n")
|
||||
// for i, x := range originalIfdTags {
|
||||
// fmt.Printf(" %02d %v\n", i, x)
|
||||
// }
|
||||
|
||||
for i, x := range recoveredIfdTags {
|
||||
fmt.Printf(" %02d %v\n", i, x)
|
||||
}
|
||||
// fmt.Printf("\nRecovered IFD tags:\n\n")
|
||||
|
||||
fmt.Printf("\n")
|
||||
// for i, x := range recoveredIfdTags {
|
||||
// fmt.Printf(" %02d %v\n", i, x)
|
||||
// }
|
||||
|
||||
t.Fatalf("Recovered IFD tags are not correct.")
|
||||
}
|
||||
// fmt.Printf("\n")
|
||||
|
||||
// Validate that all of the tags owned by the IFDs were presented. Note
|
||||
// that the thumbnail tags are not kept but only produced on the fly, which
|
||||
// is why we check it above.
|
||||
// t.Fatalf("Recovered IFD tags are not correct.")
|
||||
// }
|
||||
|
||||
if len(recoveredTags) != len(originalTags) {
|
||||
t.Fatalf("Recovered tag-count does not match original.")
|
||||
}
|
||||
// // Validate that all of the tags owned by the IFDs were presented. Note
|
||||
// // that the thumbnail tags are not kept but only produced on the fly, which
|
||||
// // is why we check it above.
|
||||
|
||||
for i, recoveredIte := range recoveredTags {
|
||||
if recoveredIte.ChildIfdName != "" {
|
||||
continue
|
||||
}
|
||||
// if len(recoveredTags) != len(originalTags) {
|
||||
// t.Fatalf("Recovered tag-count does not match original.")
|
||||
// }
|
||||
|
||||
originalIte := originalTags[i]
|
||||
// for i, recoveredIte := range recoveredTags {
|
||||
// if recoveredIte.ChildIfdName != "" {
|
||||
// continue
|
||||
// }
|
||||
|
||||
if recoveredIte.Ii != originalIte.Ii {
|
||||
t.Fatalf("IfdIdentify not as expected: %s != %s ITE=%s", recoveredIte.Ii, originalIte.Ii, recoveredIte)
|
||||
} else if recoveredIte.TagId != originalIte.TagId {
|
||||
t.Fatalf("Tag-ID not as expected: %d != %d ITE=%s", recoveredIte.TagId, originalIte.TagId, recoveredIte)
|
||||
} else if recoveredIte.TagType != originalIte.TagType {
|
||||
t.Fatalf("Tag-type not as expected: %d != %d ITE=%s", recoveredIte.TagType, originalIte.TagType, recoveredIte)
|
||||
}
|
||||
// originalIte := originalTags[i]
|
||||
|
||||
originalValueBytes, err := originalIte.ValueBytes(originalIndex.RootIfd.addressableData, originalIndex.RootIfd.ByteOrder)
|
||||
log.PanicIf(err)
|
||||
// if recoveredIte.Ii != originalIte.Ii {
|
||||
// t.Fatalf("IfdIdentify not as expected: %s != %s ITE=%s", recoveredIte.Ii, originalIte.Ii, recoveredIte)
|
||||
// } else if recoveredIte.TagId != originalIte.TagId {
|
||||
// t.Fatalf("Tag-ID not as expected: %d != %d ITE=%s", recoveredIte.TagId, originalIte.TagId, recoveredIte)
|
||||
// } else if recoveredIte.TagType != originalIte.TagType {
|
||||
// t.Fatalf("Tag-type not as expected: %d != %d ITE=%s", recoveredIte.TagType, originalIte.TagType, recoveredIte)
|
||||
// }
|
||||
|
||||
recoveredValueBytes, err := recoveredIte.ValueBytes(recoveredIndex.RootIfd.addressableData, recoveredIndex.RootIfd.ByteOrder)
|
||||
log.PanicIf(err)
|
||||
// originalValueBytes, err := originalIte.ValueBytes(originalIndex.RootIfd.addressableData, originalIndex.RootIfd.ByteOrder)
|
||||
// log.PanicIf(err)
|
||||
|
||||
if recoveredIte.TagId == 0x9286 {
|
||||
expectedValueBytes := make([]byte, 0)
|
||||
// recoveredValueBytes, err := recoveredIte.ValueBytes(recoveredIndex.RootIfd.addressableData, recoveredIndex.RootIfd.ByteOrder)
|
||||
// log.PanicIf(err)
|
||||
|
||||
expectedValueBytes = append(expectedValueBytes, []byte{'A', 'S', 'C', 'I', 'I', 0, 0, 0}...)
|
||||
expectedValueBytes = append(expectedValueBytes, []byte("TEST COMMENT")...)
|
||||
// if recoveredIte.TagId == 0x9286 {
|
||||
// expectedValueBytes := make([]byte, 0)
|
||||
|
||||
if bytes.Compare(recoveredValueBytes, expectedValueBytes) != 0 {
|
||||
t.Fatalf("Recovered UserComment does not have the right value: %v != %v", recoveredValueBytes, expectedValueBytes)
|
||||
}
|
||||
} else if bytes.Compare(recoveredValueBytes, originalValueBytes) != 0 {
|
||||
t.Fatalf("bytes of tag content not correct: %v != %v ITE=%s", recoveredValueBytes, originalValueBytes, recoveredIte)
|
||||
}
|
||||
}
|
||||
}
|
||||
// expectedValueBytes = append(expectedValueBytes, []byte{'A', 'S', 'C', 'I', 'I', 0, 0, 0}...)
|
||||
// expectedValueBytes = append(expectedValueBytes, []byte("TEST COMMENT")...)
|
||||
|
||||
// if bytes.Compare(recoveredValueBytes, expectedValueBytes) != 0 {
|
||||
// t.Fatalf("Recovered UserComment does not have the right value: %v != %v", recoveredValueBytes, expectedValueBytes)
|
||||
// }
|
||||
// } else if bytes.Compare(recoveredValueBytes, originalValueBytes) != 0 {
|
||||
// t.Fatalf("bytes of tag content not correct: %v != %v ITE=%s", recoveredValueBytes, originalValueBytes, recoveredIte)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
func ExampleIfd_Thumbnail() {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
@ -1544,7 +1574,9 @@ func ExampleIfd_Thumbnail() {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
thumbnailData, err := index.RootIfd.NextIfd.Thumbnail()
|
||||
|
@ -1560,7 +1592,9 @@ func ExampleBuilderTag_SetValue() {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
// Create builder.
|
||||
|
@ -1599,11 +1633,14 @@ func ExampleBuilderTag_SetValue() {
|
|||
}
|
||||
|
||||
func Test_IfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) {
|
||||
ti := NewTagIndex()
|
||||
|
||||
tagId := IfdTagIdWithIdentityOrFail(GpsIi)
|
||||
|
||||
parentIfd := &Ifd{
|
||||
Ii: RootIi,
|
||||
Name: IfdStandard,
|
||||
Ii: RootIi,
|
||||
Name: IfdStandard,
|
||||
tagIndex: ti,
|
||||
}
|
||||
|
||||
ifd := &Ifd{
|
||||
|
@ -1612,6 +1649,7 @@ func Test_IfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) {
|
|||
ByteOrder: TestDefaultByteOrder,
|
||||
Offset: 0x123,
|
||||
ParentIfd: parentIfd,
|
||||
tagIndex: ti,
|
||||
}
|
||||
|
||||
ib := NewIfdBuilderWithExistingIfd(ifd)
|
||||
|
@ -1628,7 +1666,12 @@ func Test_IfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNewStandardBuilderTag_OneUnit(t *testing.T) {
|
||||
bt := NewStandardBuilderTag(ExifIi, uint16(0x8833), TestDefaultByteOrder, []uint32{uint32(0x1234)})
|
||||
ti := NewTagIndex()
|
||||
|
||||
it, err := ti.Get(ExifIi, uint16(0x8833))
|
||||
log.PanicIf(err)
|
||||
|
||||
bt := NewStandardBuilderTag(ExifIi, it, TestDefaultByteOrder, []uint32{uint32(0x1234)})
|
||||
|
||||
if bt.ii != ExifIi {
|
||||
t.Fatalf("II in BuilderTag not correct")
|
||||
|
@ -1640,21 +1683,12 @@ func TestNewStandardBuilderTag_OneUnit(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNewStandardBuilderTag_TwoUnits(t *testing.T) {
|
||||
bt := NewStandardBuilderTag(ExifIi, uint16(0x8833), TestDefaultByteOrder, []uint32{uint32(0x1234), uint32(0x5678)})
|
||||
ti := NewTagIndex()
|
||||
|
||||
if bt.ii != ExifIi {
|
||||
t.Fatalf("II in BuilderTag not correct")
|
||||
} else if bt.tagId != 0x8833 {
|
||||
t.Fatalf("tag-ID not correct")
|
||||
} else if bytes.Compare(bt.value.Bytes(), []byte{
|
||||
0x0, 0x0, 0x12, 0x34,
|
||||
0x0, 0x0, 0x56, 0x78}) != 0 {
|
||||
t.Fatalf("value not correct")
|
||||
}
|
||||
}
|
||||
it, err := ti.Get(ExifIi, uint16(0x8833))
|
||||
log.PanicIf(err)
|
||||
|
||||
func TestNewStandardBuilderTagWithName(t *testing.T) {
|
||||
bt := NewStandardBuilderTagWithName(ExifIi, "ISOSpeed", TestDefaultByteOrder, []uint32{uint32(0x1234), uint32(0x5678)})
|
||||
bt := NewStandardBuilderTag(ExifIi, it, TestDefaultByteOrder, []uint32{uint32(0x1234), uint32(0x5678)})
|
||||
|
||||
if bt.ii != ExifIi {
|
||||
t.Fatalf("II in BuilderTag not correct")
|
||||
|
@ -1668,7 +1702,8 @@ func TestNewStandardBuilderTagWithName(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAddStandardWithName(t *testing.T) {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
err := ib.AddStandardWithName("ProcessingSoftware", "some software")
|
||||
log.PanicIf(err)
|
||||
|
|
1659
ifd_enumerate.go
1659
ifd_enumerate.go
File diff suppressed because it is too large
Load Diff
|
@ -1,526 +1,550 @@
|
|||
package exif
|
||||
|
||||
import (
|
||||
"path"
|
||||
"testing"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
func TestIfdTagEntry_ValueBytes(t *testing.T) {
|
||||
byteOrder := binary.BigEndian
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
byteOrder := binary.BigEndian
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
original := []byte("original text")
|
||||
original := []byte("original text")
|
||||
|
||||
ed, err := ve.encodeBytes(original)
|
||||
log.PanicIf(err)
|
||||
ed, err := ve.encodeBytes(original)
|
||||
log.PanicIf(err)
|
||||
|
||||
// Now, pass the raw encoded value as if it was the entire addressable area
|
||||
// and provide an offset of 0 as if it was a real block of data and this
|
||||
// value happened to be recorded at the beginning.
|
||||
// Now, pass the raw encoded value as if it was the entire addressable area
|
||||
// and provide an offset of 0 as if it was a real block of data and this
|
||||
// value happened to be recorded at the beginning.
|
||||
|
||||
ite := IfdTagEntry{
|
||||
TagType: TypeByte,
|
||||
UnitCount: uint32(len(original)),
|
||||
ValueOffset: 0,
|
||||
}
|
||||
ite := IfdTagEntry{
|
||||
TagType: TypeByte,
|
||||
UnitCount: uint32(len(original)),
|
||||
ValueOffset: 0,
|
||||
}
|
||||
|
||||
decodedBytes, err := ite.ValueBytes(ed.Encoded, byteOrder)
|
||||
log.PanicIf(err)
|
||||
decodedBytes, err := ite.ValueBytes(ed.Encoded, byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(decodedBytes, original) != 0 {
|
||||
t.Fatalf("Bytes not decoded correctly.")
|
||||
}
|
||||
if bytes.Compare(decodedBytes, original) != 0 {
|
||||
t.Fatalf("Bytes not decoded correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagEntry_ValueBytes_RealData(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Test failure.")
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Test failure.")
|
||||
}
|
||||
}()
|
||||
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
eh, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
var ite *IfdTagEntry
|
||||
for _, thisIte := range index.RootIfd.Entries {
|
||||
if thisIte.TagId == 0x0110 {
|
||||
ite = thisIte
|
||||
break
|
||||
}
|
||||
}
|
||||
eh, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
if ite == nil {
|
||||
t.Fatalf("Tag not found.")
|
||||
}
|
||||
var ite *IfdTagEntry
|
||||
for _, thisIte := range index.RootIfd.Entries {
|
||||
if thisIte.TagId == 0x0110 {
|
||||
ite = thisIte
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
addressableData := rawExif[ExifAddressableAreaStart:]
|
||||
decodedBytes, err := ite.ValueBytes(addressableData, eh.ByteOrder)
|
||||
log.PanicIf(err)
|
||||
if ite == nil {
|
||||
t.Fatalf("Tag not found.")
|
||||
}
|
||||
|
||||
expected := []byte("Canon EOS 5D Mark III")
|
||||
expected = append(expected, 0)
|
||||
addressableData := rawExif[ExifAddressableAreaStart:]
|
||||
decodedBytes, err := ite.ValueBytes(addressableData, eh.ByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if len(decodedBytes) != int(ite.UnitCount) {
|
||||
t.Fatalf("Decoded bytes not the right count.")
|
||||
} else if bytes.Compare(decodedBytes, expected) != 0 {
|
||||
t.Fatalf("Decoded bytes not correct.")
|
||||
}
|
||||
expected := []byte("Canon EOS 5D Mark III")
|
||||
expected = append(expected, 0)
|
||||
|
||||
if len(decodedBytes) != int(ite.UnitCount) {
|
||||
t.Fatalf("Decoded bytes not the right count.")
|
||||
} else if bytes.Compare(decodedBytes, expected) != 0 {
|
||||
t.Fatalf("Decoded bytes not correct.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagEntry_Resolver_ValueBytes(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Test failure.")
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Test failure.")
|
||||
}
|
||||
}()
|
||||
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
eh, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
var ite *IfdTagEntry
|
||||
for _, thisIte := range index.RootIfd.Entries {
|
||||
if thisIte.TagId == 0x0110 {
|
||||
ite = thisIte
|
||||
break
|
||||
}
|
||||
}
|
||||
eh, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
if ite == nil {
|
||||
t.Fatalf("Tag not found.")
|
||||
}
|
||||
var ite *IfdTagEntry
|
||||
for _, thisIte := range index.RootIfd.Entries {
|
||||
if thisIte.TagId == 0x0110 {
|
||||
ite = thisIte
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
itevr := NewIfdTagEntryValueResolver(rawExif, eh.ByteOrder)
|
||||
if ite == nil {
|
||||
t.Fatalf("Tag not found.")
|
||||
}
|
||||
|
||||
decodedBytes, err := itevr.ValueBytes(ite)
|
||||
log.PanicIf(err)
|
||||
itevr := NewIfdTagEntryValueResolver(rawExif, eh.ByteOrder)
|
||||
|
||||
expected := []byte("Canon EOS 5D Mark III")
|
||||
expected = append(expected, 0)
|
||||
decodedBytes, err := itevr.ValueBytes(ite)
|
||||
log.PanicIf(err)
|
||||
|
||||
if len(decodedBytes) != int(ite.UnitCount) {
|
||||
t.Fatalf("Decoded bytes not the right count.")
|
||||
} else if bytes.Compare(decodedBytes, expected) != 0 {
|
||||
t.Fatalf("Decoded bytes not correct.")
|
||||
}
|
||||
expected := []byte("Canon EOS 5D Mark III")
|
||||
expected = append(expected, 0)
|
||||
|
||||
if len(decodedBytes) != int(ite.UnitCount) {
|
||||
t.Fatalf("Decoded bytes not the right count.")
|
||||
} else if bytes.Compare(decodedBytes, expected) != 0 {
|
||||
t.Fatalf("Decoded bytes not correct.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagEntry_Resolver_ValueBytes__Unknown_Field_And_Nonroot_Ifd(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Test failure.")
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Test failure.")
|
||||
}
|
||||
}()
|
||||
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
eh, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
ii, _ := IfdIdOrFail(IfdStandard, IfdExif)
|
||||
ifdExif := index.Lookup[ii][0]
|
||||
eh, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
var ite *IfdTagEntry
|
||||
for _, thisIte := range ifdExif.Entries {
|
||||
if thisIte.TagId == 0x9000 {
|
||||
ite = thisIte
|
||||
break
|
||||
}
|
||||
}
|
||||
ii, _ := IfdIdOrFail(IfdStandard, IfdExif)
|
||||
ifdExif := index.Lookup[ii][0]
|
||||
|
||||
if ite == nil {
|
||||
t.Fatalf("Tag not found.")
|
||||
}
|
||||
var ite *IfdTagEntry
|
||||
for _, thisIte := range ifdExif.Entries {
|
||||
if thisIte.TagId == 0x9000 {
|
||||
ite = thisIte
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
itevr := NewIfdTagEntryValueResolver(rawExif, eh.ByteOrder)
|
||||
if ite == nil {
|
||||
t.Fatalf("Tag not found.")
|
||||
}
|
||||
|
||||
decodedBytes, err := itevr.ValueBytes(ite)
|
||||
log.PanicIf(err)
|
||||
itevr := NewIfdTagEntryValueResolver(rawExif, eh.ByteOrder)
|
||||
|
||||
expected := []byte { '0', '2', '3', '0' }
|
||||
decodedBytes, err := itevr.ValueBytes(ite)
|
||||
log.PanicIf(err)
|
||||
|
||||
if len(decodedBytes) != int(ite.UnitCount) {
|
||||
t.Fatalf("Decoded bytes not the right count.")
|
||||
} else if bytes.Compare(decodedBytes, expected) != 0 {
|
||||
t.Fatalf("Recovered unknown value is not correct.")
|
||||
}
|
||||
expected := []byte{'0', '2', '3', '0'}
|
||||
|
||||
if len(decodedBytes) != int(ite.UnitCount) {
|
||||
t.Fatalf("Decoded bytes not the right count.")
|
||||
} else if bytes.Compare(decodedBytes, expected) != 0 {
|
||||
t.Fatalf("Recovered unknown value is not correct.")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Ifd_FindTagWithId_Hit(t *testing.T) {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
ifd := index.RootIfd
|
||||
results, err := ifd.FindTagWithId(0x011b)
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
if len(results) != 1 {
|
||||
t.Fatalf("Exactly one result was not found: (%d)", len(results))
|
||||
} else if results[0].TagId != 0x011b {
|
||||
t.Fatalf("The result was not expected: %v", results[0])
|
||||
}
|
||||
ifd := index.RootIfd
|
||||
results, err := ifd.FindTagWithId(0x011b)
|
||||
|
||||
if len(results) != 1 {
|
||||
t.Fatalf("Exactly one result was not found: (%d)", len(results))
|
||||
} else if results[0].TagId != 0x011b {
|
||||
t.Fatalf("The result was not expected: %v", results[0])
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Ifd_FindTagWithId_Miss(t *testing.T) {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
ifd := index.RootIfd
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, err = ifd.FindTagWithId(0xffff)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error for not-found tag.")
|
||||
} else if log.Is(err, ErrTagNotFound) == false {
|
||||
log.Panic(err)
|
||||
}
|
||||
ifd := index.RootIfd
|
||||
|
||||
_, err = ifd.FindTagWithId(0xffff)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error for not-found tag.")
|
||||
} else if log.Is(err, ErrTagNotFound) == false {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Ifd_FindTagWithName_Hit(t *testing.T) {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
ifd := index.RootIfd
|
||||
results, err := ifd.FindTagWithName("YResolution")
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
if len(results) != 1 {
|
||||
t.Fatalf("Exactly one result was not found: (%d)", len(results))
|
||||
} else if results[0].TagId != 0x011b {
|
||||
t.Fatalf("The result was not expected: %v", results[0])
|
||||
}
|
||||
ifd := index.RootIfd
|
||||
results, err := ifd.FindTagWithName("YResolution")
|
||||
|
||||
if len(results) != 1 {
|
||||
t.Fatalf("Exactly one result was not found: (%d)", len(results))
|
||||
} else if results[0].TagId != 0x011b {
|
||||
t.Fatalf("The result was not expected: %v", results[0])
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Ifd_FindTagWithName_Miss(t *testing.T) {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
ifd := index.RootIfd
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, err = ifd.FindTagWithName("PlanarConfiguration")
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error for not-found tag.")
|
||||
} else if log.Is(err, ErrTagNotFound) == false {
|
||||
log.Panic(err)
|
||||
}
|
||||
ifd := index.RootIfd
|
||||
|
||||
_, err = ifd.FindTagWithName("PlanarConfiguration")
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error for not-found tag.")
|
||||
} else if log.Is(err, ErrTagNotFound) == false {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Ifd_FindTagWithName_NonStandard(t *testing.T) {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
ifd := index.RootIfd
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, err = ifd.FindTagWithName("GeorgeNotAtHome")
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error for not-found tag.")
|
||||
} else if log.Is(err, ErrTagNotStandard) == false {
|
||||
log.Panic(err)
|
||||
}
|
||||
ifd := index.RootIfd
|
||||
|
||||
_, err = ifd.FindTagWithName("GeorgeNotAtHome")
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error for not-found tag.")
|
||||
} else if log.Is(err, ErrTagNotStandard) == false {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Ifd_Thumbnail(t *testing.T) {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
ifd := index.RootIfd
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
if ifd.NextIfd == nil {
|
||||
t.Fatalf("There is no IFD1.")
|
||||
}
|
||||
ifd := index.RootIfd
|
||||
|
||||
// The thumbnail is in IFD1 (The second root IFD).
|
||||
actual, err := ifd.NextIfd.Thumbnail()
|
||||
log.PanicIf(err)
|
||||
if ifd.NextIfd == nil {
|
||||
t.Fatalf("There is no IFD1.")
|
||||
}
|
||||
|
||||
expectedFilepath := path.Join(assetsPath, "NDM_8901.jpg.thumbnail")
|
||||
// The thumbnail is in IFD1 (The second root IFD).
|
||||
actual, err := ifd.NextIfd.Thumbnail()
|
||||
log.PanicIf(err)
|
||||
|
||||
expected, err := ioutil.ReadFile(expectedFilepath)
|
||||
log.PanicIf(err)
|
||||
expectedFilepath := path.Join(assetsPath, "NDM_8901.jpg.thumbnail")
|
||||
|
||||
if bytes.Compare(actual, expected) != 0 {
|
||||
t.Fatalf("thumbnail not correct")
|
||||
}
|
||||
expected, err := ioutil.ReadFile(expectedFilepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(actual, expected) != 0 {
|
||||
t.Fatalf("thumbnail not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfd_GpsInfo(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Test failure.")
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Test failure.")
|
||||
}
|
||||
}()
|
||||
|
||||
filepath := path.Join(assetsPath, "gps.jpg")
|
||||
filepath := path.Join(assetsPath, "gps.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
ifd, err := index.RootIfd.ChildWithIfdIdentity(GpsIi)
|
||||
log.PanicIf(err)
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
gi, err := ifd.GpsInfo()
|
||||
log.PanicIf(err)
|
||||
ifd, err := index.RootIfd.ChildWithIfdIdentity(GpsIi)
|
||||
log.PanicIf(err)
|
||||
|
||||
if gi.Latitude.Orientation != 'N' || gi.Latitude.Degrees != 26 || gi.Latitude.Minutes != 35 || gi.Latitude.Seconds != 12 {
|
||||
t.Fatalf("latitude not correct")
|
||||
} else if gi.Longitude.Orientation != 'W' || gi.Longitude.Degrees != 80 || gi.Longitude.Minutes != 3 || gi.Longitude.Seconds != 13 {
|
||||
t.Fatalf("longitude not correct")
|
||||
} else if gi.Altitude != 0 {
|
||||
t.Fatalf("altitude not correct")
|
||||
} else if gi.Timestamp.Unix() != 1524964977 {
|
||||
t.Fatalf("timestamp not correct")
|
||||
} else if gi.Altitude != 0 {
|
||||
t.Fatalf("altitude not correct")
|
||||
}
|
||||
gi, err := ifd.GpsInfo()
|
||||
log.PanicIf(err)
|
||||
|
||||
if gi.Latitude.Orientation != 'N' || gi.Latitude.Degrees != 26 || gi.Latitude.Minutes != 35 || gi.Latitude.Seconds != 12 {
|
||||
t.Fatalf("latitude not correct")
|
||||
} else if gi.Longitude.Orientation != 'W' || gi.Longitude.Degrees != 80 || gi.Longitude.Minutes != 3 || gi.Longitude.Seconds != 13 {
|
||||
t.Fatalf("longitude not correct")
|
||||
} else if gi.Altitude != 0 {
|
||||
t.Fatalf("altitude not correct")
|
||||
} else if gi.Timestamp.Unix() != 1524964977 {
|
||||
t.Fatalf("timestamp not correct")
|
||||
} else if gi.Altitude != 0 {
|
||||
t.Fatalf("altitude not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfd_EnumerateTagsRecursively(t *testing.T) {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
collected := make([][2]interface{}, 0)
|
||||
collected := make([][2]interface{}, 0)
|
||||
|
||||
cb := func(ifd *Ifd, ite *IfdTagEntry) error {
|
||||
item := [2]interface{} {
|
||||
ifd.Ii.IfdName,
|
||||
int(ite.TagId),
|
||||
}
|
||||
cb := func(ifd *Ifd, ite *IfdTagEntry) error {
|
||||
item := [2]interface{}{
|
||||
ifd.Ii.IfdName,
|
||||
int(ite.TagId),
|
||||
}
|
||||
|
||||
collected = append(collected, item)
|
||||
collected = append(collected, item)
|
||||
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
err = index.RootIfd.EnumerateTagsRecursively(cb)
|
||||
log.PanicIf(err)
|
||||
err = index.RootIfd.EnumerateTagsRecursively(cb)
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := [][2]interface{} {
|
||||
[2]interface{} { "IFD", 0x010f },
|
||||
[2]interface{} { "IFD", 0x0110 },
|
||||
[2]interface{} { "IFD", 0x0112 },
|
||||
[2]interface{} { "IFD", 0x011a },
|
||||
[2]interface{} { "IFD", 0x011b },
|
||||
[2]interface{} { "IFD", 0x0128 },
|
||||
[2]interface{} { "IFD", 0x0132 },
|
||||
[2]interface{} { "IFD", 0x013b },
|
||||
[2]interface{} { "IFD", 0x0213 },
|
||||
[2]interface{} { "IFD", 0x8298 },
|
||||
[2]interface{} { "Exif", 0x829a },
|
||||
[2]interface{} { "Exif", 0x829d },
|
||||
[2]interface{} { "Exif", 0x8822 },
|
||||
[2]interface{} { "Exif", 0x8827 },
|
||||
[2]interface{} { "Exif", 0x8830 },
|
||||
[2]interface{} { "Exif", 0x8832 },
|
||||
[2]interface{} { "Exif", 0x9000 },
|
||||
[2]interface{} { "Exif", 0x9003 },
|
||||
[2]interface{} { "Exif", 0x9004 },
|
||||
[2]interface{} { "Exif", 0x9101 },
|
||||
[2]interface{} { "Exif", 0x9201 },
|
||||
[2]interface{} { "Exif", 0x9202 },
|
||||
[2]interface{} { "Exif", 0x9204 },
|
||||
[2]interface{} { "Exif", 0x9207 },
|
||||
[2]interface{} { "Exif", 0x9209 },
|
||||
[2]interface{} { "Exif", 0x920a },
|
||||
[2]interface{} { "Exif", 0x927c },
|
||||
[2]interface{} { "Exif", 0x9286 },
|
||||
[2]interface{} { "Exif", 0x9290 },
|
||||
[2]interface{} { "Exif", 0x9291 },
|
||||
[2]interface{} { "Exif", 0x9292 },
|
||||
[2]interface{} { "Exif", 0xa000 },
|
||||
[2]interface{} { "Exif", 0xa001 },
|
||||
[2]interface{} { "Exif", 0xa002 },
|
||||
[2]interface{} { "Exif", 0xa003 },
|
||||
[2]interface{} { "Iop", 0x0001 },
|
||||
[2]interface{} { "Iop", 0x0002 },
|
||||
[2]interface{} { "Exif", 0xa20e },
|
||||
[2]interface{} { "Exif", 0xa20f },
|
||||
[2]interface{} { "Exif", 0xa210 },
|
||||
[2]interface{} { "Exif", 0xa401 },
|
||||
[2]interface{} { "Exif", 0xa402 },
|
||||
[2]interface{} { "Exif", 0xa403 },
|
||||
[2]interface{} { "Exif", 0xa406 },
|
||||
[2]interface{} { "Exif", 0xa430 },
|
||||
[2]interface{} { "Exif", 0xa431 },
|
||||
[2]interface{} { "Exif", 0xa432 },
|
||||
[2]interface{} { "Exif", 0xa434 },
|
||||
[2]interface{} { "Exif", 0xa435 },
|
||||
[2]interface{} { "GPSInfo", 0x0000 },
|
||||
[2]interface{} { "IFD", 0x010f },
|
||||
[2]interface{} { "IFD", 0x0110 },
|
||||
[2]interface{} { "IFD", 0x0112 },
|
||||
[2]interface{} { "IFD", 0x011a },
|
||||
[2]interface{} { "IFD", 0x011b },
|
||||
[2]interface{} { "IFD", 0x0128 },
|
||||
[2]interface{} { "IFD", 0x0132 },
|
||||
[2]interface{} { "IFD", 0x013b },
|
||||
[2]interface{} { "IFD", 0x0213 },
|
||||
[2]interface{} { "IFD", 0x8298 },
|
||||
[2]interface{} { "Exif", 0x829a },
|
||||
[2]interface{} { "Exif", 0x829d },
|
||||
[2]interface{} { "Exif", 0x8822 },
|
||||
[2]interface{} { "Exif", 0x8827 },
|
||||
[2]interface{} { "Exif", 0x8830 },
|
||||
[2]interface{} { "Exif", 0x8832 },
|
||||
[2]interface{} { "Exif", 0x9000 },
|
||||
[2]interface{} { "Exif", 0x9003 },
|
||||
[2]interface{} { "Exif", 0x9004 },
|
||||
[2]interface{} { "Exif", 0x9101 },
|
||||
[2]interface{} { "Exif", 0x9201 },
|
||||
[2]interface{} { "Exif", 0x9202 },
|
||||
[2]interface{} { "Exif", 0x9204 },
|
||||
[2]interface{} { "Exif", 0x9207 },
|
||||
[2]interface{} { "Exif", 0x9209 },
|
||||
[2]interface{} { "Exif", 0x920a },
|
||||
[2]interface{} { "Exif", 0x927c },
|
||||
[2]interface{} { "Exif", 0x9286 },
|
||||
[2]interface{} { "Exif", 0x9290 },
|
||||
[2]interface{} { "Exif", 0x9291 },
|
||||
[2]interface{} { "Exif", 0x9292 },
|
||||
[2]interface{} { "Exif", 0xa000 },
|
||||
[2]interface{} { "Exif", 0xa001 },
|
||||
[2]interface{} { "Exif", 0xa002 },
|
||||
[2]interface{} { "Exif", 0xa003 },
|
||||
[2]interface{} { "Iop", 0x0001 },
|
||||
[2]interface{} { "Iop", 0x0002 },
|
||||
[2]interface{} { "Exif", 0xa20e },
|
||||
[2]interface{} { "Exif", 0xa20f },
|
||||
[2]interface{} { "Exif", 0xa210 },
|
||||
[2]interface{} { "Exif", 0xa401 },
|
||||
[2]interface{} { "Exif", 0xa402 },
|
||||
[2]interface{} { "Exif", 0xa403 },
|
||||
[2]interface{} { "Exif", 0xa406 },
|
||||
[2]interface{} { "Exif", 0xa430 },
|
||||
[2]interface{} { "Exif", 0xa431 },
|
||||
[2]interface{} { "Exif", 0xa432 },
|
||||
[2]interface{} { "Exif", 0xa434 },
|
||||
[2]interface{} { "Exif", 0xa435 },
|
||||
[2]interface{} { "GPSInfo", 0x0000 },
|
||||
}
|
||||
expected := [][2]interface{}{
|
||||
[2]interface{}{"IFD", 0x010f},
|
||||
[2]interface{}{"IFD", 0x0110},
|
||||
[2]interface{}{"IFD", 0x0112},
|
||||
[2]interface{}{"IFD", 0x011a},
|
||||
[2]interface{}{"IFD", 0x011b},
|
||||
[2]interface{}{"IFD", 0x0128},
|
||||
[2]interface{}{"IFD", 0x0132},
|
||||
[2]interface{}{"IFD", 0x013b},
|
||||
[2]interface{}{"IFD", 0x0213},
|
||||
[2]interface{}{"IFD", 0x8298},
|
||||
[2]interface{}{"Exif", 0x829a},
|
||||
[2]interface{}{"Exif", 0x829d},
|
||||
[2]interface{}{"Exif", 0x8822},
|
||||
[2]interface{}{"Exif", 0x8827},
|
||||
[2]interface{}{"Exif", 0x8830},
|
||||
[2]interface{}{"Exif", 0x8832},
|
||||
[2]interface{}{"Exif", 0x9000},
|
||||
[2]interface{}{"Exif", 0x9003},
|
||||
[2]interface{}{"Exif", 0x9004},
|
||||
[2]interface{}{"Exif", 0x9101},
|
||||
[2]interface{}{"Exif", 0x9201},
|
||||
[2]interface{}{"Exif", 0x9202},
|
||||
[2]interface{}{"Exif", 0x9204},
|
||||
[2]interface{}{"Exif", 0x9207},
|
||||
[2]interface{}{"Exif", 0x9209},
|
||||
[2]interface{}{"Exif", 0x920a},
|
||||
[2]interface{}{"Exif", 0x927c},
|
||||
[2]interface{}{"Exif", 0x9286},
|
||||
[2]interface{}{"Exif", 0x9290},
|
||||
[2]interface{}{"Exif", 0x9291},
|
||||
[2]interface{}{"Exif", 0x9292},
|
||||
[2]interface{}{"Exif", 0xa000},
|
||||
[2]interface{}{"Exif", 0xa001},
|
||||
[2]interface{}{"Exif", 0xa002},
|
||||
[2]interface{}{"Exif", 0xa003},
|
||||
[2]interface{}{"Iop", 0x0001},
|
||||
[2]interface{}{"Iop", 0x0002},
|
||||
[2]interface{}{"Exif", 0xa20e},
|
||||
[2]interface{}{"Exif", 0xa20f},
|
||||
[2]interface{}{"Exif", 0xa210},
|
||||
[2]interface{}{"Exif", 0xa401},
|
||||
[2]interface{}{"Exif", 0xa402},
|
||||
[2]interface{}{"Exif", 0xa403},
|
||||
[2]interface{}{"Exif", 0xa406},
|
||||
[2]interface{}{"Exif", 0xa430},
|
||||
[2]interface{}{"Exif", 0xa431},
|
||||
[2]interface{}{"Exif", 0xa432},
|
||||
[2]interface{}{"Exif", 0xa434},
|
||||
[2]interface{}{"Exif", 0xa435},
|
||||
[2]interface{}{"GPSInfo", 0x0000},
|
||||
[2]interface{}{"IFD", 0x010f},
|
||||
[2]interface{}{"IFD", 0x0110},
|
||||
[2]interface{}{"IFD", 0x0112},
|
||||
[2]interface{}{"IFD", 0x011a},
|
||||
[2]interface{}{"IFD", 0x011b},
|
||||
[2]interface{}{"IFD", 0x0128},
|
||||
[2]interface{}{"IFD", 0x0132},
|
||||
[2]interface{}{"IFD", 0x013b},
|
||||
[2]interface{}{"IFD", 0x0213},
|
||||
[2]interface{}{"IFD", 0x8298},
|
||||
[2]interface{}{"Exif", 0x829a},
|
||||
[2]interface{}{"Exif", 0x829d},
|
||||
[2]interface{}{"Exif", 0x8822},
|
||||
[2]interface{}{"Exif", 0x8827},
|
||||
[2]interface{}{"Exif", 0x8830},
|
||||
[2]interface{}{"Exif", 0x8832},
|
||||
[2]interface{}{"Exif", 0x9000},
|
||||
[2]interface{}{"Exif", 0x9003},
|
||||
[2]interface{}{"Exif", 0x9004},
|
||||
[2]interface{}{"Exif", 0x9101},
|
||||
[2]interface{}{"Exif", 0x9201},
|
||||
[2]interface{}{"Exif", 0x9202},
|
||||
[2]interface{}{"Exif", 0x9204},
|
||||
[2]interface{}{"Exif", 0x9207},
|
||||
[2]interface{}{"Exif", 0x9209},
|
||||
[2]interface{}{"Exif", 0x920a},
|
||||
[2]interface{}{"Exif", 0x927c},
|
||||
[2]interface{}{"Exif", 0x9286},
|
||||
[2]interface{}{"Exif", 0x9290},
|
||||
[2]interface{}{"Exif", 0x9291},
|
||||
[2]interface{}{"Exif", 0x9292},
|
||||
[2]interface{}{"Exif", 0xa000},
|
||||
[2]interface{}{"Exif", 0xa001},
|
||||
[2]interface{}{"Exif", 0xa002},
|
||||
[2]interface{}{"Exif", 0xa003},
|
||||
[2]interface{}{"Iop", 0x0001},
|
||||
[2]interface{}{"Iop", 0x0002},
|
||||
[2]interface{}{"Exif", 0xa20e},
|
||||
[2]interface{}{"Exif", 0xa20f},
|
||||
[2]interface{}{"Exif", 0xa210},
|
||||
[2]interface{}{"Exif", 0xa401},
|
||||
[2]interface{}{"Exif", 0xa402},
|
||||
[2]interface{}{"Exif", 0xa403},
|
||||
[2]interface{}{"Exif", 0xa406},
|
||||
[2]interface{}{"Exif", 0xa430},
|
||||
[2]interface{}{"Exif", 0xa431},
|
||||
[2]interface{}{"Exif", 0xa432},
|
||||
[2]interface{}{"Exif", 0xa434},
|
||||
[2]interface{}{"Exif", 0xa435},
|
||||
[2]interface{}{"GPSInfo", 0x0000},
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(collected, expected) != true {
|
||||
fmt.Printf("ACTUAL:\n")
|
||||
fmt.Printf("\n")
|
||||
if reflect.DeepEqual(collected, expected) != true {
|
||||
fmt.Printf("ACTUAL:\n")
|
||||
fmt.Printf("\n")
|
||||
|
||||
for _, item := range collected {
|
||||
fmt.Printf("[2]interface{} { \"%s\", 0x%04x },\n", item[0], item[1])
|
||||
}
|
||||
for _, item := range collected {
|
||||
fmt.Printf("[2]interface{} { \"%s\", 0x%04x },\n", item[0], item[1])
|
||||
}
|
||||
|
||||
fmt.Printf("\n")
|
||||
fmt.Printf("\n")
|
||||
|
||||
fmt.Printf("EXPECTED:\n")
|
||||
fmt.Printf("\n")
|
||||
fmt.Printf("EXPECTED:\n")
|
||||
fmt.Printf("\n")
|
||||
|
||||
for _, item := range expected {
|
||||
fmt.Printf("[2]interface{} { \"%s\", 0x%04x },\n", item[0], item[1])
|
||||
}
|
||||
for _, item := range expected {
|
||||
fmt.Printf("[2]interface{} { \"%s\", 0x%04x },\n", item[0], item[1])
|
||||
}
|
||||
|
||||
fmt.Printf("\n")
|
||||
fmt.Printf("\n")
|
||||
|
||||
t.Fatalf("tags not visited correctly: (%d) != (%d)", len(collected), len(expected))
|
||||
}
|
||||
t.Fatalf("tags not visited correctly: (%d) != (%d)", len(collected), len(expected))
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleIfd_EnumerateTagsRecursively() {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
cb := func(ifd *Ifd, ite *IfdTagEntry) error {
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
// Something useful.
|
||||
cb := func(ifd *Ifd, ite *IfdTagEntry) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
// Something useful.
|
||||
|
||||
err = index.RootIfd.EnumerateTagsRecursively(cb)
|
||||
log.PanicIf(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Output:
|
||||
err = index.RootIfd.EnumerateTagsRecursively(cb)
|
||||
log.PanicIf(err)
|
||||
|
||||
// Output:
|
||||
}
|
||||
|
||||
|
||||
func ExampleIfd_GpsInfo() {
|
||||
filepath := path.Join(assetsPath, "gps.jpg")
|
||||
filepath := path.Join(assetsPath, "gps.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
ifd, err := index.RootIfd.ChildWithIfdIdentity(GpsIi)
|
||||
log.PanicIf(err)
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
gi, err := ifd.GpsInfo()
|
||||
log.PanicIf(err)
|
||||
ifd, err := index.RootIfd.ChildWithIfdIdentity(GpsIi)
|
||||
log.PanicIf(err)
|
||||
|
||||
fmt.Printf("%s\n", gi)
|
||||
gi, err := ifd.GpsInfo()
|
||||
log.PanicIf(err)
|
||||
|
||||
// Output:
|
||||
// GpsInfo<LAT=(26.58667) LON=(-80.05361) ALT=(0) TIME=[2018-04-29 01:22:57 +0000 UTC]>
|
||||
fmt.Printf("%s\n", gi)
|
||||
|
||||
// Output:
|
||||
// GpsInfo<LAT=(26.58667) LON=(-80.05361) ALT=(0) TIME=[2018-04-29 01:22:57 +0000 UTC]>
|
||||
}
|
||||
|
|
12
tags.go
12
tags.go
|
@ -37,8 +37,6 @@ var (
|
|||
// blob (not a slice of longs).
|
||||
ThumbnailOffsetTagId: struct{}{},
|
||||
}
|
||||
|
||||
tagIndex *TagIndex
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -64,15 +62,15 @@ type IndexedTag struct {
|
|||
Type uint16
|
||||
}
|
||||
|
||||
func (it IndexedTag) String() string {
|
||||
func (it *IndexedTag) String() string {
|
||||
return fmt.Sprintf("TAG<ID=(0x%04x) NAME=[%s] IFD=[%s]>", it.Id, it.Name, it.Ifd)
|
||||
}
|
||||
|
||||
func (it IndexedTag) IsName(ifd, name string) bool {
|
||||
func (it *IndexedTag) IsName(ifd, name string) bool {
|
||||
return it.Name == name && it.Ifd == ifd
|
||||
}
|
||||
|
||||
func (it IndexedTag) Is(ifd string, id uint16) bool {
|
||||
func (it *IndexedTag) Is(ifd string, id uint16) bool {
|
||||
return it.Id == id && it.Ifd == ifd
|
||||
}
|
||||
|
||||
|
@ -318,7 +316,3 @@ func IfdId(parentIfdName, ifdName string) (ii IfdIdentity, id int) {
|
|||
|
||||
return ii, id
|
||||
}
|
||||
|
||||
func init() {
|
||||
tagIndex = NewTagIndex()
|
||||
}
|
||||
|
|
242
tags_test.go
242
tags_test.go
|
@ -1,194 +1,198 @@
|
|||
package exif
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
var (
|
||||
invalidIi = IfdIdentity{
|
||||
ParentIfdName: "invalid-parent",
|
||||
IfdName: "invalid-child",
|
||||
}
|
||||
invalidIi = IfdIdentity{
|
||||
ParentIfdName: "invalid-parent",
|
||||
IfdName: "invalid-child",
|
||||
}
|
||||
)
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
it, err := tagIndex.Get(RootIi, 0x10f)
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
if it.Is("IFD", 0x10f) == false || it.IsName("IFD", "Make") == false {
|
||||
t.Fatalf("tag info not correct")
|
||||
}
|
||||
it, err := ti.Get(RootIi, 0x10f)
|
||||
log.PanicIf(err)
|
||||
|
||||
if it.Is("IFD", 0x10f) == false || it.IsName("IFD", "Make") == false {
|
||||
t.Fatalf("tag info not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetWithName(t *testing.T) {
|
||||
it, err := tagIndex.GetWithName(RootIi, "Make")
|
||||
log.PanicIf(err)
|
||||
ti := NewTagIndex()
|
||||
|
||||
if it.Is("IFD", 0x10f) == false || it.Is("IFD", 0x10f) == false {
|
||||
t.Fatalf("tag info not correct")
|
||||
}
|
||||
it, err := ti.GetWithName(RootIi, "Make")
|
||||
log.PanicIf(err)
|
||||
|
||||
if it.Is("IFD", 0x10f) == false || it.Is("IFD", 0x10f) == false {
|
||||
t.Fatalf("tag info not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagNameWithIdOrFail_Miss(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
if err.Error() != "tag-ID (0x1234) under parent IFD [Exif] not associated with a child IFD" {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
if err.Error() != "tag-ID (0x1234) under parent IFD [Exif] not associated with a child IFD" {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
IfdTagNameWithIdOrFail(IfdExif, 0x1234)
|
||||
IfdTagNameWithIdOrFail(IfdExif, 0x1234)
|
||||
|
||||
t.Fatalf("expected failing for invalid IFD tag-ID")
|
||||
t.Fatalf("expected failing for invalid IFD tag-ID")
|
||||
}
|
||||
|
||||
func TestIfdTagNameWithIdOrFail_RootChildIfd(t *testing.T) {
|
||||
name := IfdTagNameWithIdOrFail(IfdStandard, IfdExifId)
|
||||
if name != IfdExif {
|
||||
t.Fatalf("expected EXIF IFD name for hit on EXIF IFD")
|
||||
}
|
||||
name := IfdTagNameWithIdOrFail(IfdStandard, IfdExifId)
|
||||
if name != IfdExif {
|
||||
t.Fatalf("expected EXIF IFD name for hit on EXIF IFD")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagNameWithIdOrFail_ChildChildIfd(t *testing.T) {
|
||||
name := IfdTagNameWithIdOrFail(IfdExif, IfdIopId)
|
||||
if name != IfdIop {
|
||||
t.Fatalf("expected IOP IFD name for hit on IOP IFD")
|
||||
}
|
||||
name := IfdTagNameWithIdOrFail(IfdExif, IfdIopId)
|
||||
if name != IfdIop {
|
||||
t.Fatalf("expected IOP IFD name for hit on IOP IFD")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagNameWithId_Hit(t *testing.T) {
|
||||
name, found := IfdTagNameWithId(IfdExif, IfdIopId)
|
||||
if found != true {
|
||||
t.Fatalf("could not get name for IOP IFD tag-ID")
|
||||
} else if name != IfdIop {
|
||||
t.Fatalf("expected IOP IFD name for hit on IOP IFD")
|
||||
}
|
||||
name, found := IfdTagNameWithId(IfdExif, IfdIopId)
|
||||
if found != true {
|
||||
t.Fatalf("could not get name for IOP IFD tag-ID")
|
||||
} else if name != IfdIop {
|
||||
t.Fatalf("expected IOP IFD name for hit on IOP IFD")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagNameWithId_Miss(t *testing.T) {
|
||||
name, found := IfdTagNameWithId(IfdExif, 0x1234)
|
||||
if found != false {
|
||||
t.Fatalf("expected failure for invalid IFD iag-ID under EXIF IFD")
|
||||
} else if name != "" {
|
||||
t.Fatalf("expected empty IFD name for miss")
|
||||
}
|
||||
name, found := IfdTagNameWithId(IfdExif, 0x1234)
|
||||
if found != false {
|
||||
t.Fatalf("expected failure for invalid IFD iag-ID under EXIF IFD")
|
||||
} else if name != "" {
|
||||
t.Fatalf("expected empty IFD name for miss")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagIdWithIdentity_Hit(t *testing.T) {
|
||||
tagId, found := IfdTagIdWithIdentity(GpsIi)
|
||||
if found != true {
|
||||
t.Fatalf("could not get tag-ID for II")
|
||||
} else if tagId != IfdGpsId {
|
||||
t.Fatalf("incorrect tag-ID returned for II")
|
||||
}
|
||||
tagId, found := IfdTagIdWithIdentity(GpsIi)
|
||||
if found != true {
|
||||
t.Fatalf("could not get tag-ID for II")
|
||||
} else if tagId != IfdGpsId {
|
||||
t.Fatalf("incorrect tag-ID returned for II")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagIdWithIdentity_Miss(t *testing.T) {
|
||||
tagId, found := IfdTagIdWithIdentity(invalidIi)
|
||||
if found != false {
|
||||
t.Fatalf("expected failure")
|
||||
} else if tagId != 0 {
|
||||
t.Fatalf("expected tag-ID of (0) for failure")
|
||||
}
|
||||
tagId, found := IfdTagIdWithIdentity(invalidIi)
|
||||
if found != false {
|
||||
t.Fatalf("expected failure")
|
||||
} else if tagId != 0 {
|
||||
t.Fatalf("expected tag-ID of (0) for failure")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagIdWithIdentityOrFail_Hit(t *testing.T) {
|
||||
IfdTagIdWithIdentityOrFail(GpsIi)
|
||||
IfdTagIdWithIdentityOrFail(GpsIi)
|
||||
}
|
||||
|
||||
func TestIfdTagIdWithIdentityOrFail_Miss(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
if err.Error() != "no tag for invalid IFD identity: IfdIdentity<PARENT-NAME=[invalid-parent] NAME=[invalid-child]>" {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
if err.Error() != "no tag for invalid IFD identity: IfdIdentity<PARENT-NAME=[invalid-parent] NAME=[invalid-child]>" {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
IfdTagIdWithIdentityOrFail(invalidIi)
|
||||
IfdTagIdWithIdentityOrFail(invalidIi)
|
||||
|
||||
t.Fatalf("invalid II didn't panic")
|
||||
t.Fatalf("invalid II didn't panic")
|
||||
}
|
||||
|
||||
func TestIfdIdWithIdentity_Hit(t *testing.T) {
|
||||
id := IfdIdWithIdentity(GpsIi)
|
||||
if id != 3 {
|
||||
t.Fatalf("II doesn't have the right ID")
|
||||
}
|
||||
id := IfdIdWithIdentity(GpsIi)
|
||||
if id != 3 {
|
||||
t.Fatalf("II doesn't have the right ID")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdIdWithIdentity_Miss(t *testing.T) {
|
||||
id := IfdIdWithIdentity(invalidIi)
|
||||
if id != 0 {
|
||||
t.Fatalf("II doesn't have the right ID for a miss")
|
||||
}
|
||||
id := IfdIdWithIdentity(invalidIi)
|
||||
if id != 0 {
|
||||
t.Fatalf("II doesn't have the right ID for a miss")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdIdWithIdentityOrFail_Hit(t *testing.T) {
|
||||
id := IfdIdWithIdentityOrFail(GpsIi)
|
||||
if id != 3 {
|
||||
t.Fatalf("II doesn't have the right ID")
|
||||
}
|
||||
id := IfdIdWithIdentityOrFail(GpsIi)
|
||||
if id != 3 {
|
||||
t.Fatalf("II doesn't have the right ID")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdIdWithIdentityOrFail_Miss(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
if err.Error() != "IFD not valid: IfdIdentity<PARENT-NAME=[invalid-parent] NAME=[invalid-child]>" {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
if err.Error() != "IFD not valid: IfdIdentity<PARENT-NAME=[invalid-parent] NAME=[invalid-child]>" {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
IfdIdWithIdentityOrFail(invalidIi)
|
||||
IfdIdWithIdentityOrFail(invalidIi)
|
||||
|
||||
t.Fatalf("invalid II doesn't panic")
|
||||
t.Fatalf("invalid II doesn't panic")
|
||||
}
|
||||
|
||||
func TestIfdIdOrFail_Hit(t *testing.T) {
|
||||
ii, id := IfdIdOrFail(IfdStandard, IfdExif)
|
||||
if ii != ExifIi {
|
||||
t.Fatalf("wrong II for IFD returned")
|
||||
} else if id != 2 {
|
||||
t.Fatalf("wrong ID for II returned")
|
||||
}
|
||||
ii, id := IfdIdOrFail(IfdStandard, IfdExif)
|
||||
if ii != ExifIi {
|
||||
t.Fatalf("wrong II for IFD returned")
|
||||
} else if id != 2 {
|
||||
t.Fatalf("wrong ID for II returned")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdIdOrFail_Miss(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
if err.Error() != "IFD is not valid: [IFD] [invalid-ifd]" {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
if err.Error() != "IFD is not valid: [IFD] [invalid-ifd]" {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
IfdIdOrFail(IfdStandard, "invalid-ifd")
|
||||
IfdIdOrFail(IfdStandard, "invalid-ifd")
|
||||
|
||||
t.Fatalf("expected panic for invalid IFD")
|
||||
t.Fatalf("expected panic for invalid IFD")
|
||||
}
|
||||
|
||||
func TestIfdId_Hit(t *testing.T) {
|
||||
ii, id := IfdId(IfdStandard, IfdExif)
|
||||
if ii != ExifIi {
|
||||
t.Fatalf("wrong II for IFD returned")
|
||||
} else if id != 2 {
|
||||
t.Fatalf("wrong ID for II returned")
|
||||
}
|
||||
ii, id := IfdId(IfdStandard, IfdExif)
|
||||
if ii != ExifIi {
|
||||
t.Fatalf("wrong II for IFD returned")
|
||||
} else if id != 2 {
|
||||
t.Fatalf("wrong ID for II returned")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdId_Miss(t *testing.T) {
|
||||
ii, id := IfdId(IfdStandard, "invalid-ifd")
|
||||
if id != 0 {
|
||||
t.Fatalf("non-zero ID returned for invalid IFD")
|
||||
} else if ii != ZeroIi {
|
||||
t.Fatalf("expected zero-instance result for miss")
|
||||
}
|
||||
ii, id := IfdId(IfdStandard, "invalid-ifd")
|
||||
if id != 0 {
|
||||
t.Fatalf("non-zero ID returned for invalid IFD")
|
||||
} else if ii != ZeroIi {
|
||||
t.Fatalf("expected zero-instance result for miss")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,83 +1,81 @@
|
|||
package exif
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"bytes"
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
func TestUndefinedValue_ExifVersion(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ii := ExifIi
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ii := ExifIi
|
||||
|
||||
// Create our unknown-type tag's value using the fact that we know it's a
|
||||
// non-null-terminated string.
|
||||
|
||||
// Create our unknown-type tag's value using the fact that we know it's a
|
||||
// non-null-terminated string.
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
tt := NewTagType(TypeAsciiNoNul, byteOrder)
|
||||
valueString := "0230"
|
||||
|
||||
tt := NewTagType(TypeAsciiNoNul, byteOrder)
|
||||
valueString := "0230"
|
||||
ed, err := ve.EncodeWithType(tt, valueString)
|
||||
log.PanicIf(err)
|
||||
|
||||
ed, err := ve.EncodeWithType(tt, valueString)
|
||||
log.PanicIf(err)
|
||||
// Create the tag using the official "unknown" type now that we already
|
||||
// have the bytes.
|
||||
|
||||
encodedValue := NewIfdBuilderTagValueFromBytes(ed.Encoded)
|
||||
|
||||
// Create the tag using the official "unknown" type now that we already
|
||||
// have the bytes.
|
||||
bt := &BuilderTag{
|
||||
ii: ii,
|
||||
tagId: 0x9000,
|
||||
typeId: TypeUndefined,
|
||||
value: encodedValue,
|
||||
}
|
||||
|
||||
encodedValue := NewIfdBuilderTagValueFromBytes(ed.Encoded)
|
||||
// Stage the build.
|
||||
|
||||
bt := &BuilderTag{
|
||||
ii: ii,
|
||||
tagId: 0x9000,
|
||||
typeId: TypeUndefined,
|
||||
value: encodedValue,
|
||||
}
|
||||
ti := NewTagIndex()
|
||||
|
||||
ibe := NewIfdByteEncoder()
|
||||
ib := NewIfdBuilder(ti, ii, byteOrder)
|
||||
|
||||
// Stage the build.
|
||||
b := new(bytes.Buffer)
|
||||
bw := NewByteWriter(b, byteOrder)
|
||||
|
||||
ibe := NewIfdByteEncoder()
|
||||
ib := NewIfdBuilder(ii, byteOrder)
|
||||
addressableOffset := uint32(0x1234)
|
||||
ida := newIfdDataAllocator(addressableOffset)
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
bw := NewByteWriter(b, byteOrder)
|
||||
// Encode.
|
||||
|
||||
addressableOffset := uint32(0x1234)
|
||||
ida := newIfdDataAllocator(addressableOffset)
|
||||
_, err = ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0))
|
||||
log.PanicIf(err)
|
||||
|
||||
tagBytes := b.Bytes()
|
||||
|
||||
// Encode.
|
||||
if len(tagBytes) != 12 {
|
||||
t.Fatalf("Tag not encoded to the right number of bytes: (%d)", len(tagBytes))
|
||||
}
|
||||
|
||||
_, err = ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0))
|
||||
log.PanicIf(err)
|
||||
ite, err := ParseOneTag(ii, byteOrder, tagBytes, false)
|
||||
log.PanicIf(err)
|
||||
|
||||
tagBytes := b.Bytes()
|
||||
|
||||
if len(tagBytes) != 12 {
|
||||
t.Fatalf("Tag not encoded to the right number of bytes: (%d)", len(tagBytes))
|
||||
}
|
||||
|
||||
ite, err := ParseOneTag(ii, byteOrder, tagBytes, false)
|
||||
log.PanicIf(err)
|
||||
|
||||
if ite.TagId != 0x9000 {
|
||||
t.Fatalf("Tag-ID not correct: (0x%02x)", ite.TagId)
|
||||
} else if ite.TagIndex != 0 {
|
||||
t.Fatalf("Tag index not correct: (%d)", ite.TagIndex)
|
||||
} else if ite.TagType != TypeUndefined {
|
||||
t.Fatalf("Tag type not correct: (%d)", ite.TagType)
|
||||
} else if ite.UnitCount != (uint32(len(valueString))) {
|
||||
t.Fatalf("Tag unit-count not correct: (%d)", ite.UnitCount)
|
||||
} else if bytes.Compare(ite.RawValueOffset, []byte { '0', '2', '3', '0' }) != 0 {
|
||||
t.Fatalf("Tag's value (as raw bytes) is not correct: [%x]", ite.RawValueOffset)
|
||||
} else if ite.ChildIfdName != "" {
|
||||
t.Fatalf("Tag's IFD-name should be empty: [%s]", ite.ChildIfdName)
|
||||
} else if ite.Ii != ii {
|
||||
t.Fatalf("Tag's parent IFD is not correct: %v", ite.Ii)
|
||||
}
|
||||
if ite.TagId != 0x9000 {
|
||||
t.Fatalf("Tag-ID not correct: (0x%02x)", ite.TagId)
|
||||
} else if ite.TagIndex != 0 {
|
||||
t.Fatalf("Tag index not correct: (%d)", ite.TagIndex)
|
||||
} else if ite.TagType != TypeUndefined {
|
||||
t.Fatalf("Tag type not correct: (%d)", ite.TagType)
|
||||
} else if ite.UnitCount != (uint32(len(valueString))) {
|
||||
t.Fatalf("Tag unit-count not correct: (%d)", ite.UnitCount)
|
||||
} else if bytes.Compare(ite.RawValueOffset, []byte{'0', '2', '3', '0'}) != 0 {
|
||||
t.Fatalf("Tag's value (as raw bytes) is not correct: [%x]", ite.RawValueOffset)
|
||||
} else if ite.ChildIfdName != "" {
|
||||
t.Fatalf("Tag's IFD-name should be empty: [%s]", ite.ChildIfdName)
|
||||
} else if ite.Ii != ii {
|
||||
t.Fatalf("Tag's parent IFD is not correct: %v", ite.Ii)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(dustin): !! Add tests for remaining, well-defined unknown
|
||||
|
|
Loading…
Reference in New Issue