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,15 +14,15 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"fmt"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"io/ioutil"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-exif"
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -30,7 +30,6 @@ var (
|
|||
printAsJsonArg = false
|
||||
)
|
||||
|
||||
|
||||
type IfdEntry struct {
|
||||
IfdName string `json:"ifd_name"`
|
||||
ParentIfdName string `json:"parent_ifd_name"`
|
||||
|
@ -131,7 +130,7 @@ func main() {
|
|||
return nil
|
||||
}
|
||||
|
||||
_, err = exif.Visit(rawExif, visitor)
|
||||
_, err = exif.Visit(ti, rawExif, visitor)
|
||||
log.PanicIf(err)
|
||||
|
||||
if printAsJsonArg == true {
|
||||
|
|
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)
|
||||
|
|
20
exif_test.go
20
exif_test.go
|
@ -1,20 +1,19 @@
|
|||
package exif
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"io/ioutil"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
|
||||
func TestVisit(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -23,6 +22,8 @@ func TestVisit(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
ti := NewTagIndex()
|
||||
|
||||
// Open the file.
|
||||
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
@ -63,7 +64,7 @@ func TestVisit(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
it, err := tagIndex.Get(ii, tagId)
|
||||
it, err := ti.Get(ii, tagId)
|
||||
if err != nil {
|
||||
if log.Is(err, ErrTagNotFound) {
|
||||
fmt.Printf("Unknown tag: [%v] (%04x)\n", ii, tagId)
|
||||
|
@ -94,7 +95,7 @@ func TestVisit(t *testing.T) {
|
|||
return nil
|
||||
}
|
||||
|
||||
_, err = Visit(data[foundAt:], visitor)
|
||||
_, err = Visit(ti, data[foundAt:], visitor)
|
||||
log.PanicIf(err)
|
||||
|
||||
// for _, line := range tags {
|
||||
|
@ -203,7 +204,6 @@ func TestSearchAndExtractExif(t *testing.T) {
|
|||
imageData, err := ioutil.ReadFile(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
|
||||
rawExif, err := SearchAndExtractExif(imageData)
|
||||
log.PanicIf(err)
|
||||
|
||||
|
@ -225,7 +225,9 @@ func TestCollect(t *testing.T) {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
rootIfd := index.RootIfd
|
||||
|
|
|
@ -154,48 +154,12 @@ func (bt *BuilderTag) SetValue(byteOrder binary.ByteOrder, value interface{}) (e
|
|||
|
||||
// NewStandardBuilderTag constructs a `BuilderTag` instance. The type is looked
|
||||
// up. `ii` is the type of IFD that owns this tag.
|
||||
func NewStandardBuilderTag(ii IfdIdentity, tagId uint16, byteOrder binary.ByteOrder, value interface{}) *BuilderTag {
|
||||
it, err := tagIndex.Get(ii, tagId)
|
||||
log.PanicIf(err)
|
||||
|
||||
func NewStandardBuilderTag(ii IfdIdentity, it *IndexedTag, byteOrder binary.ByteOrder, value interface{}) *BuilderTag {
|
||||
typeId := it.Type
|
||||
tt := NewTagType(typeId, byteOrder)
|
||||
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
var ed EncodedData
|
||||
if it.Type == TypeUndefined {
|
||||
var err error
|
||||
|
||||
ed, err = EncodeUndefined(ii, tagId, value)
|
||||
log.PanicIf(err)
|
||||
} else {
|
||||
var err error
|
||||
|
||||
ed, err = ve.EncodeWithType(tt, value)
|
||||
log.PanicIf(err)
|
||||
}
|
||||
|
||||
tagValue := NewIfdBuilderTagValueFromBytes(ed.Encoded)
|
||||
|
||||
return NewBuilderTag(
|
||||
ii,
|
||||
tagId,
|
||||
typeId,
|
||||
tagValue)
|
||||
}
|
||||
|
||||
// NewStandardBuilderTagWithName allows us to easily generate solid, consistent
|
||||
// tags for testing with. `ii` is the type of IFD that owns this tag. This can
|
||||
// not be an IFD (IFDs are not associated with standardized, official names).
|
||||
func NewStandardBuilderTagWithName(ii IfdIdentity, tagName string, byteOrder binary.ByteOrder, value interface{}) *BuilderTag {
|
||||
it, err := tagIndex.GetWithName(ii, tagName)
|
||||
log.PanicIf(err)
|
||||
|
||||
tt := NewTagType(it.Type, byteOrder)
|
||||
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
var ed EncodedData
|
||||
if it.Type == TypeUndefined {
|
||||
var err error
|
||||
|
@ -214,7 +178,7 @@ func NewStandardBuilderTagWithName(ii IfdIdentity, tagName string, byteOrder bin
|
|||
return NewBuilderTag(
|
||||
ii,
|
||||
it.Id,
|
||||
it.Type,
|
||||
typeId,
|
||||
tagValue)
|
||||
}
|
||||
|
||||
|
@ -242,9 +206,11 @@ type IfdBuilder struct {
|
|||
// thumbnailData is populated with thumbnail data if there was thumbnail
|
||||
// data. Otherwise, it's nil.
|
||||
thumbnailData []byte
|
||||
|
||||
tagIndex *TagIndex
|
||||
}
|
||||
|
||||
func NewIfdBuilder(ii IfdIdentity, byteOrder binary.ByteOrder) (ib *IfdBuilder) {
|
||||
func NewIfdBuilder(tagIndex *TagIndex, ii IfdIdentity, byteOrder binary.ByteOrder) (ib *IfdBuilder) {
|
||||
ifdTagId, _ := IfdTagIdWithIdentity(ii)
|
||||
|
||||
ib = &IfdBuilder{
|
||||
|
@ -256,6 +222,8 @@ func NewIfdBuilder(ii IfdIdentity, byteOrder binary.ByteOrder) (ib *IfdBuilder)
|
|||
|
||||
byteOrder: byteOrder,
|
||||
tags: make([]*BuilderTag, 0),
|
||||
|
||||
tagIndex: tagIndex,
|
||||
}
|
||||
|
||||
return ib
|
||||
|
@ -278,6 +246,7 @@ func NewIfdBuilderWithExistingIfd(ifd *Ifd) (ib *IfdBuilder) {
|
|||
ifdTagId: ifdTagId,
|
||||
byteOrder: ifd.ByteOrder,
|
||||
existingOffset: ifd.Offset,
|
||||
tagIndex: ifd.tagIndex,
|
||||
}
|
||||
|
||||
return ib
|
||||
|
@ -293,7 +262,7 @@ func NewIfdBuilderFromExistingChain(rootIfd *Ifd, itevr *IfdTagEntryValueResolve
|
|||
for thisExistingIfd := rootIfd; thisExistingIfd != nil; thisExistingIfd = thisExistingIfd.NextIfd {
|
||||
ii := thisExistingIfd.Identity()
|
||||
|
||||
newIb := NewIfdBuilder(ii, thisExistingIfd.ByteOrder)
|
||||
newIb := NewIfdBuilder(rootIfd.tagIndex, ii, thisExistingIfd.ByteOrder)
|
||||
if firstIb == nil {
|
||||
firstIb = newIb
|
||||
} else {
|
||||
|
@ -350,7 +319,7 @@ func GetOrCreateIbFromRootIb(rootIb *IfdBuilder, ifdDesignation string) (ib *Ifd
|
|||
|
||||
case "ifd1":
|
||||
if ib.nextIb == nil {
|
||||
ib.nextIb = NewIfdBuilder(RootIi, ib.byteOrder)
|
||||
ib.nextIb = NewIfdBuilder(ib.tagIndex, RootIi, ib.byteOrder)
|
||||
}
|
||||
|
||||
return ib.nextIb, nil
|
||||
|
@ -359,7 +328,7 @@ func GetOrCreateIbFromRootIb(rootIb *IfdBuilder, ifdDesignation string) (ib *Ifd
|
|||
exifIb, err := ib.ChildWithIfdIdentity(ExifIi)
|
||||
if err != nil {
|
||||
if log.Is(err, ErrChildIbNotFound) == true {
|
||||
exifIb = NewIfdBuilder(ExifIi, ib.byteOrder)
|
||||
exifIb = NewIfdBuilder(exifIb.tagIndex, ExifIi, ib.byteOrder)
|
||||
|
||||
err := ib.AddChildIb(exifIb)
|
||||
log.PanicIf(err)
|
||||
|
@ -374,7 +343,7 @@ func GetOrCreateIbFromRootIb(rootIb *IfdBuilder, ifdDesignation string) (ib *Ifd
|
|||
exifIb, err := ib.ChildWithIfdIdentity(ExifIi)
|
||||
if err != nil {
|
||||
if log.Is(err, ErrChildIbNotFound) == true {
|
||||
exifIb = NewIfdBuilder(ExifIi, ib.byteOrder)
|
||||
exifIb = NewIfdBuilder(exifIb.tagIndex, ExifIi, ib.byteOrder)
|
||||
|
||||
err := ib.AddChildIb(exifIb)
|
||||
log.PanicIf(err)
|
||||
|
@ -391,7 +360,7 @@ func GetOrCreateIbFromRootIb(rootIb *IfdBuilder, ifdDesignation string) (ib *Ifd
|
|||
iopIb, err := exifIb.ChildWithIfdIdentity(ExifIopIi)
|
||||
if err != nil {
|
||||
if log.Is(err, ErrChildIbNotFound) == true {
|
||||
iopIb = NewIfdBuilder(ExifIopIi, ib.byteOrder)
|
||||
iopIb = NewIfdBuilder(iopIb.tagIndex, ExifIopIi, ib.byteOrder)
|
||||
|
||||
err := exifIb.AddChildIb(iopIb)
|
||||
log.PanicIf(err)
|
||||
|
@ -406,7 +375,7 @@ func GetOrCreateIbFromRootIb(rootIb *IfdBuilder, ifdDesignation string) (ib *Ifd
|
|||
gpsIb, err := ib.ChildWithIfdIdentity(GpsIi)
|
||||
if err != nil {
|
||||
if log.Is(err, ErrChildIbNotFound) == true {
|
||||
gpsIb = NewIfdBuilder(GpsIi, ib.byteOrder)
|
||||
gpsIb = NewIfdBuilder(gpsIb.tagIndex, GpsIi, ib.byteOrder)
|
||||
|
||||
err := ib.AddChildIb(gpsIb)
|
||||
log.PanicIf(err)
|
||||
|
@ -477,7 +446,10 @@ func (ib *IfdBuilder) SetThumbnail(data []byte) (err error) {
|
|||
err = ib.Set(offsetBt)
|
||||
log.PanicIf(err)
|
||||
|
||||
sizeBt := NewStandardBuilderTag(ib.ii, ThumbnailSizeTagId, ib.byteOrder, []uint32{uint32(len(ib.thumbnailData))})
|
||||
thumbnailSizeIt, err := ib.tagIndex.Get(ib.ii, ThumbnailSizeTagId)
|
||||
log.PanicIf(err)
|
||||
|
||||
sizeBt := NewStandardBuilderTag(ib.ii, thumbnailSizeIt, ib.byteOrder, []uint32{uint32(len(ib.thumbnailData))})
|
||||
|
||||
err = ib.Set(sizeBt)
|
||||
log.PanicIf(err)
|
||||
|
@ -517,7 +489,7 @@ func (ib *IfdBuilder) printTagTree(levels int) {
|
|||
if isChildIb == true {
|
||||
tagName = "<Child IFD>"
|
||||
} else {
|
||||
it, err := tagIndex.Get(tag.ii, tag.tagId)
|
||||
it, err := ib.tagIndex.Get(tag.ii, tag.tagId)
|
||||
if log.Is(err, ErrTagNotFound) == true {
|
||||
tagName = "<UNKNOWN>"
|
||||
} else if err != nil {
|
||||
|
@ -817,7 +789,7 @@ func (ib *IfdBuilder) FindTagWithName(tagName string) (bt *BuilderTag, err error
|
|||
}
|
||||
}()
|
||||
|
||||
it, err := tagIndex.GetWithName(ib.ii, tagName)
|
||||
it, err := ib.tagIndex.GetWithName(ib.ii, tagName)
|
||||
log.PanicIf(err)
|
||||
|
||||
found, err := ib.FindN(it.Id, 1)
|
||||
|
@ -1025,10 +997,8 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResol
|
|||
} else {
|
||||
var err error
|
||||
|
||||
|
||||
// TODO(dustin): !! Not correct. If we're adding from existing and it's an unknown-type tag that we can't parse, we're just going to be seting the placeholder even though there's nothing stopping us from just taking the raw bytes (other than some design decisions that we'd have to make in order to do this).
|
||||
|
||||
|
||||
valueBytes, err := itevr.ValueBytes(ite)
|
||||
if err != nil {
|
||||
if log.Is(err, ErrUnhandledUnknownTypedTag) == true {
|
||||
|
@ -1060,7 +1030,10 @@ func (ib *IfdBuilder) AddStandard(tagId uint16, value interface{}) (err error) {
|
|||
}
|
||||
}()
|
||||
|
||||
bt := NewStandardBuilderTag(ib.ii, tagId, ib.byteOrder, value)
|
||||
it, err := ib.tagIndex.Get(ib.ii, tagId)
|
||||
log.PanicIf(err)
|
||||
|
||||
bt := NewStandardBuilderTag(ib.ii, it, ib.byteOrder, value)
|
||||
|
||||
err = ib.add(bt)
|
||||
log.PanicIf(err)
|
||||
|
@ -1078,7 +1051,10 @@ func (ib *IfdBuilder) AddStandardWithName(tagName string, value interface{}) (er
|
|||
}
|
||||
}()
|
||||
|
||||
bt := NewStandardBuilderTagWithName(ib.ii, tagName, ib.byteOrder, value)
|
||||
it, err := ib.tagIndex.GetWithName(ib.ii, tagName)
|
||||
log.PanicIf(err)
|
||||
|
||||
bt := NewStandardBuilderTag(ib.ii, it, ib.byteOrder, value)
|
||||
|
||||
err = ib.add(bt)
|
||||
log.PanicIf(err)
|
||||
|
@ -1097,7 +1073,10 @@ func (ib *IfdBuilder) SetStandard(tagId uint16, value interface{}) (err error) {
|
|||
|
||||
// TODO(dustin): !! Add test for this function.
|
||||
|
||||
bt := NewStandardBuilderTag(ib.ii, tagId, ib.byteOrder, value)
|
||||
it, err := ib.tagIndex.Get(ib.ii, tagId)
|
||||
log.PanicIf(err)
|
||||
|
||||
bt := NewStandardBuilderTag(ib.ii, it, ib.byteOrder, value)
|
||||
|
||||
i, err := ib.Find(tagId)
|
||||
if err != nil {
|
||||
|
@ -1125,7 +1104,10 @@ func (ib *IfdBuilder) SetStandardWithName(tagName string, value interface{}) (er
|
|||
|
||||
// TODO(dustin): !! Add test for this function.
|
||||
|
||||
bt := NewStandardBuilderTagWithName(ib.ii, tagName, ib.byteOrder, value)
|
||||
it, err := ib.tagIndex.GetWithName(ib.ii, tagName)
|
||||
log.PanicIf(err)
|
||||
|
||||
bt := NewStandardBuilderTag(ib.ii, it, ib.byteOrder, value)
|
||||
|
||||
i, err := ib.Find(bt.tagId)
|
||||
if err != nil {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package exif
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"bytes"
|
||||
"reflect"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
@ -94,7 +94,6 @@ func Test_ByteWriter_WriteFourBytes_TooMany(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
func Test_IfdDataAllocator_Allocate_InitialOffset1(t *testing.T) {
|
||||
addressableOffset := uint32(0)
|
||||
ida := newIfdDataAllocator(addressableOffset)
|
||||
|
@ -169,7 +168,6 @@ func Test_IfdDataAllocator_Allocate_InitialOffset2(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
func Test_IfdByteEncoder__Arithmetic(t *testing.T) {
|
||||
ibe := NewIfdByteEncoder()
|
||||
|
||||
|
@ -190,9 +188,13 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_embedded1(t *testing.T) {
|
|||
|
||||
ibe := NewIfdByteEncoder()
|
||||
|
||||
ib := NewIfdBuilder(GpsIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, GpsIi, TestDefaultByteOrder)
|
||||
|
||||
bt := NewStandardBuilderTag(GpsIi, uint16(0x0000), TestDefaultByteOrder, []uint8 { uint8(0x12) })
|
||||
it, err := ti.Get(ib.ii, uint16(0x0000))
|
||||
log.PanicIf(err)
|
||||
|
||||
bt := NewStandardBuilderTag(GpsIi, it, TestDefaultByteOrder, []uint8{uint8(0x12)})
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
bw := NewByteWriter(b, TestDefaultByteOrder)
|
||||
|
@ -215,9 +217,13 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_embedded1(t *testing.T) {
|
|||
func Test_IfdByteEncoder_encodeTagToBytes_bytes_embedded2(t *testing.T) {
|
||||
ibe := NewIfdByteEncoder()
|
||||
|
||||
ib := NewIfdBuilder(GpsIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, GpsIi, TestDefaultByteOrder)
|
||||
|
||||
bt := NewStandardBuilderTag(GpsIi, uint16(0x0000), TestDefaultByteOrder, []uint8 { uint8(0x12), uint8(0x34), uint8(0x56), uint8(0x78) })
|
||||
it, err := ti.Get(ib.ii, uint16(0x0000))
|
||||
log.PanicIf(err)
|
||||
|
||||
bt := NewStandardBuilderTag(GpsIi, it, TestDefaultByteOrder, []uint8{uint8(0x12), uint8(0x34), uint8(0x56), uint8(0x78)})
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
bw := NewByteWriter(b, TestDefaultByteOrder)
|
||||
|
@ -240,7 +246,8 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_embedded2(t *testing.T) {
|
|||
func Test_IfdByteEncoder_encodeTagToBytes_bytes_allocated(t *testing.T) {
|
||||
ibe := NewIfdByteEncoder()
|
||||
|
||||
ib := NewIfdBuilder(GpsIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, GpsIi, TestDefaultByteOrder)
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
bw := NewByteWriter(b, TestDefaultByteOrder)
|
||||
|
@ -248,7 +255,10 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_allocated(t *testing.T) {
|
|||
addressableOffset := uint32(0x1234)
|
||||
ida := newIfdDataAllocator(addressableOffset)
|
||||
|
||||
bt := NewStandardBuilderTag(GpsIi, uint16(0x0000), TestDefaultByteOrder, []uint8 { uint8(0x12), uint8(0x34), uint8(0x56), uint8(0x78), uint8(0x9a) })
|
||||
it, err := ti.Get(ib.ii, uint16(0x0000))
|
||||
log.PanicIf(err)
|
||||
|
||||
bt := NewStandardBuilderTag(GpsIi, it, TestDefaultByteOrder, []uint8{uint8(0x12), uint8(0x34), uint8(0x56), uint8(0x78), uint8(0x9a)})
|
||||
|
||||
childIfdBlock, err := ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0))
|
||||
log.PanicIf(err)
|
||||
|
@ -265,7 +275,7 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_allocated(t *testing.T) {
|
|||
|
||||
// Test that another allocation encodes to the new offset.
|
||||
|
||||
bt = NewStandardBuilderTag(GpsIi, uint16(0x0000), TestDefaultByteOrder, []uint8 { uint8(0xbc), uint8(0xde), uint8(0xf0), uint8(0x12), uint8(0x34) })
|
||||
bt = NewStandardBuilderTag(GpsIi, it, TestDefaultByteOrder, []uint8{uint8(0xbc), uint8(0xde), uint8(0xf0), uint8(0x12), uint8(0x34)})
|
||||
|
||||
childIfdBlock, err = ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0))
|
||||
log.PanicIf(err)
|
||||
|
@ -290,7 +300,8 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_allocated(t *testing.T) {
|
|||
func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withoutAllocate(t *testing.T) {
|
||||
ibe := NewIfdByteEncoder()
|
||||
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
bw := NewByteWriter(b, TestDefaultByteOrder)
|
||||
|
@ -298,7 +309,7 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withoutAllocate(t *testing.T
|
|||
addressableOffset := uint32(0x1234)
|
||||
ida := newIfdDataAllocator(addressableOffset)
|
||||
|
||||
childIb := NewIfdBuilder(ExifIi, TestDefaultByteOrder)
|
||||
childIb := NewIfdBuilder(ti, ExifIi, TestDefaultByteOrder)
|
||||
tagValue := NewIfdBuilderTagValueFromIfdBuilder(childIb)
|
||||
bt := NewChildIfdBuilderTag(RootIi, IfdExifId, tagValue)
|
||||
|
||||
|
@ -320,7 +331,8 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) {
|
|||
// space for and then attach to a tag (which would normally be an entry,
|
||||
// then, in a higher IFD).
|
||||
|
||||
childIb := NewIfdBuilder(ExifIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
childIb := NewIfdBuilder(ti, ExifIi, TestDefaultByteOrder)
|
||||
|
||||
childIbTestTag := &BuilderTag{
|
||||
ii: ExifIi,
|
||||
|
@ -343,7 +355,7 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) {
|
|||
|
||||
ibe := NewIfdByteEncoder()
|
||||
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
bw := NewByteWriter(b, TestDefaultByteOrder)
|
||||
|
@ -443,10 +455,14 @@ func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) {
|
|||
|
||||
ibe := NewIfdByteEncoder()
|
||||
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
it, err := ib.tagIndex.Get(ib.ii, uint16(0x000b))
|
||||
log.PanicIf(err)
|
||||
|
||||
valueString := "testvalue"
|
||||
bt := NewStandardBuilderTag(RootIi, uint16(0x000b), TestDefaultByteOrder, valueString)
|
||||
bt := NewStandardBuilderTag(RootIi, it, TestDefaultByteOrder, valueString)
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
bw := NewByteWriter(b, TestDefaultByteOrder)
|
||||
|
@ -474,7 +490,6 @@ func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) {
|
|||
t.Fatalf("Child IFD not have been allocated.")
|
||||
}
|
||||
|
||||
|
||||
ite, err := ParseOneTag(RootIi, TestDefaultByteOrder, tagBytes, false)
|
||||
log.PanicIf(err)
|
||||
|
||||
|
@ -508,7 +523,8 @@ func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) {
|
|||
}
|
||||
|
||||
func getExifSimpleTestIb() *IfdBuilder {
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
err := ib.AddStandard(0x000b, "asciivalue")
|
||||
log.PanicIf(err)
|
||||
|
@ -526,7 +542,9 @@ func getExifSimpleTestIb() *IfdBuilder {
|
|||
}
|
||||
|
||||
func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
|
||||
eh, index, err := Collect(exifData)
|
||||
ti := NewTagIndex()
|
||||
|
||||
eh, index, err := Collect(ti, exifData)
|
||||
log.PanicIf(err)
|
||||
|
||||
if eh.ByteOrder != TestDefaultByteOrder {
|
||||
|
@ -557,7 +575,6 @@ func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
|
|||
t.Fatalf("Next-IFD pointer is non-nil.")
|
||||
}
|
||||
|
||||
|
||||
// Verify the values by using the actual, orginal types (this is awesome).
|
||||
|
||||
addressableData := exifData[ExifAddressableAreaStart:]
|
||||
|
@ -632,7 +649,6 @@ func Test_IfdByteEncoder_encodeIfdToBytes_simple(t *testing.T) {
|
|||
// - Next IFD offset
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
|
||||
// IFD data block.
|
||||
|
||||
// - The one ASCII value
|
||||
|
@ -657,7 +673,6 @@ func Test_IfdByteEncoder_encodeIfdToBytes_fullExif(t *testing.T) {
|
|||
|
||||
ib := getExifSimpleTestIb()
|
||||
|
||||
|
||||
// Encode the IFD to a byte stream.
|
||||
|
||||
ibe := NewIfdByteEncoder()
|
||||
|
@ -677,7 +692,6 @@ func Test_IfdByteEncoder_encodeIfdToBytes_fullExif(t *testing.T) {
|
|||
t.Fatalf("Table-and-data size doesn't match what was expected: (%d) != (%d + %d)", len(tableAndAllocated), tableSize, allocatedDataSize)
|
||||
}
|
||||
|
||||
|
||||
// Wrap the IFD in a formal EXIF block.
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
|
@ -691,7 +705,6 @@ func Test_IfdByteEncoder_encodeIfdToBytes_fullExif(t *testing.T) {
|
|||
_, err = b.Write(tableAndAllocated)
|
||||
log.PanicIf(err)
|
||||
|
||||
|
||||
// Now, try parsing it as EXIF data, making sure to resolve (read:
|
||||
// dereference) the values (which will include the allocated ones).
|
||||
|
||||
|
@ -709,7 +722,6 @@ func Test_IfdByteEncoder_EncodeToExifPayload(t *testing.T) {
|
|||
|
||||
ib := getExifSimpleTestIb()
|
||||
|
||||
|
||||
// Encode the IFD to a byte stream.
|
||||
|
||||
ibe := NewIfdByteEncoder()
|
||||
|
@ -730,7 +742,6 @@ func Test_IfdByteEncoder_EncodeToExifPayload(t *testing.T) {
|
|||
_, err = b.Write(encodedIfds)
|
||||
log.PanicIf(err)
|
||||
|
||||
|
||||
// Now, try parsing it as EXIF data, making sure to resolve (read:
|
||||
// dereference) the values (which will include the allocated ones).
|
||||
|
||||
|
@ -759,7 +770,8 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
err := ib.AddStandard(0x000b, "asciivalue")
|
||||
log.PanicIf(err)
|
||||
|
@ -767,10 +779,9 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
|
|||
err = ib.AddStandard(0x00ff, []uint16{0x1122})
|
||||
log.PanicIf(err)
|
||||
|
||||
|
||||
// Add a child IB right in the middle.
|
||||
|
||||
childIb := NewIfdBuilder(ExifIi, TestDefaultByteOrder)
|
||||
childIb := NewIfdBuilder(ti, ExifIi, TestDefaultByteOrder)
|
||||
|
||||
err = childIb.AddStandardWithName("ISOSpeedRatings", []uint16{0x1122})
|
||||
log.PanicIf(err)
|
||||
|
@ -781,15 +792,13 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
|
|||
err = ib.AddChildIb(childIb)
|
||||
log.PanicIf(err)
|
||||
|
||||
|
||||
err = ib.AddStandard(0x0100, []uint32{0x33445566})
|
||||
log.PanicIf(err)
|
||||
|
||||
|
||||
// Add another child IB, just to ensure a little more punishment and make
|
||||
// sure we're managing our allocation offsets correctly.
|
||||
|
||||
childIb2 := NewIfdBuilder(GpsIi, TestDefaultByteOrder)
|
||||
childIb2 := NewIfdBuilder(ti, GpsIi, TestDefaultByteOrder)
|
||||
|
||||
err = childIb2.AddStandardWithName("GPSAltitudeRef", []uint8{0x11, 0x22})
|
||||
log.PanicIf(err)
|
||||
|
@ -797,15 +806,13 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
|
|||
err = ib.AddChildIb(childIb2)
|
||||
log.PanicIf(err)
|
||||
|
||||
|
||||
err = ib.AddStandard(0x013e, []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
|
||||
log.PanicIf(err)
|
||||
|
||||
|
||||
// Link to another IB (sibling relationship). The root/standard IFD may
|
||||
// occur twice in some JPEGs (for thumbnail or FlashPix images).
|
||||
|
||||
nextIb := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
nextIb := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
err = nextIb.AddStandard(0x0101, []uint32{0x11223344})
|
||||
log.PanicIf(err)
|
||||
|
@ -815,7 +822,6 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
|
|||
|
||||
ib.SetNextIb(nextIb)
|
||||
|
||||
|
||||
// Encode.
|
||||
|
||||
ibe := NewIfdByteEncoder()
|
||||
|
@ -823,10 +829,9 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
|
|||
exifData, err := ibe.EncodeToExif(ib)
|
||||
log.PanicIf(err)
|
||||
|
||||
|
||||
// Parse.
|
||||
|
||||
_, index, err := Collect(exifData)
|
||||
_, index, err := Collect(ti, exifData)
|
||||
log.PanicIf(err)
|
||||
|
||||
tagsDump := index.RootIfd.DumpTree()
|
||||
|
@ -875,7 +880,9 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
|
|||
func ExampleIfdByteEncoder_EncodeToExif() {
|
||||
// Construct an IFD.
|
||||
|
||||
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)
|
||||
ti := NewTagIndex()
|
||||
|
||||
ib := NewIfdBuilder(ti, RootIi, TestDefaultByteOrder)
|
||||
|
||||
err := ib.AddStandardWithName("ProcessingSoftware", "asciivalue")
|
||||
log.PanicIf(err)
|
||||
|
@ -895,7 +902,6 @@ func ExampleIfdByteEncoder_EncodeToExif() {
|
|||
err = ib.AddStandardWithName("ShutterSpeedValue", []SignedRational{{Numerator: 0x11112222, Denominator: 0x33334444}})
|
||||
log.PanicIf(err)
|
||||
|
||||
|
||||
// Encode it.
|
||||
|
||||
ibe := NewIfdByteEncoder()
|
||||
|
@ -903,10 +909,9 @@ func ExampleIfdByteEncoder_EncodeToExif() {
|
|||
exifData, err := ibe.EncodeToExif(ib)
|
||||
log.PanicIf(err)
|
||||
|
||||
|
||||
// Parse it so we can see it.
|
||||
|
||||
_, index, err := Collect(exifData)
|
||||
_, index, err := Collect(ti, exifData)
|
||||
log.PanicIf(err)
|
||||
|
||||
// addressableData is the byte-slice where the allocated data can be
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
@ -194,6 +199,7 @@ func TestAddTagsFromExisting(t *testing.T) {
|
|||
ifd := &Ifd{
|
||||
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)
|
||||
|
||||
|
@ -237,6 +244,7 @@ func TestAddTagsFromExisting__Includes(t *testing.T) {
|
|||
ifd := &Ifd{
|
||||
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)
|
||||
|
||||
|
@ -276,6 +285,7 @@ func TestAddTagsFromExisting__Excludes(t *testing.T) {
|
|||
ifd := &Ifd{
|
||||
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,
|
||||
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)
|
||||
|
|
|
@ -2,12 +2,12 @@ package exif
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"encoding/binary"
|
||||
|
||||
|
@ -23,7 +23,6 @@ var (
|
|||
ErrNoGpsTags = errors.New("no gps tags")
|
||||
)
|
||||
|
||||
|
||||
// IfdTagEnumerator knows how to decode an IFD and all of the tags it
|
||||
// describes.
|
||||
//
|
||||
|
@ -96,19 +95,20 @@ func (ife *IfdTagEnumerator) getUint32() (value uint32, raw []byte, err error) {
|
|||
return value, raw, nil
|
||||
}
|
||||
|
||||
|
||||
type IfdEnumerate struct {
|
||||
exifData []byte
|
||||
buffer *bytes.Buffer
|
||||
byteOrder binary.ByteOrder
|
||||
currentOffset uint32
|
||||
tagIndex *TagIndex
|
||||
}
|
||||
|
||||
func NewIfdEnumerate(exifData []byte, byteOrder binary.ByteOrder) *IfdEnumerate {
|
||||
func NewIfdEnumerate(tagIndex *TagIndex, exifData []byte, byteOrder binary.ByteOrder) *IfdEnumerate {
|
||||
return &IfdEnumerate{
|
||||
exifData: exifData,
|
||||
buffer: bytes.NewBuffer(exifData),
|
||||
byteOrder: byteOrder,
|
||||
tagIndex: tagIndex,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ func (ie *IfdEnumerate) getTagEnumerator(ifdOffset uint32) (ite *IfdTagEnumerato
|
|||
return ite
|
||||
}
|
||||
|
||||
func (ie *IfdEnumerate) parseTag(ii IfdIdentity, tagIndex int, ite *IfdTagEnumerator, resolveValue bool) (tag *IfdTagEntry, err error) {
|
||||
func (ie *IfdEnumerate) parseTag(ii IfdIdentity, tagPosition int, ite *IfdTagEnumerator, resolveValue bool) (tag *IfdTagEntry, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -152,7 +152,7 @@ func (ie *IfdEnumerate) parseTag(ii IfdIdentity, tagIndex int, ite *IfdTagEnumer
|
|||
tag = &IfdTagEntry{
|
||||
Ii: ii,
|
||||
TagId: tagId,
|
||||
TagIndex: tagIndex,
|
||||
TagIndex: tagPosition,
|
||||
TagType: tagType,
|
||||
UnitCount: unitCount,
|
||||
ValueOffset: valueOffset,
|
||||
|
@ -336,7 +336,6 @@ func (ie *IfdEnumerate) parseThumbnail(offsetIte, lengthIte *IfdTagEntry) (thumb
|
|||
|
||||
addressableData := ie.exifData[ExifAddressableAreaStart:]
|
||||
|
||||
|
||||
vRaw, err := lengthIte.Value(addressableData, ie.byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
|
@ -398,7 +397,6 @@ func (ie *IfdEnumerate) Scan(ifdOffset uint32, visitor RawTagVisitor, resolveVal
|
|||
return nil
|
||||
}
|
||||
|
||||
|
||||
// Ifd represents a single parsed IFD.
|
||||
type Ifd struct {
|
||||
// This is just for convenience, just so that we can easily get the values
|
||||
|
@ -435,6 +433,8 @@ type Ifd struct {
|
|||
NextIfd *Ifd
|
||||
|
||||
thumbnailData []byte
|
||||
|
||||
tagIndex *TagIndex
|
||||
}
|
||||
|
||||
func (ifd *Ifd) ChildWithIfdIdentity(ii IfdIdentity) (childIfd *Ifd, err error) {
|
||||
|
@ -524,7 +524,7 @@ func (ifd *Ifd) FindTagWithName(tagName string) (results []*IfdTagEntry, err err
|
|||
}()
|
||||
|
||||
ii := ifd.Identity()
|
||||
it, err := tagIndex.GetWithName(ii, tagName)
|
||||
it, err := ifd.tagIndex.GetWithName(ii, tagName)
|
||||
if log.Is(err, ErrTagNotFound) == true {
|
||||
log.Panic(ErrTagNotStandard)
|
||||
} else if err != nil {
|
||||
|
@ -630,7 +630,7 @@ func (ifd *Ifd) printTagTree(populateValues bool, index, level int, nextLink boo
|
|||
if tag.ChildIfdName != "" {
|
||||
fmt.Printf("%s - TAG: %s\n", indent, tag)
|
||||
} else {
|
||||
it, err := tagIndex.Get(ifd.Identity(), tag.TagId)
|
||||
it, err := ifd.tagIndex.Get(ifd.Identity(), tag.TagId)
|
||||
|
||||
tagName := ""
|
||||
if err == nil {
|
||||
|
@ -785,10 +785,8 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
}
|
||||
}()
|
||||
|
||||
|
||||
// TODO(dustin): !! Also add functionality to update the GPS info.
|
||||
|
||||
|
||||
gi = new(GpsInfo)
|
||||
|
||||
if ifd.Ii != GpsIi {
|
||||
|
@ -801,7 +799,6 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
log.Panic(ErrNoGpsTags)
|
||||
}
|
||||
|
||||
|
||||
tags, found := ifd.EntriesByTagId[TagLatitudeId]
|
||||
if found == false {
|
||||
log.Panicf("latitude not found")
|
||||
|
@ -834,7 +831,6 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
longitudeRefValue, err := ifd.TagValue(tags[0])
|
||||
log.PanicIf(err)
|
||||
|
||||
|
||||
// Parse location.
|
||||
|
||||
latitudeRaw := latitudeValue.([]Rational)
|
||||
|
@ -855,7 +851,6 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
Seconds: int(float64(longitudeRaw[2].Numerator) / float64(longitudeRaw[2].Denominator)),
|
||||
}
|
||||
|
||||
|
||||
// Parse altitude.
|
||||
|
||||
altitudeTags, foundAltitude := ifd.EntriesByTagId[TagAltitudeId]
|
||||
|
@ -877,7 +872,6 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
gi.Altitude = altitude
|
||||
}
|
||||
|
||||
|
||||
// Parse time.
|
||||
|
||||
timestampTags, foundTimestamp := ifd.EntriesByTagId[TagTimestampId]
|
||||
|
@ -910,7 +904,6 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
return gi, nil
|
||||
}
|
||||
|
||||
|
||||
type ParsedTagVisitor func(*Ifd, *IfdTagEntry) error
|
||||
|
||||
func (ifd *Ifd) EnumerateTagsRecursively(visitor ParsedTagVisitor) (err error) {
|
||||
|
@ -937,7 +930,6 @@ func (ifd *Ifd) EnumerateTagsRecursively(visitor ParsedTagVisitor) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
|
||||
type QueuedIfd struct {
|
||||
Ii IfdIdentity
|
||||
TagId uint16
|
||||
|
@ -952,7 +944,6 @@ type QueuedIfd struct {
|
|||
ParentTagIndex int
|
||||
}
|
||||
|
||||
|
||||
type IfdIndex struct {
|
||||
RootIfd *Ifd
|
||||
Ifds []*Ifd
|
||||
|
@ -960,7 +951,6 @@ type IfdIndex struct {
|
|||
Lookup map[IfdIdentity][]*Ifd
|
||||
}
|
||||
|
||||
|
||||
// Scan enumerates the different EXIF blocks (called IFDs).
|
||||
func (ie *IfdEnumerate) Collect(rootIfdOffset uint32, resolveValues bool) (index IfdIndex, err error) {
|
||||
defer func() {
|
||||
|
@ -1043,6 +1033,8 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32, resolveValues bool) (index
|
|||
|
||||
NextIfdOffset: nextIfdOffset,
|
||||
thumbnailData: thumbnailData,
|
||||
|
||||
tagIndex: ie.tagIndex,
|
||||
}
|
||||
|
||||
// Add ourselves to a big list of IFDs.
|
||||
|
@ -1146,7 +1138,6 @@ func (ie *IfdEnumerate) setChildrenIndex(ifd *Ifd) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
|
||||
// ParseOneIfd is a hack to use an IE to parse a raw IFD block. Can be used for
|
||||
// testing.
|
||||
func ParseOneIfd(ii IfdIdentity, byteOrder binary.ByteOrder, ifdBlock []byte, visitor RawTagVisitor, resolveValues bool) (nextIfdOffset uint32, entries []*IfdTagEntry, err error) {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package exif
|
||||
|
||||
import (
|
||||
"path"
|
||||
"testing"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
|
@ -53,7 +53,9 @@ func TestIfdTagEntry_ValueBytes_RealData(t *testing.T) {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
eh, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
eh, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
var ite *IfdTagEntry
|
||||
|
@ -95,7 +97,9 @@ func TestIfdTagEntry_Resolver_ValueBytes(t *testing.T) {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
eh, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
eh, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
var ite *IfdTagEntry
|
||||
|
@ -138,7 +142,9 @@ func TestIfdTagEntry_Resolver_ValueBytes__Unknown_Field_And_Nonroot_Ifd(t *testi
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
eh, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
eh, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
ii, _ := IfdIdOrFail(IfdStandard, IfdExif)
|
||||
|
@ -176,7 +182,9 @@ func Test_Ifd_FindTagWithId_Hit(t *testing.T) {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
ifd := index.RootIfd
|
||||
|
@ -195,7 +203,9 @@ func Test_Ifd_FindTagWithId_Miss(t *testing.T) {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
ifd := index.RootIfd
|
||||
|
@ -214,7 +224,9 @@ func Test_Ifd_FindTagWithName_Hit(t *testing.T) {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
ifd := index.RootIfd
|
||||
|
@ -233,7 +245,9 @@ func Test_Ifd_FindTagWithName_Miss(t *testing.T) {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
ifd := index.RootIfd
|
||||
|
@ -252,7 +266,9 @@ func Test_Ifd_FindTagWithName_NonStandard(t *testing.T) {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
ifd := index.RootIfd
|
||||
|
@ -271,7 +287,9 @@ func Test_Ifd_Thumbnail(t *testing.T) {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
ifd := index.RootIfd
|
||||
|
@ -307,7 +325,9 @@ func TestIfd_GpsInfo(t *testing.T) {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
ifd, err := index.RootIfd.ChildWithIfdIdentity(GpsIi)
|
||||
|
@ -335,9 +355,10 @@ func TestIfd_EnumerateTagsRecursively(t *testing.T) {
|
|||
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)
|
||||
|
||||
|
@ -487,7 +508,9 @@ func ExampleIfd_EnumerateTagsRecursively() {
|
|||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
cb := func(ifd *Ifd, ite *IfdTagEntry) error {
|
||||
|
@ -503,14 +526,15 @@ func ExampleIfd_EnumerateTagsRecursively() {
|
|||
// Output:
|
||||
}
|
||||
|
||||
|
||||
func ExampleIfd_GpsInfo() {
|
||||
filepath := path.Join(assetsPath, "gps.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
log.PanicIf(err)
|
||||
|
||||
_, index, err := Collect(rawExif)
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
ifd, err := index.RootIfd.ChildWithIfdIdentity(GpsIi)
|
||||
|
|
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()
|
||||
}
|
||||
|
|
|
@ -14,7 +14,9 @@ var (
|
|||
)
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
it, err := tagIndex.Get(RootIi, 0x10f)
|
||||
ti := NewTagIndex()
|
||||
|
||||
it, err := ti.Get(RootIi, 0x10f)
|
||||
log.PanicIf(err)
|
||||
|
||||
if it.Is("IFD", 0x10f) == false || it.IsName("IFD", "Make") == false {
|
||||
|
@ -23,7 +25,9 @@ func TestGet(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetWithName(t *testing.T) {
|
||||
it, err := tagIndex.GetWithName(RootIi, "Make")
|
||||
ti := NewTagIndex()
|
||||
|
||||
it, err := ti.GetWithName(RootIi, "Make")
|
||||
log.PanicIf(err)
|
||||
|
||||
if it.Is("IFD", 0x10f) == false || it.Is("IFD", 0x10f) == false {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package exif
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
@ -11,7 +11,6 @@ func TestUndefinedValue_ExifVersion(t *testing.T) {
|
|||
byteOrder := TestDefaultByteOrder
|
||||
ii := ExifIi
|
||||
|
||||
|
||||
// Create our unknown-type tag's value using the fact that we know it's a
|
||||
// non-null-terminated string.
|
||||
|
||||
|
@ -23,7 +22,6 @@ func TestUndefinedValue_ExifVersion(t *testing.T) {
|
|||
ed, err := ve.EncodeWithType(tt, valueString)
|
||||
log.PanicIf(err)
|
||||
|
||||
|
||||
// Create the tag using the official "unknown" type now that we already
|
||||
// have the bytes.
|
||||
|
||||
|
@ -36,11 +34,12 @@ func TestUndefinedValue_ExifVersion(t *testing.T) {
|
|||
value: encodedValue,
|
||||
}
|
||||
|
||||
|
||||
// Stage the build.
|
||||
|
||||
ti := NewTagIndex()
|
||||
|
||||
ibe := NewIfdByteEncoder()
|
||||
ib := NewIfdBuilder(ii, byteOrder)
|
||||
ib := NewIfdBuilder(ti, ii, byteOrder)
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
bw := NewByteWriter(b, byteOrder)
|
||||
|
@ -48,7 +47,6 @@ func TestUndefinedValue_ExifVersion(t *testing.T) {
|
|||
addressableOffset := uint32(0x1234)
|
||||
ida := newIfdDataAllocator(addressableOffset)
|
||||
|
||||
|
||||
// Encode.
|
||||
|
||||
_, err = ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0))
|
||||
|
|
Loading…
Reference in New Issue