mirror of https://github.com/dsoprea/go-exif.git
ifd: Formalized visitor implementation.
parent
05fe72f929
commit
315ca60f03
21
exif.go
21
exif.go
|
@ -1,7 +1,6 @@
|
|||
package exif
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"bytes"
|
||||
|
||||
|
@ -31,7 +30,7 @@ func (e *Exif) IsExif(data []byte) (ok bool) {
|
|||
return false
|
||||
}
|
||||
|
||||
func (e *Exif) Parse(data []byte) (err error) {
|
||||
func (e *Exif) Parse(data []byte, visitor TagVisitor) (err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -39,10 +38,6 @@ func (e *Exif) Parse(data []byte) (err error) {
|
|||
}()
|
||||
|
||||
if e.IsExif(data) == false {
|
||||
|
||||
// TODO(dustin): !! Debugging.
|
||||
fmt.Printf("AppData doesn't look like EXIF. BYTES=(%d)\n", len(data))
|
||||
|
||||
return ErrNotExif
|
||||
}
|
||||
|
||||
|
@ -51,7 +46,6 @@ func (e *Exif) Parse(data []byte) (err error) {
|
|||
// CIPA DC-008-2016; JEITA CP-3451D
|
||||
// -> http://www.cipa.jp/std/documents/e/DC-008-Translation-2016-E.pdf
|
||||
|
||||
fmt.Printf("AppData DOES look like EXIF. BYTES=(%d)\n", len(data))
|
||||
byteOrderSignature := data[6:8]
|
||||
byteOrder := IfdByteOrder(BigEndianByteOrder)
|
||||
if string(byteOrderSignature) == "II" {
|
||||
|
@ -60,15 +54,9 @@ fmt.Printf("AppData DOES look like EXIF. BYTES=(%d)\n", len(data))
|
|||
log.Panicf("byte-order not recognized: [%v]", byteOrderSignature)
|
||||
}
|
||||
|
||||
fmt.Printf("BYTE-ORDER: [%s]\n", byteOrderSignature)
|
||||
|
||||
fixedBytes := data[8:10]
|
||||
if fixedBytes[0] != 0x2a || fixedBytes[1] != 0x00 {
|
||||
exifLogger.Warningf(nil, "EXIF app-data header fixed-bytes should be 0x002a but are: [%v]", fixedBytes)
|
||||
|
||||
// TODO(dustin): Debugging.
|
||||
fmt.Printf("EXIF app-data header fixed-bytes should be 0x002a but are: [%v]\n", fixedBytes)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -81,13 +69,6 @@ fmt.Printf("AppData DOES look like EXIF. BYTES=(%d)\n", len(data))
|
|||
|
||||
ifd := NewIfd(data, byteOrder)
|
||||
|
||||
visitor := func() error {
|
||||
// TODO(dustin): !! Debugging.
|
||||
|
||||
fmt.Printf("IFD visitor.\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
err = ifd.Scan(visitor, firstIfdOffset)
|
||||
log.PanicIf(err)
|
||||
|
||||
|
|
28
exif_test.go
28
exif_test.go
|
@ -4,6 +4,7 @@ import (
|
|||
"testing"
|
||||
"os"
|
||||
"path"
|
||||
"fmt"
|
||||
|
||||
"io/ioutil"
|
||||
|
||||
|
@ -62,7 +63,32 @@ func TestParse(t *testing.T) {
|
|||
|
||||
// Run the parse.
|
||||
|
||||
err = e.Parse(data[foundAt:])
|
||||
ti := NewTagIndex()
|
||||
|
||||
visitor := func(tagId, tagType uint16, tagCount, valueOffset uint32) (err error) {
|
||||
it, err := ti.GetWithTagId(tagId)
|
||||
if err != nil {
|
||||
if err == ErrTagNotFound {
|
||||
return nil
|
||||
} else {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Tag: ID=(0x%04x) NAME=[%s] IFD=[%s] TYPE=(%d) COUNT=(%d) VALUE-OFFSET=(%d)\n", tagId, it.Name, it.Ifd, tagType, tagCount, valueOffset)
|
||||
|
||||
// Notes on the tag-value's value (we'll have to use this as a pointer if the type potentially requires more than four bytes):
|
||||
//
|
||||
// This tag records the offset from the start of the TIFF header to the position where the value itself is
|
||||
// recorded. In cases where the value fits in 4 Bytes, the value itself is recorded. If the value is smaller
|
||||
// than 4 Bytes, the value is stored in the 4-Byte area starting from the left, i.e., from the lower end of
|
||||
// the byte offset area. For example, in big endian format, if the type is SHORT and the value is 1, it is
|
||||
// recorded as 00010000.H
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
err = e.Parse(data[foundAt:], visitor)
|
||||
log.PanicIf(err)
|
||||
}
|
||||
|
||||
|
|
60
ifd.go
60
ifd.go
|
@ -1,7 +1,6 @@
|
|||
package exif
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
|
@ -102,9 +101,12 @@ func (ifd *Ifd) getUint32() (value uint32, err error) {
|
|||
return value, nil
|
||||
}
|
||||
|
||||
|
||||
type TagVisitor func(tagId, tagType uint16, tagCount, valueOffset uint32) (err error)
|
||||
|
||||
// parseCurrentIfd decodes the IFD block that we're currently sitting on the
|
||||
// first byte of.
|
||||
func (ifd *Ifd) parseCurrentIfd() (nextIfdOffset uint32, err error) {
|
||||
func (ifd *Ifd) parseCurrentIfd(visitor TagVisitor) (nextIfdOffset uint32, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -115,62 +117,34 @@ func (ifd *Ifd) parseCurrentIfd() (nextIfdOffset uint32, err error) {
|
|||
tagCount, err := ifd.getUint16()
|
||||
log.PanicIf(err)
|
||||
|
||||
fmt.Printf("IFD: TOTAL TAG COUNT=(%02x)\n", tagCount)
|
||||
|
||||
t := NewTagIndex()
|
||||
ifdLogger.Debugf(nil, "Current IFD tag-count: (%d)", tagCount)
|
||||
|
||||
for i := uint16(0); i < tagCount; i++ {
|
||||
// TODO(dustin): !! 0x8769 tag-IDs are child IFDs.
|
||||
|
||||
// TODO(dustin): !! 0x8769 tag-IDs are child IFDs. We need to be able to recurse.
|
||||
|
||||
tagId, err := ifd.getUint16()
|
||||
log.PanicIf(err)
|
||||
|
||||
it, err := t.GetWithTagId(tagId)
|
||||
if err != nil {
|
||||
if err == ErrTagNotFound {
|
||||
log.Panicf("tag (%04x) not known")
|
||||
} else {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("IFD: Tag (%d) ID=(%02x) NAME=[%s] IFD=[%s]\n", i, tagId, it.Name, it.Ifd)
|
||||
|
||||
|
||||
tagType, err := ifd.getUint16()
|
||||
log.PanicIf(err)
|
||||
|
||||
fmt.Printf("IFD: Tag (%d) TYPE=(%d)\n", i, tagType)
|
||||
|
||||
|
||||
tagCount, err := ifd.getUint32()
|
||||
log.PanicIf(err)
|
||||
|
||||
fmt.Printf("IFD: Tag (%d) COUNT=(%02x)\n", i, tagCount)
|
||||
|
||||
|
||||
valueOffset, err := ifd.getUint32()
|
||||
log.PanicIf(err)
|
||||
|
||||
fmt.Printf("IFD: Tag (%d) VALUE-OFFSET=(%x)\n", i, valueOffset)
|
||||
|
||||
// Notes on the tag-value's value (we'll have to use this as a pointer if the type potentially requires more than four bytes):
|
||||
//
|
||||
// This tag records the offset from the start of the TIFF header to the position where the value itself is
|
||||
// recorded. In cases where the value fits in 4 Bytes, the value itself is recorded. If the value is smaller
|
||||
// than 4 Bytes, the value is stored in the 4-Byte area starting from the left, i.e., from the lower end of
|
||||
// the byte offset area. For example, in big endian format, if the type is SHORT and the value is 1, it is
|
||||
// recorded as 00010000.H
|
||||
|
||||
if visitor != nil {
|
||||
err := visitor(tagId, tagType, tagCount, valueOffset)
|
||||
log.PanicIf(err)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("\n")
|
||||
|
||||
nextIfdOffset, err = ifd.getUint32()
|
||||
log.PanicIf(err)
|
||||
|
||||
fmt.Printf("IFD: NEXT-IFD-OFFSET=(%x)\n", nextIfdOffset)
|
||||
|
||||
fmt.Printf("\n")
|
||||
ifdLogger.Debugf(nil, "Next IFD at offset: (%08x)", nextIfdOffset)
|
||||
|
||||
return nextIfdOffset, nil
|
||||
}
|
||||
|
@ -184,7 +158,7 @@ func (ifd *Ifd) forwardToIfd(ifdOffset uint32) (err error) {
|
|||
}
|
||||
}()
|
||||
|
||||
fmt.Printf("IFD: Forwarding to IFD. TOP-OFFSET=(%d) IFD-OFFSET=(%d)\n", ifd.ifdTopOffset, ifdOffset)
|
||||
ifdLogger.Debugf(nil, "Forwarding to IFD. TOP-OFFSET=(%d) IFD-OFFSET=(%d)", ifd.ifdTopOffset, ifdOffset)
|
||||
|
||||
nextOffset := ifd.ifdTopOffset + ifdOffset
|
||||
|
||||
|
@ -198,10 +172,8 @@ func (ifd *Ifd) forwardToIfd(ifdOffset uint32) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
type IfdVisitor func() error
|
||||
|
||||
// Scan enumerates the different EXIF blocks (called IFDs).
|
||||
func (ifd *Ifd) Scan(v IfdVisitor, firstIfdOffset uint32) (err error) {
|
||||
func (ifd *Ifd) Scan(visitor TagVisitor, firstIfdOffset uint32) (err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -212,7 +184,7 @@ func (ifd *Ifd) Scan(v IfdVisitor, firstIfdOffset uint32) (err error) {
|
|||
log.PanicIf(err)
|
||||
|
||||
for {
|
||||
nextIfdOffset, err := ifd.parseCurrentIfd()
|
||||
nextIfdOffset, err := ifd.parseCurrentIfd(visitor)
|
||||
log.PanicIf(err)
|
||||
|
||||
if nextIfdOffset == 0 {
|
||||
|
|
Loading…
Reference in New Issue