rwcarlsen / goexif

Decode embedded EXIF meta data from image files.
BSD 2-Clause "Simplified" License
627 stars 134 forks source link

Decoding GPSLatitude/Longitude tags #1

Closed imarko closed 11 years ago

imarko commented 11 years ago

I am trying to use goexif to grab and decode GPS location exif tags in jpeg images. This doesn't seem to work, I always get 0 rather than the actual values.

I think the problem is in the interaction of the DecodeTag() and Rat2() logic in tiff.go. The GPSLatitude and GPSLongitude tags are made up of 3 rational values. This puts valLen over 4 so DecodeTag sets Val to the raw bytes rather than using PutUvarint. The Rat2 method on the other hand tries to interpret Val as a varint and because the high byte of the GPS coordinates tends to be 0 binary.Uvarint stops processing when it encounters this initial 0 and returns 0.

rwcarlsen commented 11 years ago

Would you mind sending a sample file that isn't working right (or maybe a string of bytes representing the IFD) and what you expect the output to be? Indeed - you are correct - the Varint and Uvarint functions do not work like I thought they did.

rwcarlsen commented 11 years ago

Actually Uvarint and Varint stop processing if any byte is less than 0x80. I'm not sure why they were written this way - strange.

imarko commented 11 years ago

The varint thing confused me too for a while. It appears to be some kind of a 7 bit encoding so it's not right for reading raw 32 bit values. It just happens to work for big endian if all octets are less than 0x80.

Sample image:

http://kismala.com/exif-little-endian.jpg

Test program below.

Expected output:

0 0 0 37 0 0 0 1 0 0 0 22 0 0 0 1 0 0 9 224 0 0 0 100
37/1 22/1 2528/100

Actual output:

0 0 0 37 0 0 0 1 0 0 0 22 0 0 0 1 0 0 9 224 0 0 0 100
0/0 0/0 0/0
package main

import (
    "fmt"
    "github.com/rwcarlsen/goexif/exif"
    "log"
    "os"
)

func decodefile(fname string) {
    f, err := os.Open(fname)
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    x, err := exif.Decode(f)
    if err != nil {
        fmt.Printf("%s: failed to decode \n", fname)
        return
    }
    lat := x.Get("GPSLatitude")
    for _, b := range lat.Val {
        fmt.Printf("%d ", b)

    }
    fmt.Println()
    latdeg_numer, latdeg_denom := lat.Rat2(0)
    latmin_numer, latmin_denom := lat.Rat2(1)
    latsec_numer, latsec_denom := lat.Rat2(2)
    fmt.Printf("%d/%d %d/%d %d/%d\n",
        latdeg_numer, latdeg_denom,
        latmin_numer, latmin_denom,
        latsec_numer, latsec_denom)
}

func main() {
    for _, f := range os.Args[1:] {
        decodefile(f)
    }

}