## Geotag – EXIF GPS Latitude field format with libEXIF

I have been developing some software to geotag jpeg images by adding EXIF GPS information using libEXIF. This is very handy as loads of applications like GIS systems and google maps etc can correctly geographically position your images.

As usual I started in the middle rather than starting at the beginning and got a bit confused by how GPS latitude and longitude fields are specified in EXIF, so I decided to try to describe it here with pictures (so that I can test out the google drawing app).

So, latitude (and longitude) can be expressed in different ways bit it is essentially just an angle. Common ways of expressing these angles are:

Degrees, minutes & seconds (with decimal places)
N 52 58 40.44

Degrees & minutes (with decimal places)
N 52 58.674

Degrees (with decimal places)
52.97790

The EXIF latitude field allows you to specify the angle in all of these forms, it is made up of 3 parts as follows:

1.) Degrees – Rational (8 bytes)
2.) Minutes – Rational (8 bytes)
3.) Seconds – Rational (8 bytes)

Each part is an EXIF Rational, it is hard to find a description of its format, but a an EXIF rational contains two 4-byte words and is like a fraction. The first word specifies the value’s magnitude while the second denominates the units. Consider the following values, (where ‘/’ should be read as ‘over’ or ‘divided by’):

a.) 52 = 52 / 1 (52 units)
b.) 40.44 = 4044 / 100 (4044 hundredths)
c.) 52.97790 = 52977900 / 1000000 (52977900 millionths)
d.) 0 = 0/1

the last value ( 0/1 ) is handy as it allows us to specify, say, 0 seconds if we only want to provide degrees and fractional minutes.

To set a rational we can use libEXIF’s set_rational() function like this:

```//
// 40.44 = 4044 / 100 (4044 hundredths)
exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL, { 4044, 100 });
//
```

or more generally, if, for example, you want to set a value to 6 decimal places:

```//
float lat = 52.977900;
exif_set_rational(entry->data, FILE_BYTE_ORDER, { (unsigned)(lat * 1000000.0), 1000000 });
//
```

So now, given a latitude value in degrees, minutes and seconds all we have to do is create a EXIF_TAG_GPS_LATITUDE tag and add a rational for each. Imagine that we want to encode 52, 58, 44.44 then the tag data will then end up looking like this:

This is all very well but I don’t normally bother holding minutes and seconds in my code, instead I preferr to use a degree value to many decimal places, e.g. 52.97790, no problem, this is where our rational value 0 / 1 comes in handy – it can be represented as follows:

So wrapping all of this up, here is some example code that sets a decimal degree value for latitude:

```/*
* create_tag() is from the write-exif.c sample code that is floating
* around the interweb - with thanks to whoever created it!
*/
/* Create a brand-new tag with a data field of the given length, in the
* given IFD. This is needed when exif_entry_initialize() isn't able to create
* this type of tag itself, or the default data length it creates isn't the
* correct length.
*/
static ExifEntry *create_tag(ExifData *exif, ExifIfd ifd, ExifTag tag, size_t len)
{
void *buf;
ExifEntry *entry;
/* Create a memory allocator to manage this ExifEntry */
ExifMem *mem = exif_mem_new_default();
/* Create a new ExifEntry using our allocator */
entry = exif_entry_new_mem (mem);
/* Allocate memory to use for holding the tag data */
buf = exif_mem_alloc(mem, len);
/* Fill in the entry */
entry->data = buf;
entry->size = len;
entry->tag = tag;
entry->components = len;
entry->format = EXIF_FORMAT_UNDEFINED;
/* Attach the ExifEntry to an IFD */
/* The ExifMem and ExifEntry are now owned elsewhere */
exif_mem_unref(mem);
exif_entry_unref(entry);
return entry;
}
// Set a decimal degree value with support for 6 decimal places
//
//
// create our latitude tag, the whole  field is 24 bytes long
entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE, 24);
// Set the field's format and number of components, this is very important!
entry->format = EXIF_FORMAT_RATIONAL;
entry->components = 3;
// Degrees
float lat = 52.977900;
exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL, { (unsigned)(lat * 1000000.0), 1000000 });
//
//

```

I will probably do another post that details how to write EXIF data into a jpeg image’s header using libEXIF and libJPEG

The google drawing app actually worked quite well!

## Compiling / Building libJpeg for Windows

Here is a record of how I managed to build libJpeg for Windows, Visual Studio 2012:

2.) Launch the Visual Studio Command console. To launch it, search for ‘command’ in the start menu, and you should see something like ‘Developer Command Prompt for VS2012’, start this.

3.) in the command prompt cd to the directory in which the libJpeg source resides

4.) At the command prompt, run the following commands:

```
set INCLUDE=%INCLUDE%;c:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include
copy jconfig.vc jconfig.h
copy makelib.ds jpeg.mak
copy makeapps.ds apps.mak
nmake /f makefile.vc  nodebug=1 libjpeg.lib

```

In the first command make sure to replace the path with your path to your installation of the windows SDK, you may have to look around for this… If you get an error like this:

```.
.
```

Then you haven’t correctly specified the SDK path.

When the compile finishes you should see libjpeg.lib in the top folder.

.

## Cross compiling libjpeg-turbo targeting ARM for software jpeg compression

In a quest to get faster software jpeg compression on ARM I cross compiled libjpeg-turbo 1.3.0 and pitted it against standard libjpeg (libjpeg-turbo can be used as a drop in replacement for libjpeg). For 24bit rbg images of size 4096×2000, libjpeg-turbo was about twice as fast as libjpeg. Here’s how I compiled libjpeg-turbo:

First get the source:

```wget http://downloads.sourceforge.net/libjpeg-turbo/libjpeg-turbo-1.3.0.tar.gz
```

Then un-tar it and cd into the main source directory. Then configure for ARM:

``` ./configure --host=arm-linux-gnueabi CC=arm-linux-gnueabi-gcc AR=arm-linux-gnueabi-ar \
STRIP=arm-linux-gnueabi-strip RANLIB=arm-linux-gnueabi-ranlib \
--prefix=
```

And make:

```make
make install
```

The output files will be put under the directory that you specified when you configured, copy them onto your ARM device as appropriate.

## Cross compiling libjpeg for Linux on ARM

I am taking this opportunity to document a cross compilation procedure for libjpeg targeting ARM Linux mostly so that I won’t have to go searching for it again in the future!

First create a directory and cd to it:

```mkdir libjpeg_build
cd libjpeg_build```

Now get the source and un-tar it:

```wget http://www.ijg.org/files/jpegsrc.v9.tar.gz
tar -xzvf jpegsrc.v9.tar.gz```

Configure the build, specifying your C compiler and cross compilation host, then make:

```./configure --host=arm-xilinx-linux CC=arm-xilinx-linux-gnueabi-gcc
make```

Here, I am using the xilinx build of the compiler, hence the reference to xilinx in the host and CC parameters, if I wasn’t using the xilinx tools the above configure command may have looked more like this:

`./configure --host=arm-linux CC=arm-linux-gnueabi-gcc`

Now make install, specifying a directory for the output:

`make install DESTDIR=./_install`

If all goes well the output of the build process should be written to the _install directory, copy the .so files to the appropriate directory on your target device (e.g. /usr/local/lib)