diff --git a/exif.go b/exif.go index 14d4187..2fd95ee 100644 --- a/exif.go +++ b/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) diff --git a/exif_test.go b/exif_test.go index bdaafdc..acb5363 100644 --- a/exif_test.go +++ b/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) } diff --git a/ifd.go b/ifd.go index fe2a3cb..9eba654 100644 --- a/ifd.go +++ b/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 {