ifd_builder_encode: Bugfixed next-IFD offsets.

- Affected sibling IFDs.
pull/3/head
Dustin Oprea 2018-05-05 02:01:18 -04:00
parent 887842e85a
commit 6c71ccf651
2 changed files with 86 additions and 166 deletions

View File

@ -2,7 +2,6 @@ package exif
import (
"bytes"
// "fmt"
"encoding/binary"
@ -288,15 +287,18 @@ func (ibe *IfdByteEncoder) encodeIfdToBytes(ib *IfdBuilder, ifdAddressableOffset
// N the link from this IFD to the next IFD that will be written in the
// next cycle.
if setNextIb == true {
nextIfdOffsetToWrite += dataSize
// fmt.Printf("SETTING NEXT-IFD FOR %s TO: (0x%04x)\n", ib.ii, nextIfdOffsetToWrite)
} else {
nextIfdOffsetToWrite = 0
}
// Write address of next IFD in chain. This will be the original
// allocation offset plus the size of everything we have allocated for
// this IFD and its child-IFDs.
// Write address of next IFD in chain.
err = bw.WriteUint32(nextIfdOffsetToWrite)
log.PanicIf(err)
offset := ifdAddressableOffset + dataSize
err := bw.WriteUint32(offset)
log.PanicIf(err)
} else {
err := bw.WriteUint32(0)
log.PanicIf(err)
}
_, err = b.Write(dataBytes)
log.PanicIf(err)
@ -336,8 +338,6 @@ func (ibe *IfdByteEncoder) encodeAndAttachIfd(ib *IfdBuilder, ifdAddressableOffs
for thisIb := ib; thisIb != nil; thisIb = thisIb.nextIb {
// Do a dry-run in order to pre-determine its size requirement.
// fmt.Printf("BUILDING IFD: %s ifdAddressableOffset=(0x%04x)\n", ib.ii, ifdAddressableOffset)
_, tableSize, allocatedDataSize, _, err := ibe.encodeIfdToBytes(ib, ifdAddressableOffset, 0, false)
log.PanicIf(err)

View File

@ -5,6 +5,7 @@ import (
"bytes"
"reflect"
"fmt"
"strings"
"github.com/dsoprea/go-logging"
)
@ -793,18 +794,18 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
log.PanicIf(err)
// // Link to another IB (sibling relationship). The root/standard IFD may
// // occur twice in some JPEGs (for thumbnail or FlashPix images).
// 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(RootIi, TestDefaultByteOrder)
// err = nextIb.AddFromConfig(0x0101, []uint32 { 0x11223344 })
// log.PanicIf(err)
err = nextIb.AddFromConfig(0x0101, []uint32 { 0x11223344 })
log.PanicIf(err)
// err = nextIb.AddFromConfig(0x0102, []uint16 { 0x5566 })
// log.PanicIf(err)
err = nextIb.AddFromConfig(0x0102, []uint16 { 0x5566 })
log.PanicIf(err)
// ib.SetNextIb(nextIb)
ib.SetNextIb(nextIb)
// Encode.
@ -824,184 +825,103 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
tagsDump := index.RootIfd.DumpTree()
expected := []string {
"[ROOT]->[IFD] (0x000b)",
"[ROOT]->[IFD] (0x00ff)",
"[ROOT]->[IFD] (0x8769)",
"[IFD]->[Exif] (0x8827)",
"[IFD]->[Exif] (0x8833)",
"[ROOT]->[IFD] (0x0100)",
"[ROOT]->[IFD] (0x8825)",
"[IFD]->[GPSInfo] (0x0005)",
"[ROOT]->[IFD] (0x013e)",
}
actual := strings.Join(tagsDump, "\n")
if reflect.DeepEqual(tagsDump, expected) != true {
expected :=
`> IFD [ROOT]->[IFD]:(0) TOP
- (0x000b)
- (0x00ff)
- (0x8769)
> IFD [IFD]->[Exif]:(0) TOP
- (0x8827)
- (0x8833)
< IFD [IFD]->[Exif]:(0) BOTTOM
- (0x0100)
- (0x8825)
> IFD [IFD]->[GPSInfo]:(0) TOP
- (0x0005)
< IFD [IFD]->[GPSInfo]:(0) BOTTOM
- (0x013e)
< IFD [ROOT]->[IFD]:(0) BOTTOM
* LINKING TO SIBLING IFD [IFD]:(1)
> IFD [ROOT]->[IFD]:(1) TOP
- (0x8827)
- (0x8833)
< IFD [ROOT]->[IFD]:(1) BOTTOM`
if actual != expected {
fmt.Printf("\n")
fmt.Printf("Actual:\n")
fmt.Printf("\n")
for i, line := range tagsDump {
fmt.Printf("%d: %s\n", i, line)
}
fmt.Printf("%s\n", actual)
fmt.Printf("\n")
fmt.Printf("Expected:\n")
fmt.Printf("\n")
for i, line := range expected {
fmt.Printf("%d: %s\n", i, line)
}
fmt.Printf("%s\n", expected)
fmt.Printf("\n")
t.Fatalf("IFD hierarchy not correct.")
}
}
// func ExampleIfdByteEncoder_EncodeToExif() {
// // Construct an IFD.
func ExampleIfdByteEncoder_EncodeToExif() {
// Construct an IFD.
// ib := NewIfdBuilder(RootIi, EncodeDefaultByteOrder)
ib := NewIfdBuilder(RootIi, EncodeDefaultByteOrder)
// err := ib.AddFromConfigWithName("ProcessingSoftware", "asciivalue")
// log.PanicIf(err)
err := ib.AddFromConfigWithName("ProcessingSoftware", "asciivalue")
log.PanicIf(err)
// err = ib.AddFromConfigWithName("DotRange", []uint8 { 0x11 })
// log.PanicIf(err)
err = ib.AddFromConfigWithName("DotRange", []uint8 { 0x11 })
log.PanicIf(err)
// err = ib.AddFromConfigWithName("SubfileType", []uint16 { 0x2233 })
// log.PanicIf(err)
err = ib.AddFromConfigWithName("SubfileType", []uint16 { 0x2233 })
log.PanicIf(err)
// err = ib.AddFromConfigWithName("ImageWidth", []uint32 { 0x44556677 })
// log.PanicIf(err)
err = ib.AddFromConfigWithName("ImageWidth", []uint32 { 0x44556677 })
log.PanicIf(err)
// err = ib.AddFromConfigWithName("WhitePoint", []Rational { { Numerator: 0x11112222, Denominator: 0x33334444 } })
// log.PanicIf(err)
err = ib.AddFromConfigWithName("WhitePoint", []Rational { { Numerator: 0x11112222, Denominator: 0x33334444 } })
log.PanicIf(err)
// err = ib.AddFromConfigWithName("ShutterSpeedValue", []SignedRational { { Numerator: 0x11112222, Denominator: 0x33334444 } })
// log.PanicIf(err)
err = ib.AddFromConfigWithName("ShutterSpeedValue", []SignedRational { { Numerator: 0x11112222, Denominator: 0x33334444 } })
log.PanicIf(err)
// // Encode it.
// Encode it.
// ibe := NewIfdByteEncoder()
ibe := NewIfdByteEncoder()
// exifData, err := ibe.EncodeToExif(ib)
// log.PanicIf(err)
exifData, err := ibe.EncodeToExif(ib)
log.PanicIf(err)
// // Parse it so we can see it.
// Parse it so we can see it.
// e := NewExif()
e := NewExif()
// _, index, err := e.Collect(exifData)
// log.PanicIf(err)
_, index, err := e.Collect(exifData)
log.PanicIf(err)
// // addressableData is the byte-slice where the allocated data can be
// // resolved (where position 0x0 will correlate with offset 0x0).
// addressableData := exifData[ExifAddressableAreaStart:]
// addressableData is the byte-slice where the allocated data can be
// resolved (where position 0x0 will correlate with offset 0x0).
addressableData := exifData[ExifAddressableAreaStart:]
// for i, e := range index.RootIfd.Entries {
// value, err := e.Value(addressableData, EncodeDefaultByteOrder)
// log.PanicIf(err)
for i, e := range index.RootIfd.Entries {
value, err := e.Value(addressableData, EncodeDefaultByteOrder)
log.PanicIf(err)
// fmt.Printf("%d: %s [%v]\n", i, e, value)
// }
fmt.Printf("%d: %s [%v]\n", i, e, value)
}
// // Output:
// //
// // 0: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0b) TAG-TYPE=[ASCII] UNIT-COUNT=(11)> [asciivalue]
// // 1: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x150) TAG-TYPE=[BYTE] UNIT-COUNT=(1)> [[17]]
// // 2: IfdTagEntry<TAG-IFD=[] TAG-ID=(0xff) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> [[8755]]
// // 3: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x100) TAG-TYPE=[LONG] UNIT-COUNT=(1)> [[1146447479]]
// // 4: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x13e) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> [[{286335522 858997828}]]
// // 5: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x9201) TAG-TYPE=[SRATIONAL] UNIT-COUNT=(1)> [[{286335522 858997828}]]
// }
// func ExampleIfdByteEncoder_EncodeToExif_WithChild() {
// // Construct an IFD.
// ib := NewIfdBuilder(RootIi, EncodeDefaultByteOrder)
// err := ib.AddFromConfigWithName("ProcessingSoftware", "asciivalue")
// log.PanicIf(err)
// err = ib.AddFromConfigWithName("DotRange", []uint8 { 0x11 })
// log.PanicIf(err)
// err = ib.AddFromConfigWithName("SubfileType", []uint16 { 0x2233 })
// log.PanicIf(err)
// // Add a child IB right in the middle.
// childIb := NewIfdBuilder(ExifIi, EncodeDefaultByteOrder)
// err = childIb.AddFromConfigWithName("ISOSpeedRatings", []uint16 { 0x1122 })
// log.PanicIf(err)
// err = childIb.AddFromConfigWithName("ISOSpeed", []uint32 { 0x33445566 })
// log.PanicIf(err)
// err = ib.AddChildIb(childIb)
// log.PanicIf(err)
// err = ib.AddFromConfigWithName("ImageWidth", []uint32 { 0x44556677 })
// log.PanicIf(err)
// err = ib.AddFromConfigWithName("WhitePoint", []Rational { { Numerator: 0x11112222, Denominator: 0x33334444 } })
// log.PanicIf(err)
// err = ib.AddFromConfigWithName("ShutterSpeedValue", []SignedRational { { Numerator: 0x11112222, Denominator: 0x33334444 } })
// log.PanicIf(err)
// // Encode it.
// ibe := NewIfdByteEncoder()
// exifData, err := ibe.EncodeToExif(ib)
// log.PanicIf(err)
// // Parse it so we can see it.
// e := NewExif()
// _, index, err := e.Collect(exifData)
// log.PanicIf(err)
// // addressableData is the byte-slice where the allocated data can be
// // resolved (where position 0x0 will correlate with offset 0x0).
// addressableData := exifData[ExifAddressableAreaStart:]
// for i, e := range index.RootIfd.Entries {
// value, err := e.Value(addressableData, EncodeDefaultByteOrder)
// log.PanicIf(err)
// fmt.Printf("%d: %s %v\n", i, e, value)
// }
// // Output:
// //
// // 0: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0b) TAG-TYPE=[ASCII] UNIT-COUNT=(11)> asciivalue
// // 1: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x150) TAG-TYPE=[BYTE] UNIT-COUNT=(1)> [17]
// // 2: IfdTagEntry<TAG-IFD=[] TAG-ID=(0xff) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> [8755]
// // 3: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x100) TAG-TYPE=[LONG] UNIT-COUNT=(1)> [1146447479]
// // 4: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x13e) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> [{286335522 858997828}]
// // 5: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x9201) TAG-TYPE=[SRATIONAL] UNIT-COUNT=(1)> [{286335522 858997828}]
// }
// TODO(dustin): !! Write test with both chained and child IFDs
// Output:
//
// 0: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0b) TAG-TYPE=[ASCII] UNIT-COUNT=(11)> [asciivalue]
// 1: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x150) TAG-TYPE=[BYTE] UNIT-COUNT=(1)> [[17]]
// 2: IfdTagEntry<TAG-IFD=[] TAG-ID=(0xff) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> [[8755]]
// 3: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x100) TAG-TYPE=[LONG] UNIT-COUNT=(1)> [[1146447479]]
// 4: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x13e) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> [[{286335522 858997828}]]
// 5: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x9201) TAG-TYPE=[SRATIONAL] UNIT-COUNT=(1)> [[{286335522 858997828}]]
}