mirror of https://github.com/dsoprea/go-exif.git
encode: We now encode child IFDs as they occur.
- ..rather than after the normal tags.pull/3/head
parent
5996e32e27
commit
3c1c668a9f
162
ifd_builder.go
162
ifd_builder.go
|
@ -298,9 +298,7 @@ func NewIfdBuilderWithExistingIfd(ifd *Ifd) (ib *IfdBuilder) {
|
|||
|
||||
// NewIfdBuilderFromExistingChain creates a chain of IB instances from an
|
||||
// IFD chain generated from real data.
|
||||
func NewIfdBuilderFromExistingChain(rootIfd *Ifd, exifData []byte) (firstIb *IfdBuilder) {
|
||||
itevr := NewIfdTagEntryValueResolver(exifData, rootIfd.ByteOrder)
|
||||
|
||||
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).
|
||||
|
||||
var lastIb *IfdBuilder
|
||||
|
@ -318,15 +316,6 @@ func NewIfdBuilderFromExistingChain(rootIfd *Ifd, exifData []byte) (firstIb *Ifd
|
|||
err := newIb.AddTagsFromExisting(thisExistingIfd, itevr, nil, nil)
|
||||
log.PanicIf(err)
|
||||
|
||||
// Any child IFDs will still not be copied. Do that now.
|
||||
|
||||
for _, childIfd := range thisExistingIfd.Children {
|
||||
childIb := NewIfdBuilderFromExistingChain(childIfd, exifData)
|
||||
|
||||
err = newIb.AddChildIb(childIb)
|
||||
log.PanicIf(err)
|
||||
}
|
||||
|
||||
lastIb = newIb
|
||||
i++
|
||||
}
|
||||
|
@ -375,14 +364,14 @@ func (ib *IfdBuilder) SetThumbnail(data []byte) (err error) {
|
|||
if data == nil || len(data) == 0 {
|
||||
|
||||
// TODO(dustin): !! Debugging.
|
||||
fmt.Printf("Thumbnail empty.\n")
|
||||
// fmt.Printf("Thumbnail empty.\n")
|
||||
|
||||
log.Panic("thumbnail is empty")
|
||||
}
|
||||
|
||||
ib.thumbnailData = data
|
||||
|
||||
fmt.Printf("SETTING THUMBNAIL.\n")
|
||||
// fmt.Printf("SETTING THUMBNAIL.\n")
|
||||
|
||||
ibtvfb := NewIfdBuilderTagValueFromBytes(ib.thumbnailData)
|
||||
offsetBt := NewBuilderTag(ib.ii, ThumbnailOffsetTagId, TypeLong, ibtvfb)
|
||||
|
@ -398,7 +387,7 @@ fmt.Printf("SETTING THUMBNAIL.\n")
|
|||
|
||||
|
||||
// TODO(dustin): !! Debugging.
|
||||
fmt.Printf("Set thumbnail into IB.\n")
|
||||
// fmt.Printf("Set thumbnail into IB.\n")
|
||||
|
||||
|
||||
return nil
|
||||
|
@ -664,7 +653,7 @@ func (ib *IfdBuilder) Set(bt builderTag) (err error) {
|
|||
if err == nil {
|
||||
ib.tags[position] = bt
|
||||
} else if log.Is(err, ErrTagEntryNotFound) == true {
|
||||
err = ib.Add(bt)
|
||||
err = ib.add(bt)
|
||||
log.PanicIf(err)
|
||||
} else {
|
||||
log.Panic(err)
|
||||
|
@ -711,7 +700,7 @@ func (ib *IfdBuilder) Find(tagId uint16) (position int, err error) {
|
|||
return found[0], nil
|
||||
}
|
||||
|
||||
func (ib *IfdBuilder) Add(bt builderTag) (err error) {
|
||||
func (ib *IfdBuilder) add(bt builderTag) (err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -726,11 +715,24 @@ func (ib *IfdBuilder) Add(bt builderTag) (err error) {
|
|||
log.Panicf("builderTag value is not set: %s", bt)
|
||||
}
|
||||
|
||||
ib.tags = append(ib.tags, bt)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ib *IfdBuilder) Add(bt builderTag) (err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
if bt.value.IsIb() == true {
|
||||
log.Panicf("child IfdBuilders must be added via AddChildIb() not Add()")
|
||||
log.Panicf("child IfdBuilders must be added via AddChildIb() or AddTagsFromExisting(), not Add()")
|
||||
}
|
||||
|
||||
ib.tags = append(ib.tags, bt)
|
||||
err = ib.add(bt)
|
||||
log.PanicIf(err)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -757,16 +759,28 @@ func (ib *IfdBuilder) AddChildIb(childIb *IfdBuilder) (err error) {
|
|||
}
|
||||
}
|
||||
|
||||
bt := ib.NewBuilderTagFromBuilder(childIb)
|
||||
ib.tags = append(ib.tags, bt)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ib *IfdBuilder) NewBuilderTagFromBuilder(childIb *IfdBuilder) (bt builderTag) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.Panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
value := NewIfdBuilderTagValueFromIfdBuilder(childIb)
|
||||
|
||||
bt := NewChildIfdBuilderTag(
|
||||
bt = NewChildIfdBuilderTag(
|
||||
ib.ii,
|
||||
childIb.ifdTagId,
|
||||
value)
|
||||
|
||||
ib.tags = append(ib.tags, bt)
|
||||
|
||||
return nil
|
||||
return bt
|
||||
}
|
||||
|
||||
// AddTagsFromExisting does a verbatim copy of the entries in `ifd` to this
|
||||
|
@ -782,8 +796,10 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResol
|
|||
thumbnailData, err := ifd.Thumbnail()
|
||||
if err == nil {
|
||||
|
||||
// TODO(dustin): The thumbnail tags will be added out of order.
|
||||
|
||||
// TODO(dustin): !! Debugging.
|
||||
fmt.Printf("Importing thumbnail: %s\n", ifd.Identity())
|
||||
// fmt.Printf("Importing thumbnail: %s\n", ifd.Identity())
|
||||
|
||||
err = ib.SetThumbnail(thumbnailData)
|
||||
log.PanicIf(err)
|
||||
|
@ -792,17 +808,12 @@ fmt.Printf("Importing thumbnail: %s\n", ifd.Identity())
|
|||
} else {
|
||||
|
||||
// TODO(dustin): !! Debugging.
|
||||
fmt.Printf("NO THUMBNAIL FOUND: %s\n", ifd.Identity())
|
||||
// fmt.Printf("NO THUMBNAIL FOUND: %s\n", ifd.Identity())
|
||||
|
||||
}
|
||||
|
||||
for _, ite := range ifd.Entries {
|
||||
if ite.ChildIfdName != "" {
|
||||
// If we want to add an IFD tag, we'll have to build it first and
|
||||
// *then* add it via a different method.
|
||||
|
||||
continue
|
||||
} else if ite.TagId == ThumbnailOffsetTagId || ite.TagId == ThumbnailSizeTagId {
|
||||
for i, ite := range ifd.Entries {
|
||||
if ite.TagId == ThumbnailOffsetTagId || ite.TagId == ThumbnailSizeTagId {
|
||||
// These will be added on-the-fly when we encode.
|
||||
|
||||
continue
|
||||
|
@ -838,34 +849,79 @@ fmt.Printf("NO THUMBNAIL FOUND: %s\n", ifd.Identity())
|
|||
}
|
||||
}
|
||||
|
||||
var value *IfdBuilderTagValue
|
||||
var bt builderTag
|
||||
|
||||
if itevr == nil {
|
||||
// rawValueOffsetCopy is our own private copy of the original data.
|
||||
// It should always be four-bytes, but just copy whatever there is.
|
||||
rawValueOffsetCopy := make([]byte, len(ite.RawValueOffset))
|
||||
copy(rawValueOffsetCopy, ite.RawValueOffset)
|
||||
if ite.ChildIfdName != "" {
|
||||
// If we want to add an IFD tag, we'll have to build it first and
|
||||
// *then* add it via a different method.
|
||||
|
||||
value = NewIfdBuilderTagValueFromBytes(rawValueOffsetCopy)
|
||||
} else {
|
||||
var err error
|
||||
if itevr == nil {
|
||||
// We don't have any ability to resolve the structure of the
|
||||
// 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.Ii, ite.TagId, ite.TagType, value)
|
||||
} else {
|
||||
// Figure out which of the child-IFDs that are associated with
|
||||
// this IFD represents this specific child IFD.
|
||||
|
||||
valueBytes, err := itevr.ValueBytes(ite)
|
||||
if err != nil {
|
||||
if log.Is(err, ErrUnhandledUnknownTypedTag) == true {
|
||||
ifdBuilderLogger.Warningf(nil, "Unknown-type tag can't be parsed so it can't be copied to the new IFD.")
|
||||
continue
|
||||
var childIfd *Ifd
|
||||
for _, thisChildIfd := range ifd.Children {
|
||||
if thisChildIfd.ParentTagIndex != i {
|
||||
continue
|
||||
} 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)
|
||||
}
|
||||
|
||||
childIfd = thisChildIfd
|
||||
break
|
||||
}
|
||||
|
||||
log.Panic(err)
|
||||
if childIfd == nil {
|
||||
childTagIds := make([]string, len(ifd.Children))
|
||||
for j, childIfd := range ifd.Children {
|
||||
childTagIds[j] = fmt.Sprintf("0x%02x (parent tag-position %d)", childIfd.TagId, childIfd.ParentTagIndex)
|
||||
}
|
||||
|
||||
log.Panicf("could not find child IFD for child ITE: II=[%s] TAG-ID=(0x%02x) CURRENT-TAG-POSITION=(%d) CHILDREN=%v", ite.Ii, ite.TagId, i, childTagIds)
|
||||
}
|
||||
|
||||
childIb := NewIfdBuilderFromExistingChain(childIfd, itevr)
|
||||
bt = ib.NewBuilderTagFromBuilder(childIb)
|
||||
}
|
||||
} else {
|
||||
var value *IfdBuilderTagValue
|
||||
|
||||
if itevr == nil {
|
||||
// rawValueOffsetCopy is our own private copy of the original data.
|
||||
// It should always be four-bytes, but just copy whatever there is.
|
||||
rawValueOffsetCopy := make([]byte, len(ite.RawValueOffset))
|
||||
copy(rawValueOffsetCopy, ite.RawValueOffset)
|
||||
|
||||
value = NewIfdBuilderTagValueFromBytes(rawValueOffsetCopy)
|
||||
} else {
|
||||
var err error
|
||||
|
||||
valueBytes, err := itevr.ValueBytes(ite)
|
||||
if err != nil {
|
||||
if log.Is(err, ErrUnhandledUnknownTypedTag) == true {
|
||||
ifdBuilderLogger.Warningf(nil, "Unknown-type tag can't be parsed so it can't be copied to the new IFD.")
|
||||
continue
|
||||
}
|
||||
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
value = NewIfdBuilderTagValueFromBytes(valueBytes)
|
||||
}
|
||||
|
||||
value = NewIfdBuilderTagValueFromBytes(valueBytes)
|
||||
bt = NewBuilderTag(ifd.Ii, ite.TagId, ite.TagType, value)
|
||||
}
|
||||
|
||||
bt := NewBuilderTag(ifd.Ii, ite.TagId, ite.TagType, value)
|
||||
|
||||
err := ib.Add(bt)
|
||||
err := ib.add(bt)
|
||||
log.PanicIf(err)
|
||||
}
|
||||
|
||||
|
@ -883,7 +939,7 @@ func (ib *IfdBuilder) AddFromConfig(tagId uint16, value interface{}) (err error)
|
|||
|
||||
bt := NewStandardBuilderTagFromConfig(ib.ii, tagId, ib.byteOrder, value)
|
||||
|
||||
err = ib.Add(bt)
|
||||
err = ib.add(bt)
|
||||
log.PanicIf(err)
|
||||
|
||||
return nil
|
||||
|
@ -922,7 +978,7 @@ func (ib *IfdBuilder) AddFromConfigWithName(tagName string, value interface{}) (
|
|||
|
||||
bt := NewStandardBuilderTagFromConfigWithName(ib.ii, tagName, ib.byteOrder, value)
|
||||
|
||||
err = ib.Add(bt)
|
||||
err = ib.add(bt)
|
||||
log.PanicIf(err)
|
||||
|
||||
return nil
|
||||
|
|
|
@ -1211,7 +1211,7 @@ func TestDeleteAll(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewIfdBuilderFromExistingChain(t *testing.T) {
|
||||
func Test_IfdBuilder_CreateIfdBuilderFromExistingChain(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
|
@ -1223,13 +1223,15 @@ func TestNewIfdBuilderFromExistingChain(t *testing.T) {
|
|||
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
exifData, err := e.SearchAndExtractExif(filepath)
|
||||
rawExif, err := e.SearchAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := e.Collect(exifData)
|
||||
_, index, err := e.Collect(rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
ib := NewIfdBuilderFromExistingChain(index.RootIfd, exifData)
|
||||
itevr := NewIfdTagEntryValueResolver(rawExif, index.RootIfd.ByteOrder)
|
||||
ib := NewIfdBuilderFromExistingChain(index.RootIfd, itevr)
|
||||
|
||||
lines := ib.DumpToStrings()
|
||||
|
||||
expected := []string {
|
||||
|
@ -1295,7 +1297,7 @@ func TestNewIfdBuilderFromExistingChain(t *testing.T) {
|
|||
|
||||
// TODO(dustin): !! Test with an actual GPS-attached image.
|
||||
|
||||
func TestNewIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
||||
func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
e := NewExif()
|
||||
|
@ -1310,12 +1312,14 @@ func TestNewIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
|||
log.PanicIf(err)
|
||||
|
||||
originalTags := index.RootIfd.DumpTags()
|
||||
index.RootIfd.PrintTagTree(true)
|
||||
|
||||
// Encode back to binary.
|
||||
|
||||
ibe := NewIfdByteEncoder()
|
||||
|
||||
rootIb := NewIfdBuilderFromExistingChain(index.RootIfd, rawExif)
|
||||
itevr := NewIfdTagEntryValueResolver(rawExif, index.RootIfd.ByteOrder)
|
||||
rootIb := NewIfdBuilderFromExistingChain(index.RootIfd, itevr)
|
||||
|
||||
updatedExif, err := ibe.EncodeToExif(rootIb)
|
||||
log.PanicIf(err)
|
||||
|
@ -1326,8 +1330,11 @@ func TestNewIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
|||
log.PanicIf(err)
|
||||
|
||||
recoveredTags := index.RootIfd.DumpTags()
|
||||
index.RootIfd.PrintTagTree(true)
|
||||
|
||||
|
||||
return
|
||||
|
||||
// Validate that all of the same IFDs were presented.
|
||||
|
||||
originalIfdTags := make([][2]interface{}, 0)
|
||||
|
@ -1405,7 +1412,7 @@ func TestNewIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewIfdBuilderWithExistingIfd(t *testing.T) {
|
||||
func Test_IfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) {
|
||||
tagId := IfdTagIdWithIdentityOrFail(GpsIi)
|
||||
|
||||
parentIfd := &Ifd{
|
||||
|
|
|
@ -330,9 +330,17 @@ type Ifd struct {
|
|||
ByteOrder binary.ByteOrder
|
||||
|
||||
Ii IfdIdentity
|
||||
TagId uint16
|
||||
|
||||
Id int
|
||||
|
||||
ParentIfd *Ifd
|
||||
|
||||
// ParentTagIndex is our tag position in the parent IFD, if we had a parent
|
||||
// (if `ParentIfd` is not nil and we weren't an IFD referenced as a sibling
|
||||
// instead of as a child).
|
||||
ParentTagIndex int
|
||||
|
||||
Name string
|
||||
Index int
|
||||
Offset uint32
|
||||
|
@ -429,7 +437,7 @@ func (ifd Ifd) String() string {
|
|||
parentOffset = ifd.ParentIfd.Offset
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Ifd<ID=(%d) PARENT-IFD=[%s] IFD=[%s] IDX=(%d) COUNT=(%d) OFF=(0x%04x) CHILDREN=(%d) PARENT=(0x%04x) NEXT-IFD=(0x%04x)", ifd.Id, ifd.Ii.ParentIfdName, ifd.Ii.IfdName, ifd.Index, len(ifd.Entries), ifd.Offset, len(ifd.Children), parentOffset, ifd.NextIfdOffset)
|
||||
return fmt.Sprintf("Ifd<ID=(%d) PARENT-IFD=[%s] IFD=[%s] INDEX=(%d) COUNT=(%d) OFF=(0x%04x) CHILDREN=(%d) PARENT=(0x%04x) NEXT-IFD=(0x%04x)>", ifd.Id, ifd.Ii.ParentIfdName, ifd.Ii.IfdName, ifd.Index, len(ifd.Entries), ifd.Offset, len(ifd.Children), parentOffset, ifd.NextIfdOffset)
|
||||
}
|
||||
|
||||
func (ifd *Ifd) Thumbnail() (data []byte, err error) {
|
||||
|
@ -497,7 +505,7 @@ func (ifd *Ifd) DumpTags() []*IfdTagEntry {
|
|||
return ifd.dumpTags(nil)
|
||||
}
|
||||
|
||||
func (ifd *Ifd) printTagTree(index, level int, nextLink bool) {
|
||||
func (ifd *Ifd) printTagTree(populateValues bool, index, level int, nextLink bool) {
|
||||
indent := strings.Repeat(" ", level * 2)
|
||||
|
||||
prefix := " "
|
||||
|
@ -505,7 +513,7 @@ func (ifd *Ifd) printTagTree(index, level int, nextLink bool) {
|
|||
prefix = ">"
|
||||
}
|
||||
|
||||
fmt.Printf("%s%sIFD: %s INDEX=(%d)\n", indent, prefix, ifd, index)
|
||||
fmt.Printf("%s%sIFD: %s\n", indent, prefix, ifd)
|
||||
|
||||
// Quickly create an index of the child-IFDs.
|
||||
|
||||
|
@ -530,7 +538,15 @@ func (ifd *Ifd) printTagTree(index, level int, nextLink bool) {
|
|||
tagName = it.Name
|
||||
}
|
||||
|
||||
fmt.Printf("%s - TAG: %s NAME=[%s]\n", indent, tag, tagName)
|
||||
var value interface{}
|
||||
if populateValues == true {
|
||||
var err error
|
||||
|
||||
value, err = ifd.TagValue(tag)
|
||||
log.PanicIf(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s - TAG: %s NAME=[%s] VALUE=[%v]\n", indent, tag, tagName, value)
|
||||
}
|
||||
|
||||
if tag.ChildIfdName != "" {
|
||||
|
@ -541,7 +557,7 @@ func (ifd *Ifd) printTagTree(index, level int, nextLink bool) {
|
|||
log.Panicf("alien child IFD referenced by a tag: [%s]", tag.ChildIfdName)
|
||||
}
|
||||
|
||||
childIfd.printTagTree(0, level + 1, false)
|
||||
childIfd.printTagTree(populateValues, 0, level + 1, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -550,13 +566,13 @@ func (ifd *Ifd) printTagTree(index, level int, nextLink bool) {
|
|||
}
|
||||
|
||||
if ifd.NextIfd != nil {
|
||||
ifd.NextIfd.printTagTree(index + 1, level, true)
|
||||
ifd.NextIfd.printTagTree(populateValues, index + 1, level, true)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintTagTree prints the IFD hierarchy.
|
||||
func (ifd *Ifd) PrintTagTree() {
|
||||
ifd.printTagTree(0, 0, false)
|
||||
func (ifd *Ifd) PrintTagTree(populateValues bool) {
|
||||
ifd.printTagTree(populateValues, 0, 0, false)
|
||||
}
|
||||
|
||||
func (ifd *Ifd) printIfdTree(level int, nextLink bool) {
|
||||
|
@ -671,9 +687,16 @@ func (ifd *Ifd) DumpTree() []string {
|
|||
|
||||
type QueuedIfd struct {
|
||||
Ii IfdIdentity
|
||||
TagId uint16
|
||||
|
||||
Index int
|
||||
Offset uint32
|
||||
Parent *Ifd
|
||||
|
||||
// ParentTagIndex is our tag position in the parent IFD, if we had a parent
|
||||
// (if `ParentIfd` is not nil and we weren't an IFD referenced as a sibling
|
||||
// instead of as a child).
|
||||
ParentTagIndex int
|
||||
}
|
||||
|
||||
|
||||
|
@ -700,6 +723,8 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32) (index IfdIndex, err error
|
|||
queue := []QueuedIfd{
|
||||
{
|
||||
Ii: RootIi,
|
||||
TagId: 0xffff,
|
||||
|
||||
Index: 0,
|
||||
Offset: rootIfdOffset,
|
||||
},
|
||||
|
@ -712,14 +737,14 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32) (index IfdIndex, err error
|
|||
break
|
||||
}
|
||||
|
||||
ii := queue[0].Ii
|
||||
|
||||
qi := queue[0]
|
||||
|
||||
ii := qi.Ii
|
||||
name := ii.IfdName
|
||||
index := queue[0].Index
|
||||
offset := queue[0].Offset
|
||||
|
||||
parentIfd := queue[0].Parent
|
||||
index := qi.Index
|
||||
offset := qi.Offset
|
||||
parentIfd := qi.Parent
|
||||
|
||||
queue = queue[1:]
|
||||
|
||||
|
@ -741,53 +766,62 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32) (index IfdIndex, err error
|
|||
entriesByTagId[tag.TagId] = append(tags, tag)
|
||||
}
|
||||
|
||||
ifd := Ifd{
|
||||
ifd := &Ifd{
|
||||
addressableData: ie.exifData[ExifAddressableAreaStart:],
|
||||
|
||||
ByteOrder: ie.byteOrder,
|
||||
|
||||
Ii: ii,
|
||||
TagId: qi.TagId,
|
||||
|
||||
Id: id,
|
||||
|
||||
ParentIfd: parentIfd,
|
||||
ParentTagIndex: qi.ParentTagIndex,
|
||||
|
||||
Name: name,
|
||||
Index: index,
|
||||
Offset: offset,
|
||||
Entries: entries,
|
||||
EntriesByTagId: entriesByTagId,
|
||||
|
||||
// This is populated as each child is processed.
|
||||
Children: make([]*Ifd, 0),
|
||||
|
||||
NextIfdOffset: nextIfdOffset,
|
||||
thumbnailData: thumbnailData,
|
||||
}
|
||||
|
||||
// Add ourselves to a big list of IFDs.
|
||||
ifds = append(ifds, &ifd)
|
||||
ifds = append(ifds, ifd)
|
||||
|
||||
// Install ourselves into a by-id lookup table (keys are unique).
|
||||
tree[id] = &ifd
|
||||
tree[id] = ifd
|
||||
|
||||
// Install into by-name buckets.
|
||||
|
||||
if list_, found := lookup[ii]; found == true {
|
||||
lookup[ii] = append(list_, &ifd)
|
||||
lookup[ii] = append(list_, ifd)
|
||||
} else {
|
||||
list_ = make([]*Ifd, 1)
|
||||
list_[0] = &ifd
|
||||
list_[0] = ifd
|
||||
|
||||
lookup[ii] = list_
|
||||
}
|
||||
|
||||
// Add a link from the previous IFD in the chain to us.
|
||||
if previousIfd, found := edges[offset]; found == true {
|
||||
previousIfd.NextIfd = &ifd
|
||||
previousIfd.NextIfd = ifd
|
||||
}
|
||||
|
||||
// Attach as a child to our parent (where we appeared as a tag in
|
||||
// that IFD).
|
||||
if parentIfd != nil {
|
||||
parentIfd.Children = append(parentIfd.Children, &ifd)
|
||||
parentIfd.Children = append(parentIfd.Children, ifd)
|
||||
}
|
||||
|
||||
// Determine if any of our entries is a child IFD and queue it.
|
||||
for _, entry := range entries {
|
||||
for i, entry := range entries {
|
||||
if entry.ChildIfdName == "" {
|
||||
continue
|
||||
}
|
||||
|
@ -799,9 +833,12 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32) (index IfdIndex, err error
|
|||
|
||||
qi := QueuedIfd{
|
||||
Ii: childIi,
|
||||
TagId: entry.TagId,
|
||||
|
||||
Index: 0,
|
||||
Offset: entry.ValueOffset,
|
||||
Parent: &ifd,
|
||||
Parent: ifd,
|
||||
ParentTagIndex: i,
|
||||
}
|
||||
|
||||
queue = append(queue, qi)
|
||||
|
@ -810,10 +847,11 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32) (index IfdIndex, err error
|
|||
// If there's another IFD in the chain.
|
||||
if nextIfdOffset != 0 {
|
||||
// Allow the next link to know what the previous link was.
|
||||
edges[nextIfdOffset] = &ifd
|
||||
edges[nextIfdOffset] = ifd
|
||||
|
||||
qi := QueuedIfd{
|
||||
Ii: ii,
|
||||
TagId: 0xffff,
|
||||
Index: index + 1,
|
||||
Offset: nextIfdOffset,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue