diff --git a/ifd_builder_encode.go b/ifd_builder_encode.go index cd098df..9825af0 100644 --- a/ifd_builder_encode.go +++ b/ifd_builder_encode.go @@ -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) diff --git a/ifd_builder_encode_test.go b/ifd_builder_encode_test.go index 433ed5e..00ecff0 100644 --- a/ifd_builder_encode_test.go +++ b/ifd_builder_encode_test.go @@ -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 [asciivalue] -// // 1: IfdTagEntry [[17]] -// // 2: IfdTagEntry [[8755]] -// // 3: IfdTagEntry [[1146447479]] -// // 4: IfdTagEntry [[{286335522 858997828}]] -// // 5: IfdTagEntry [[{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 asciivalue -// // 1: IfdTagEntry [17] -// // 2: IfdTagEntry [8755] -// // 3: IfdTagEntry [1146447479] -// // 4: IfdTagEntry [{286335522 858997828}] -// // 5: IfdTagEntry [{286335522 858997828}] -// } - -// TODO(dustin): !! Write test with both chained and child IFDs + // Output: + // + // 0: IfdTagEntry [asciivalue] + // 1: IfdTagEntry [[17]] + // 2: IfdTagEntry [[8755]] + // 3: IfdTagEntry [[1146447479]] + // 4: IfdTagEntry [[{286335522 858997828}]] + // 5: IfdTagEntry [[{286335522 858997828}]] +}