mirror of https://github.com/dsoprea/go-exif.git
ifd_builder.go: No longer use ITEVRs
This was an early way of resolving tag values that is now obsolete. `ValueContext` structs should be used, and these, in many cases, should be able to be constructed from the current context without passing additional arguments. - ifd_builder_test.go: Refactors to several tests due to loss of ITEVR support. - ifd_builder_encode_test.go: Moved test-IB populate to testing_common.go . - ifd_builder.go: Fixed test naming (in most cases, omitted type name).pull/28/head
parent
9946007f05
commit
88612c1cf8
143
ifd_builder.go
143
ifd_builder.go
|
@ -222,8 +222,8 @@ type IfdBuilder struct {
|
||||||
byteOrder binary.ByteOrder
|
byteOrder binary.ByteOrder
|
||||||
|
|
||||||
// Includes both normal tags and IFD tags (which point to child IFDs).
|
// Includes both normal tags and IFD tags (which point to child IFDs).
|
||||||
// TODO(dustin): Keep a separate list of children like with IFd.
|
// TODO(dustin): Keep a separate list of children like with `Ifd`.
|
||||||
// TODO(dustin): Either rename this or `Entries` in Ifd to be the same thing.
|
// TODO(dustin): Either rename this or `Entries` in `Ifd` to be the same thing.
|
||||||
tags []*BuilderTag
|
tags []*BuilderTag
|
||||||
|
|
||||||
// existingOffset will be the offset that this IFD is currently found at if
|
// existingOffset will be the offset that this IFD is currently found at if
|
||||||
|
@ -312,7 +312,7 @@ func NewIfdBuilderWithExistingIfd(ifd *Ifd) (ib *IfdBuilder) {
|
||||||
// NewIfdBuilderFromExistingChain creates a chain of IB instances from an
|
// NewIfdBuilderFromExistingChain creates a chain of IB instances from an
|
||||||
// IFD chain generated from real data.
|
// IFD chain generated from real data.
|
||||||
func NewIfdBuilderFromExistingChain(rootIfd *Ifd, itevr *IfdTagEntryValueResolver) (firstIb *IfdBuilder) {
|
func NewIfdBuilderFromExistingChain(rootIfd *Ifd, itevr *IfdTagEntryValueResolver) (firstIb *IfdBuilder) {
|
||||||
// TODO(dustin): !! When we actually write the code to flatten the IB to bytes, make sure to skip the tags that have a nil value (which will happen when we add-from-exsting without a resolver instance).
|
// OBSOLETE(dustin): Support for `itevr` is now obsolete. This parameter will be removed in the future.
|
||||||
|
|
||||||
var lastIb *IfdBuilder
|
var lastIb *IfdBuilder
|
||||||
i := 0
|
i := 0
|
||||||
|
@ -324,7 +324,7 @@ func NewIfdBuilderFromExistingChain(rootIfd *Ifd, itevr *IfdTagEntryValueResolve
|
||||||
lastIb.SetNextIb(newIb)
|
lastIb.SetNextIb(newIb)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := newIb.AddTagsFromExisting(thisExistingIfd, itevr, nil, nil)
|
err := newIb.AddTagsFromExisting(thisExistingIfd, nil, nil, nil)
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
lastIb = newIb
|
lastIb = newIb
|
||||||
|
@ -1028,6 +1028,8 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResol
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// OBSOLETE(dustin): Support for `itevr` is now obsolete. This parameter will be removed in the future.
|
||||||
|
|
||||||
thumbnailData, err := ifd.Thumbnail()
|
thumbnailData, err := ifd.Thumbnail()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = ib.SetThumbnail(thumbnailData)
|
err = ib.SetThumbnail(thumbnailData)
|
||||||
|
@ -1078,105 +1080,76 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResol
|
||||||
// If we want to add an IFD tag, we'll have to build it first and
|
// If we want to add an IFD tag, we'll have to build it first and
|
||||||
// *then* add it via a different method.
|
// *then* add it via a different method.
|
||||||
|
|
||||||
if itevr == nil {
|
// Figure out which of the child-IFDs that are associated with
|
||||||
// We don't have any ability to resolve the structure of the
|
// this IFD represents this specific child IFD.
|
||||||
// child-IFD. Just install it as a normal tag rather than a
|
|
||||||
// fully-structured child-IFD. We're going to blank the value,
|
|
||||||
// though, since its original offset will no longer be valid
|
|
||||||
// (nor does it matter since this is just a temporary
|
|
||||||
// placeholder, in this situation).
|
|
||||||
value := NewIfdBuilderTagValueFromBytes([]byte{0, 0, 0, 0})
|
|
||||||
bt = NewBuilderTag(
|
|
||||||
ite.IfdPath,
|
|
||||||
ite.TagId,
|
|
||||||
ite.TagType,
|
|
||||||
value,
|
|
||||||
ib.byteOrder)
|
|
||||||
} else {
|
|
||||||
// Figure out which of the child-IFDs that are associated with
|
|
||||||
// this IFD represents this specific child IFD.
|
|
||||||
|
|
||||||
var childIfd *Ifd
|
var childIfd *Ifd
|
||||||
for _, thisChildIfd := range ifd.Children {
|
for _, thisChildIfd := range ifd.Children {
|
||||||
if thisChildIfd.ParentTagIndex != i {
|
if thisChildIfd.ParentTagIndex != i {
|
||||||
continue
|
continue
|
||||||
} else if thisChildIfd.TagId != 0xffff && thisChildIfd.TagId != ite.TagId {
|
} else if thisChildIfd.TagId != 0xffff && thisChildIfd.TagId != ite.TagId {
|
||||||
log.Panicf("child-IFD tag is not correct: TAG-POSITION=(%d) ITE=%s CHILD-IFD=%s", thisChildIfd.ParentTagIndex, ite, thisChildIfd)
|
log.Panicf("child-IFD tag is not correct: TAG-POSITION=(%d) ITE=%s CHILD-IFD=%s", thisChildIfd.ParentTagIndex, ite, thisChildIfd)
|
||||||
}
|
|
||||||
|
|
||||||
childIfd = thisChildIfd
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if childIfd == nil {
|
childIfd = thisChildIfd
|
||||||
childTagIds := make([]string, len(ifd.Children))
|
break
|
||||||
for j, childIfd := range ifd.Children {
|
|
||||||
childTagIds[j] = fmt.Sprintf("0x%04x (parent tag-position %d)", childIfd.TagId, childIfd.ParentTagIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Panicf("could not find child IFD for child ITE: IFD-PATH=[%s] TAG-ID=(0x%04x) CURRENT-TAG-POSITION=(%d) CHILDREN=%v", ite.IfdPath, ite.TagId, i, childTagIds)
|
|
||||||
}
|
|
||||||
|
|
||||||
childIb := NewIfdBuilderFromExistingChain(childIfd, itevr)
|
|
||||||
bt = ib.NewBuilderTagFromBuilder(childIb)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if childIfd == nil {
|
||||||
|
childTagIds := make([]string, len(ifd.Children))
|
||||||
|
for j, childIfd := range ifd.Children {
|
||||||
|
childTagIds[j] = fmt.Sprintf("0x%04x (parent tag-position %d)", childIfd.TagId, childIfd.ParentTagIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Panicf("could not find child IFD for child ITE: IFD-PATH=[%s] TAG-ID=(0x%04x) CURRENT-TAG-POSITION=(%d) CHILDREN=%v", ite.IfdPath, ite.TagId, i, childTagIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
childIb := NewIfdBuilderFromExistingChain(childIfd, nil)
|
||||||
|
bt = ib.NewBuilderTagFromBuilder(childIb)
|
||||||
} else {
|
} else {
|
||||||
// Non-IFD tag.
|
// Non-IFD tag.
|
||||||
|
|
||||||
var value *IfdBuilderTagValue
|
var value *IfdBuilderTagValue
|
||||||
|
|
||||||
// TODO(dustin): !! We should be able to dump (i.e. deimplement) the concept of itevr's and exclusively use ValueContext, now.
|
valueContext := newValueContextFromTag(
|
||||||
|
ite,
|
||||||
|
ifd.addressableData,
|
||||||
|
ifd.ByteOrder)
|
||||||
|
|
||||||
if itevr == nil {
|
var rawBytes []byte
|
||||||
// TODO(dustin): !! This might not make sense. The undefined-type data will just likely now have invalid value.
|
|
||||||
|
|
||||||
// rawValueOffsetCopy is our own private copy of the original data.
|
if ite.TagType == TypeUndefined {
|
||||||
// It should always be four-bytes, but just copy whatever there is.
|
// It's an undefined-type value. Try to process, or skip if
|
||||||
rawValueOffsetCopy := make([]byte, len(ite.RawValueOffset))
|
// we don't know how to.
|
||||||
copy(rawValueOffsetCopy, ite.RawValueOffset)
|
|
||||||
|
|
||||||
value = NewIfdBuilderTagValueFromBytes(rawValueOffsetCopy)
|
x, err := valueContext.Undefined()
|
||||||
} else {
|
log.PanicIf(err)
|
||||||
valueContext := newValueContextFromTag(
|
|
||||||
ite,
|
|
||||||
ifd.addressableData,
|
|
||||||
ifd.ByteOrder)
|
|
||||||
|
|
||||||
var rawBytes []byte
|
// TODO(dustin): !! Add test for this.
|
||||||
|
_, isUnknownUndefined := x.(TagUnknownType_UnknownValue)
|
||||||
|
|
||||||
if ite.TagType == TypeUndefined {
|
if isUnknownUndefined == true {
|
||||||
// It's an undefined-type value. Try to process, or skip if
|
continue
|
||||||
// we don't know how to.
|
|
||||||
|
|
||||||
x, err := valueContext.Undefined()
|
|
||||||
log.PanicIf(err)
|
|
||||||
|
|
||||||
// TODO(dustin): !! Add test for this.
|
|
||||||
_, isUnknownUndefined := x.(TagUnknownType_UnknownValue)
|
|
||||||
|
|
||||||
if isUnknownUndefined == true {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
undefined, ok := x.(UnknownTagValue)
|
|
||||||
if ok != true {
|
|
||||||
log.Panicf("unexpected value returned from undefined-value processor")
|
|
||||||
}
|
|
||||||
|
|
||||||
rawBytes, err = undefined.ValueBytes()
|
|
||||||
log.PanicIf(err)
|
|
||||||
} else {
|
|
||||||
// It's a value with a standard type.
|
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
rawBytes, err = valueContext.readRawEncoded()
|
|
||||||
log.PanicIf(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
value = NewIfdBuilderTagValueFromBytes(rawBytes)
|
undefined, ok := x.(UnknownTagValue)
|
||||||
|
if ok != true {
|
||||||
|
log.Panicf("unexpected value returned from undefined-value processor")
|
||||||
|
}
|
||||||
|
|
||||||
|
rawBytes, err = undefined.ValueBytes()
|
||||||
|
log.PanicIf(err)
|
||||||
|
} else {
|
||||||
|
// It's a value with a standard type.
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
rawBytes, err = valueContext.readRawEncoded()
|
||||||
|
log.PanicIf(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value = NewIfdBuilderTagValueFromBytes(rawBytes)
|
||||||
|
|
||||||
bt = NewBuilderTag(
|
bt = NewBuilderTag(
|
||||||
ifd.IfdPath,
|
ifd.IfdPath,
|
||||||
ite.TagId,
|
ite.TagId,
|
||||||
|
|
|
@ -3,7 +3,6 @@ package exif
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -562,97 +561,6 @@ func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExifSimpleTestIb() *IfdBuilder {
|
|
||||||
im := NewIfdMapping()
|
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
|
||||||
log.PanicIf(err)
|
|
||||||
|
|
||||||
ti := NewTagIndex()
|
|
||||||
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
|
||||||
|
|
||||||
err = ib.AddStandard(0x000b, "asciivalue")
|
|
||||||
log.PanicIf(err)
|
|
||||||
|
|
||||||
err = ib.AddStandard(0x00ff, []uint16{0x1122})
|
|
||||||
log.PanicIf(err)
|
|
||||||
|
|
||||||
err = ib.AddStandard(0x0100, []uint32{0x33445566})
|
|
||||||
log.PanicIf(err)
|
|
||||||
|
|
||||||
err = ib.AddStandard(0x013e, []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
|
|
||||||
log.PanicIf(err)
|
|
||||||
|
|
||||||
return ib
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
|
|
||||||
im := NewIfdMapping()
|
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
|
||||||
log.PanicIf(err)
|
|
||||||
|
|
||||||
ti := NewTagIndex()
|
|
||||||
|
|
||||||
eh, index, err := Collect(im, ti, exifData)
|
|
||||||
log.PanicIf(err)
|
|
||||||
|
|
||||||
if eh.ByteOrder != TestDefaultByteOrder {
|
|
||||||
t.Fatalf("EXIF byte-order is not correct: %v", eh.ByteOrder)
|
|
||||||
} else if eh.FirstIfdOffset != ExifDefaultFirstIfdOffset {
|
|
||||||
t.Fatalf("EXIF first IFD-offset not correct: (0x%02x)", eh.FirstIfdOffset)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(index.Ifds) != 1 {
|
|
||||||
t.Fatalf("There wasn't exactly one IFD decoded: (%d)", len(index.Ifds))
|
|
||||||
}
|
|
||||||
|
|
||||||
ifd := index.RootIfd
|
|
||||||
|
|
||||||
if ifd.ByteOrder != TestDefaultByteOrder {
|
|
||||||
t.Fatalf("IFD byte-order not correct.")
|
|
||||||
} else if ifd.IfdPath != IfdStandard {
|
|
||||||
t.Fatalf("IFD name not correct.")
|
|
||||||
} else if ifd.Index != 0 {
|
|
||||||
t.Fatalf("IFD index not zero: (%d)", ifd.Index)
|
|
||||||
} else if ifd.Offset != uint32(0x0008) {
|
|
||||||
t.Fatalf("IFD offset not correct.")
|
|
||||||
} else if len(ifd.Entries) != 4 {
|
|
||||||
t.Fatalf("IFD number of entries not correct: (%d)", len(ifd.Entries))
|
|
||||||
} else if ifd.NextIfdOffset != uint32(0) {
|
|
||||||
t.Fatalf("Next-IFD offset is non-zero.")
|
|
||||||
} else if ifd.NextIfd != nil {
|
|
||||||
t.Fatalf("Next-IFD pointer is non-nil.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the values by using the actual, orginal types (this is awesome).
|
|
||||||
|
|
||||||
addressableData := exifData[ExifAddressableAreaStart:]
|
|
||||||
|
|
||||||
expected := []struct {
|
|
||||||
tagId uint16
|
|
||||||
value interface{}
|
|
||||||
}{
|
|
||||||
{tagId: 0x000b, value: "asciivalue"},
|
|
||||||
{tagId: 0x00ff, value: []uint16{0x1122}},
|
|
||||||
{tagId: 0x0100, value: []uint32{0x33445566}},
|
|
||||||
{tagId: 0x013e, value: []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, e := range ifd.Entries {
|
|
||||||
if e.TagId != expected[i].tagId {
|
|
||||||
t.Fatalf("Tag-ID for entry (%d) not correct: (0x%02x) != (0x%02x)", i, e.TagId, expected[i].tagId)
|
|
||||||
}
|
|
||||||
|
|
||||||
value, err := e.Value(addressableData, TestDefaultByteOrder)
|
|
||||||
log.PanicIf(err)
|
|
||||||
|
|
||||||
if reflect.DeepEqual(value, expected[i].value) != true {
|
|
||||||
t.Fatalf("Value for entry (%d) not correct: [%v] != [%v]", i, value, expected[i].value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_IfdByteEncoder_encodeIfdToBytes_simple(t *testing.T) {
|
func Test_IfdByteEncoder_encodeIfdToBytes_simple(t *testing.T) {
|
||||||
ib := getExifSimpleTestIb()
|
ib := getExifSimpleTestIb()
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"github.com/dsoprea/go-logging"
|
"github.com/dsoprea/go-logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAdd(t *testing.T) {
|
func TestIfdBuilder_Add(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -103,7 +103,7 @@ func TestAdd(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetNextIb(t *testing.T) {
|
func TestIfdBuilder_SetNextIb(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -128,7 +128,7 @@ func TestSetNextIb(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddChildIb(t *testing.T) {
|
func TestIfdBuilder_AddChildIb(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -172,160 +172,120 @@ func TestAddChildIb(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddTagsFromExisting(t *testing.T) {
|
func TestIfdBuilder_AddTagsFromExisting(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if state := recover(); state != nil {
|
if state := recover(); state != nil {
|
||||||
err := log.Wrap(state.(error))
|
err := log.Wrap(state.(error))
|
||||||
log.PrintErrorf(err, "Test failure.")
|
log.PrintError(err)
|
||||||
|
|
||||||
|
t.Fatalf("Test failure.")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
exifData := getExifSimpleTestIbBytes()
|
||||||
|
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
ti := NewTagIndex()
|
ti := NewTagIndex()
|
||||||
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
|
||||||
|
|
||||||
entries := make([]*IfdTagEntry, 3)
|
_, index, err := Collect(im, ti, exifData)
|
||||||
|
|
||||||
entries[0] = &IfdTagEntry{
|
|
||||||
IfdPath: IfdPathStandardExif,
|
|
||||||
TagId: 0x11,
|
|
||||||
TagType: TypeByte,
|
|
||||||
UnitCount: 4,
|
|
||||||
RawValueOffset: []byte{0x12, 0, 0, 0},
|
|
||||||
}
|
|
||||||
|
|
||||||
entries[1] = &IfdTagEntry{
|
|
||||||
IfdPath: IfdPathStandardExif,
|
|
||||||
TagId: 0x22,
|
|
||||||
TagType: TypeLong,
|
|
||||||
ChildIfdPath: "some ifd",
|
|
||||||
}
|
|
||||||
|
|
||||||
entries[2] = &IfdTagEntry{
|
|
||||||
IfdPath: IfdPathStandardExif,
|
|
||||||
TagId: 0x33,
|
|
||||||
TagType: TypeByte,
|
|
||||||
UnitCount: 4,
|
|
||||||
RawValueOffset: []byte{0x34, 0, 0, 0},
|
|
||||||
}
|
|
||||||
|
|
||||||
ifd := &Ifd{
|
|
||||||
IfdPath: IfdPathStandard,
|
|
||||||
Entries: entries,
|
|
||||||
tagIndex: ti,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ib.AddTagsFromExisting(ifd, nil, nil, nil)
|
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
if ib.tags[0].tagId != 0x11 {
|
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||||
t.Fatalf("tag (0) not correct")
|
|
||||||
} else if ib.tags[1].tagId != 0x22 {
|
err = ib.AddTagsFromExisting(index.RootIfd, nil, nil, nil)
|
||||||
t.Fatalf("tag (1) not correct")
|
log.PanicIf(err)
|
||||||
} else if ib.tags[2].tagId != 0x33 {
|
|
||||||
t.Fatalf("tag (2) not correct")
|
expected := []uint16{
|
||||||
} else if len(ib.tags) != 3 {
|
0x000b,
|
||||||
t.Fatalf("tag count not correct")
|
0x00ff,
|
||||||
|
0x0100,
|
||||||
|
0x013e,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ib.tags) != len(expected) {
|
||||||
|
t.Fatalf("Tag count not correct: (%d) != (%d)", len(ib.tags), len(expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tag := range ib.tags {
|
||||||
|
if tag.tagId != expected[i] {
|
||||||
|
t.Fatalf("Tag (%d) not correct: (0x%04x) != (0x%04x)", i, tag.tagId, expected[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddTagsFromExisting__Includes(t *testing.T) {
|
func TestIfdBuilder_AddTagsFromExisting__Includes(t *testing.T) {
|
||||||
|
exifData := getExifSimpleTestIbBytes()
|
||||||
|
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
ti := NewTagIndex()
|
ti := NewTagIndex()
|
||||||
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
|
||||||
|
|
||||||
entries := make([]*IfdTagEntry, 3)
|
_, index, err := Collect(im, ti, exifData)
|
||||||
|
|
||||||
entries[0] = &IfdTagEntry{
|
|
||||||
IfdPath: IfdPathStandard,
|
|
||||||
TagType: TypeByte,
|
|
||||||
TagId: 0x11,
|
|
||||||
}
|
|
||||||
|
|
||||||
entries[1] = &IfdTagEntry{
|
|
||||||
IfdPath: IfdPathStandard,
|
|
||||||
TagType: TypeByte,
|
|
||||||
TagId: 0x22,
|
|
||||||
ChildIfdPath: "some ifd",
|
|
||||||
}
|
|
||||||
|
|
||||||
entries[2] = &IfdTagEntry{
|
|
||||||
IfdPath: IfdPathStandard,
|
|
||||||
TagType: TypeByte,
|
|
||||||
TagId: 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
ifd := &Ifd{
|
|
||||||
IfdPath: IfdPathStandard,
|
|
||||||
Entries: entries,
|
|
||||||
tagIndex: ti,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ib.AddTagsFromExisting(ifd, nil, []uint16{0x33}, nil)
|
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
if ib.tags[0].tagId != 0x33 {
|
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||||
t.Fatalf("tag (1) not correct")
|
|
||||||
} else if len(ib.tags) != 1 {
|
err = ib.AddTagsFromExisting(index.RootIfd, nil, []uint16{0x00ff}, nil)
|
||||||
t.Fatalf("tag count not correct")
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
expected := []uint16{
|
||||||
|
0x00ff,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ib.tags) != len(expected) {
|
||||||
|
t.Fatalf("Tag count not correct: (%d) != (%d)", len(ib.tags), len(expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tag := range ib.tags {
|
||||||
|
if tag.tagId != expected[i] {
|
||||||
|
t.Fatalf("Tag (%d) not correct: (0x%04x) != (0x%04x)", i, tag.tagId, expected[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddTagsFromExisting__Excludes(t *testing.T) {
|
func TestIfdBuilder_AddTagsFromExisting__Excludes(t *testing.T) {
|
||||||
|
exifData := getExifSimpleTestIbBytes()
|
||||||
|
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
ti := NewTagIndex()
|
ti := NewTagIndex()
|
||||||
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
|
||||||
|
|
||||||
entries := make([]*IfdTagEntry, 3)
|
_, index, err := Collect(im, ti, exifData)
|
||||||
|
|
||||||
entries[0] = &IfdTagEntry{
|
|
||||||
IfdPath: IfdPathStandard,
|
|
||||||
TagType: TypeByte,
|
|
||||||
TagId: 0x11,
|
|
||||||
}
|
|
||||||
|
|
||||||
entries[1] = &IfdTagEntry{
|
|
||||||
IfdPath: IfdPathStandard,
|
|
||||||
TagType: TypeByte,
|
|
||||||
TagId: 0x22,
|
|
||||||
ChildIfdPath: "some ifd",
|
|
||||||
}
|
|
||||||
|
|
||||||
entries[2] = &IfdTagEntry{
|
|
||||||
IfdPath: IfdPathStandard,
|
|
||||||
TagType: TypeByte,
|
|
||||||
TagId: 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
ifd := &Ifd{
|
|
||||||
IfdPath: IfdPathStandard,
|
|
||||||
Entries: entries,
|
|
||||||
tagIndex: ti,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ib.AddTagsFromExisting(ifd, nil, nil, []uint16{0x11})
|
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
if ib.tags[0].tagId != 0x22 {
|
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||||
t.Fatalf("tag not correct")
|
|
||||||
} else if len(ib.tags) != 2 {
|
err = ib.AddTagsFromExisting(index.RootIfd, nil, nil, []uint16{0xff})
|
||||||
t.Fatalf("tag count not correct")
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
expected := []uint16{
|
||||||
|
0x000b,
|
||||||
|
0x0100,
|
||||||
|
0x013e,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ib.tags) != len(expected) {
|
||||||
|
t.Fatalf("Tag count not correct: (%d) != (%d)", len(ib.tags), len(expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tag := range ib.tags {
|
||||||
|
if tag.tagId != expected[i] {
|
||||||
|
t.Fatalf("Tag (%d) not correct: (0x%04x) != (0x%04x)", i, tag.tagId, expected[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindN_First_1(t *testing.T) {
|
func TestIfdBuilder_FindN__First_1(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -381,7 +341,7 @@ func TestFindN_First_1(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindN_First_2_1Returned(t *testing.T) {
|
func TestIfdBuilder_FindN__First_2_1Returned(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -437,7 +397,7 @@ func TestFindN_First_2_1Returned(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindN_First_2_2Returned(t *testing.T) {
|
func TestIfdBuilder_FindN__First_2_2Returned(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -520,7 +480,7 @@ func TestFindN_First_2_2Returned(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindN_Middle_WithDuplicates(t *testing.T) {
|
func TestIfdBuilder_FindN__Middle_WithDuplicates(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -606,7 +566,7 @@ func TestFindN_Middle_WithDuplicates(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindN_Middle_NoDuplicates(t *testing.T) {
|
func TestIfdBuilder_FindN__Middle_NoDuplicates(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -672,7 +632,7 @@ func TestFindN_Middle_NoDuplicates(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindN_Miss(t *testing.T) {
|
func TestIfdBuilder_FindN__Miss(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -689,7 +649,7 @@ func TestFindN_Miss(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFind_Hit(t *testing.T) {
|
func TestIfdBuilder_Find__Hit(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -753,7 +713,7 @@ func TestFind_Hit(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFind_Miss(t *testing.T) {
|
func TestIfdBuilder_Find__Miss(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -810,7 +770,7 @@ func TestFind_Miss(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReplace(t *testing.T) {
|
func TestIfdBuilder_Replace(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -878,7 +838,7 @@ func TestReplace(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReplaceN(t *testing.T) {
|
func TestIfdBuilder_ReplaceN(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -946,7 +906,7 @@ func TestReplaceN(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteFirst(t *testing.T) {
|
func TestIfdBuilder_DeleteFirst(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -1048,7 +1008,7 @@ func TestDeleteFirst(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteN(t *testing.T) {
|
func TestIfdBuilder_DeleteN(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -1150,7 +1110,7 @@ func TestDeleteN(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteN_Two(t *testing.T) {
|
func TestIfdBuilder_DeleteN_Two(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -1236,7 +1196,7 @@ func TestDeleteN_Two(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteAll(t *testing.T) {
|
func TestIfdBuilder_DeleteAll(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -1324,7 +1284,7 @@ func TestDeleteAll(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_IfdBuilder_CreateIfdBuilderFromExistingChain(t *testing.T) {
|
func TestIfdBuilder_CreateIfdBuilderFromExistingChain(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if state := recover(); state != nil {
|
if state := recover(); state != nil {
|
||||||
err := log.Wrap(state.(error))
|
err := log.Wrap(state.(error))
|
||||||
|
@ -1427,7 +1387,7 @@ func Test_IfdBuilder_CreateIfdBuilderFromExistingChain(t *testing.T) {
|
||||||
|
|
||||||
// TODO(dustin): !! Test with an actual GPS-attached image.
|
// TODO(dustin): !! Test with an actual GPS-attached image.
|
||||||
|
|
||||||
func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
||||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||||
|
|
||||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||||
|
@ -1546,7 +1506,7 @@ func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData_WithUpdate(t *testing.T) {
|
// func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData_WithUpdate(t *testing.T) {
|
||||||
// filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
// filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||||
|
|
||||||
// rawExif, err := SearchFileAndExtractExif(filepath)
|
// rawExif, err := SearchFileAndExtractExif(filepath)
|
||||||
|
@ -1843,7 +1803,7 @@ func ExampleIfdBuilder_SetStandardWithName() {
|
||||||
// alternative software
|
// alternative software
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_IfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) {
|
func TestIfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) {
|
||||||
ti := NewTagIndex()
|
ti := NewTagIndex()
|
||||||
|
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
@ -1884,7 +1844,7 @@ func Test_IfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewStandardBuilderTag_OneUnit(t *testing.T) {
|
func TestNewStandardBuilderTag__OneUnit(t *testing.T) {
|
||||||
ti := NewTagIndex()
|
ti := NewTagIndex()
|
||||||
|
|
||||||
it, err := ti.Get(IfdPathStandardExif, uint16(0x8833))
|
it, err := ti.Get(IfdPathStandardExif, uint16(0x8833))
|
||||||
|
@ -1901,7 +1861,7 @@ func TestNewStandardBuilderTag_OneUnit(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewStandardBuilderTag_TwoUnits(t *testing.T) {
|
func TestNewStandardBuilderTag__TwoUnits(t *testing.T) {
|
||||||
ti := NewTagIndex()
|
ti := NewTagIndex()
|
||||||
|
|
||||||
it, err := ti.Get(IfdPathStandardExif, uint16(0x8833))
|
it, err := ti.Get(IfdPathStandardExif, uint16(0x8833))
|
||||||
|
@ -1920,7 +1880,7 @@ func TestNewStandardBuilderTag_TwoUnits(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddStandardWithName(t *testing.T) {
|
func TestIfdBuilder_AddStandardWithName(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -1951,7 +1911,7 @@ func TestAddStandardWithName(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetOrCreateIbFromRootIb_Noop(t *testing.T) {
|
func TestGetOrCreateIbFromRootIb__Noop(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -1972,7 +1932,7 @@ func TestGetOrCreateIbFromRootIb_Noop(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetOrCreateIbFromRootIb_FqNoop(t *testing.T) {
|
func TestGetOrCreateIbFromRootIb__FqNoop(t *testing.T) {
|
||||||
im := NewIfdMapping()
|
im := NewIfdMapping()
|
||||||
|
|
||||||
err := LoadStandardIfds(im)
|
err := LoadStandardIfds(im)
|
||||||
|
@ -2010,7 +1970,7 @@ func TestGetOrCreateIbFromRootIb_InvalidChild(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetOrCreateIbFromRootIb_Child(t *testing.T) {
|
func TestGetOrCreateIbFromRootIb__Child(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if state := recover(); state != nil {
|
if state := recover(); state != nil {
|
||||||
err := log.Wrap(state.(error))
|
err := log.Wrap(state.(error))
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
package exif
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/dsoprea/go-logging"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getExifSimpleTestIb() *IfdBuilder {
|
||||||
|
defer func() {
|
||||||
|
if state := recover(); state != nil {
|
||||||
|
err := log.Wrap(state.(error))
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
im := NewIfdMapping()
|
||||||
|
|
||||||
|
err := LoadStandardIfds(im)
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
ti := NewTagIndex()
|
||||||
|
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||||
|
|
||||||
|
err = ib.AddStandard(0x000b, "asciivalue")
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
err = ib.AddStandard(0x00ff, []uint16{0x1122})
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
err = ib.AddStandard(0x0100, []uint32{0x33445566})
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
err = ib.AddStandard(0x013e, []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
return ib
|
||||||
|
}
|
||||||
|
|
||||||
|
func getExifSimpleTestIbBytes() []byte {
|
||||||
|
defer func() {
|
||||||
|
if state := recover(); state != nil {
|
||||||
|
err := log.Wrap(state.(error))
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
im := NewIfdMapping()
|
||||||
|
|
||||||
|
err := LoadStandardIfds(im)
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
ti := NewTagIndex()
|
||||||
|
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||||
|
|
||||||
|
err = ib.AddStandard(0x000b, "asciivalue")
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
err = ib.AddStandard(0x00ff, []uint16{0x1122})
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
err = ib.AddStandard(0x0100, []uint32{0x33445566})
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
err = ib.AddStandard(0x013e, []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
ibe := NewIfdByteEncoder()
|
||||||
|
|
||||||
|
exifData, err := ibe.EncodeToExif(ib)
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
return exifData
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if state := recover(); state != nil {
|
||||||
|
err := log.Wrap(state.(error))
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
im := NewIfdMapping()
|
||||||
|
|
||||||
|
err := LoadStandardIfds(im)
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
ti := NewTagIndex()
|
||||||
|
|
||||||
|
eh, index, err := Collect(im, ti, exifData)
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
if eh.ByteOrder != TestDefaultByteOrder {
|
||||||
|
t.Fatalf("EXIF byte-order is not correct: %v", eh.ByteOrder)
|
||||||
|
} else if eh.FirstIfdOffset != ExifDefaultFirstIfdOffset {
|
||||||
|
t.Fatalf("EXIF first IFD-offset not correct: (0x%02x)", eh.FirstIfdOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(index.Ifds) != 1 {
|
||||||
|
t.Fatalf("There wasn't exactly one IFD decoded: (%d)", len(index.Ifds))
|
||||||
|
}
|
||||||
|
|
||||||
|
ifd := index.RootIfd
|
||||||
|
|
||||||
|
if ifd.ByteOrder != TestDefaultByteOrder {
|
||||||
|
t.Fatalf("IFD byte-order not correct.")
|
||||||
|
} else if ifd.IfdPath != IfdStandard {
|
||||||
|
t.Fatalf("IFD name not correct.")
|
||||||
|
} else if ifd.Index != 0 {
|
||||||
|
t.Fatalf("IFD index not zero: (%d)", ifd.Index)
|
||||||
|
} else if ifd.Offset != uint32(0x0008) {
|
||||||
|
t.Fatalf("IFD offset not correct.")
|
||||||
|
} else if len(ifd.Entries) != 4 {
|
||||||
|
t.Fatalf("IFD number of entries not correct: (%d)", len(ifd.Entries))
|
||||||
|
} else if ifd.NextIfdOffset != uint32(0) {
|
||||||
|
t.Fatalf("Next-IFD offset is non-zero.")
|
||||||
|
} else if ifd.NextIfd != nil {
|
||||||
|
t.Fatalf("Next-IFD pointer is non-nil.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the values by using the actual, orginal types (this is awesome).
|
||||||
|
|
||||||
|
addressableData := exifData[ExifAddressableAreaStart:]
|
||||||
|
|
||||||
|
expected := []struct {
|
||||||
|
tagId uint16
|
||||||
|
value interface{}
|
||||||
|
}{
|
||||||
|
{tagId: 0x000b, value: "asciivalue"},
|
||||||
|
{tagId: 0x00ff, value: []uint16{0x1122}},
|
||||||
|
{tagId: 0x0100, value: []uint32{0x33445566}},
|
||||||
|
{tagId: 0x013e, value: []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, e := range ifd.Entries {
|
||||||
|
if e.TagId != expected[i].tagId {
|
||||||
|
t.Fatalf("Tag-ID for entry (%d) not correct: (0x%02x) != (0x%02x)", i, e.TagId, expected[i].tagId)
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := e.Value(addressableData, TestDefaultByteOrder)
|
||||||
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
if reflect.DeepEqual(value, expected[i].value) != true {
|
||||||
|
t.Fatalf("Value for entry (%d) not correct: [%v] != [%v]", i, value, expected[i].value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue