It is difficult to find relevant information on the Internet. I have implemented one by myself, but some of the offsets are inconsistent with those in the standard. The individual offset is obtained based on the photos taken by my SamSung mobile phone. Currently, the results obtained by testing the photos taken by my mobile phone are correct. Now I am posting the code here. I hope you can raise the errors and improve them together.
How to obtain GPS information from JPG files
Extract the IFD (image file Directory) information corresponding to GPS in the Exif (Exchangeable Image File format) data structure, that is, GPS_TAG.
The key is to clarify the structure of JPEG files.
// Get GPS Info From JPG File <br/> // Johnny.cxx@gmail.com <br/> // 2012.4.30 </p> <p> # include <Windows. h> <br/> # include <iostream> <br/> # include <string> </p> <p> using namespace std; </p> <p> // const values <br/> const unsigned char SOF [2] = {0xff, 0xd8 }; <br/> const unsigned char APP1 [2] = {0xff, 0xe1}; <br/> const unsigned char pai_header_length = 6; <br/> const unsigned char TIF_Header [pai_header_length] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; <br/> const unsigned char BUFFERSIZE = 255; <br/> const unsigned char BIG_ENDIAN = 0x4d; <br/> const unsigned char SMALL_ENDIAN = 0x49; <br/> const unsigned char AfterTIFF [2] = {0x2a, 0x00 }; <br/> const unsigned char IFD_DISTANCE_LENGTH = 4; <br/> const unsigned char COMPONENT_NUM_LENGTH = 4; <br/> const unsigned char DATA_LENGTH = 4; <br/> const unsigned char DISTAN CE_TO_NEXT_IFD = 4; <br/> const unsigned int GPS_TAG = 0x8825; </p> <p> // global variable <br/> bool IsSmallEndian = false; <br/> int GPSVersion [4]; <br/> char GPSLatitudeRef, GPSLongitudeRef; <br/> int GPSLatitude [3]; <br/> int gpslongdistance [3]; <br/> bool HasGPSInfo = false; <br/> string failInfo; </p> <p> int main (int argc, char * argv []) <br/>{< br/> if (argc <= 1) <br/>{< br/> cout <"[No file input!] "<Endl; <br/> system (" pause "); <br/> return 0; <br/>}</p> <p> unsigned char buf [BUFFERSIZE]; <br/> DWORD dwFileRead = 0; <br/> // HANDLE hTIFF = 0; </p> <p> // Open jpg file <br/> //////////////////////// //////////////////////////////////////// ////////////// <br/> HANDLE hFile = CreateFile (argv [1], // maid <br/> GENERIC_WRITE | GENERIC_READ, // DWORD dwAccess <br/> file_assist_write | file_assist_re AD, // DWORD dwShareMode <br/> NULL, // LPSECURITY_ATTRIBUTES lpSecurityAttributes <br/> OPEN_ALWAYS, // DWORD dwCreate <br/> FILE_ATTRIBUTE_NORMAL, // DWORD dwFlagsAndAttributes <br/> NULL // HANDLE hTemplateFile <br/>); <br/> try <br/> {<br/> if (hFile = 0) <br/>{< br/> failInfo = "fail to open file! "; <Br/> throw (failInfo ); <br/>}</p> <p> // check SOF <br/> //////////////////// //////////////////////////////////////// ////// // <br/> // read the first 2 bytes of jpg <br/> ReadFile (hFile, buf, 1, & dwFileRead, NULL); <br/> ReadFile (hFile, buf + 1, 1, & dwFileRead, NULL ); </p> <p> // check whether this file is of jpg format <br/> // if buf suit SOF, it is jpg <br/> if (buf [0]! = SOF [0] | buf [1]! = SOF [1]) <br/>{< br/> failInfo = "Current file is not of Jpg format! "; <Br/> throw (failInfo ); <br/>}</p> <p> // chech APP1 symbol <br/> /////////////////// //////////////////////////////////////// //////// // <br/> // read the next 2 bytes of jpg <br/> ReadFile (hFile, buf, 1, & dwFileRead, NULL); <br/> ReadFile (hFile, buf + 1, 1, & dwFileRead, NULL ); </p> <p> // check whether APP1 symbol <br/> // if buf suit APP1, it is APP1 symbol <br/> if (buf [0]! = APP1 [0] | buf [1]! = APP1 [1]) <br/>{< br/> failInfo = "Fail to suit APP1 symbol"; <br/> throw (failInfo ); <br/>}</p> <p> // get the capacity of APP1 field <br/> //////////////// //////////////////////////////////////// /// // <br/> unsigned int APP1_Capacity = 0; <br/> // read the next 2 bytes of jpg <br/> ReadFile (hFile, buf, 1, & dwFileRead, NULL); <br/> ReadFile (hFile, buf + 1, 1, & dwFileRead, NULL); <br/> memcpy (& Appenders capacity, buf, 2 ); </p> <p> // check TIFF header <br/> //////////////////////// //////////////////////////////////////// ////// // <br/> // read the next packet _header_length bytes of jpg <br/> for (int I = 0; I <cmd_header_length; I ++) <br/> ReadFile (hFile, buf + I, 1, & dwFileRead, NULL ); <br/> // check TIFF header <br/> bool IsTIFFHeader = true; <br/> for (int I = 0; I <pai_header_length; I ++) <br />{< Br/> if (buf [I] = TIF_Header [I]) <br/>; <br/> else <br/> IsTIFFHeader = false; <br/>}< br/> if (IsTIFFHeader = false) <br/>{< br/> failInfo = "Bad TIFF header "; <br/> throw (failInfo ); <br/>}</p> <p> // check for Big_Endian or Small_Endian <br/> // Intel-> SmallEndian <br/>/Motorola-> BigEndian <br/> // hex: 0x12345678 <br/> // Motorola-> 0x12, 0x34,0x56, 0x78 <br/> // Intel-> 0x78,0x56, 0x34,0x12 <br/> // Almost All camera are using Intel Small Endian <br/> ///////////////////////////// //////////////////////////////////////// ///////// <br/> // read the next 2 bytes of jpg <br/> ReadFile (hFile, buf, 1, & dwFileRead, NULL); <br/> ReadFile (hFile, buf + 1, 1, & dwFileRead, NULL ); <br/> if (buf [0]! = Buf [1]) <br/>{< br/> failInfo = "Bad Endian"; <br/> throw (failInfo ); <br/>}< br/> else <br/> {<br/> if (buf [0] = BIG_ENDIAN) <br/> IsSmallEndian = false; <br/> else <br/> if (buf [0] = SMALL_ENDIAN) <br/> IsSmallEndian = true; <br/> else <br/>{< br/> failInfo = "Bad Endian"; <br/> throw (failInfo ); <br/>}</p> <p> // if it is Small Endian format <br/> if (IsSmallEndian = true) <br/> {<br/> // chech 2 bytes after TIF F <br/> /////////////////////////////////// //////////////////////////////////////// ///// <br/> // read the next 2 bytes of jpg <br/> ReadFile (hFile, buf, 1, & dwFileRead, NULL); <br/> ReadFile (hFile, buf + 1, 1, & dwFileRead, NULL ); </p> <p> // check whether AfterTIFF symbol <br/> // if buf suit AfterTIFF, it is AfterTIFF symbol <br/> if (buf [0]! = AfterTIFF [0] | buf [1]! = AfterTIFF [1]) <br/>{< br/> failInfo = "Fail to suit AfterTIFF symbol"; <br/> throw (failInfo ); <br/>}</p> <p> // get diatance to IFD (Image File Directory) <br/> //////////////////////////////////// //////////////////////////////////////// //// <br/> // read the next IFD_DISTANCE_LENGTH bytes of jpg <br/> unsigned int distance2IFD = 0; <br/> for (int I = 0; I <IFD_DISTANCE_LENGTH; I ++) <br/> ReadFile (hFile, buf + I, 1, & dwFileRead, NULL); <br/> memcpy (& distance2IFD, buf, 2 ); </p> <p> // get IFD count <br/> //////////////////////// //////////////////////////////////////// ///////////// <br/> // read the next 2 bytes of jpg <br/> unsigned int IFDCount = 0; <br/> for (int I = 0; I <2; I ++) <br/> ReadFile (hFile, buf + I, 1, & dwFileRead, NULL ); <br/> memcpy (& IFDCount, buf, 2 ); </p> <p> // iterate every tag <br/> /////////// //////////////////////////////////////// /// // <Br/> unsigned int TagID = 0, dataFormat = 0, ComponentNum = 0; <br/> unsigned long Value = 0; <br/> for (unsigned int I = 0; I <IFDCount; I ++) <br/> {<br/> // get Tag Id <br/> ////////////////////// //////////////////////////////////////// //// // <br/> // read the next 2 bytes of jpg <br/> for (int I = 0; I <2; I ++) <br/> ReadF Ile (hFile, buf + I, 1, & dwFileRead, NULL); <br/> memcpy (& TagID, buf, 2 ); </p> <p> // get data format <br/> //////////////////////// //////////////////////////////////////// ////// // <br/> // read the next 2 bytes of jpg <br/> for (int I = 0; I <2; I ++) <br/> ReadFile (hFile, buf + I, 1, & dwFileRead, NULL); <br/> memcpy (& DataFormat, buf, 2 ); </p> <p> // get ComponentNum <br/> ///////////////////////// //////// //////////////////////////////////////// ////// <Br/> // read the next 2 bytes of jpg <br/> for (int I = 0; I <COMPONENT_NUM_LENGTH; I ++) <br/> ReadFile (hFile, buf + I, 1, & dwFileRead, NULL); <br/> memcpy (& ComponentNum, buf, COMPONENT_NUM_LENGTH ); </p> <p> // get Value <br/> ///////////////////////// //////////////////////////////////////// /// // <br/> // read the next 2 bytes of jpg <br/> for (int I = 0; I <DATA_LENGTH; I ++) <br/> ReadFile (hFile, buf + I, 1, & dwFileRead, NULL); <br/> memcpy (& Value, buf, DATA_LENGTH); </p> <p> // Is GPS Info <br/> if (TagID = GPS_TAG) <br/>{< br/> HANDLE tFile = hFile; </p> <p> // SetFilePointer (tFile, Value + 34, NULL, FILE_BEGIN ); <br/> SetFilePointer (tFile, Value + 0x1a /*? Guess? */, NULL, FILE_BEGIN); </p> <p> // Get GPS Version <br/> for (int I = 0; I <4; I ++) <br/>{< br/> ReadFile (tFile, buf, 1, & dwFileRead, NULL); <br/> ReadFile (tFile, buf + 1, 1, & dwFileRead, NULL); <br/> memcpy (GPSVersion + I, buf, 2 ); <br/>}</p> <p> // Read GPSLatitudeRef <br/> ReadFile (tFile, buf, 1, & dwFileRead, NULL ); <br/> memcpy (& GPSLatitudeRef, buf, 1); </p> <p> // Move file pointer to GPSLongitudeRef <br/> SetFilePointer (tFile, 0x17, NULL, FILE_CURRENT); <br/> ReadFile (tFile, buf, 1, & dwFileRead, NULL); <br/> memcpy (& GPSLongitudeRef, buf, 1 ); </p> <p> // Move file pointer to GPS Info <br/> SetFilePointer (tFile, 0x4f, NULL, FILE_CURRENT ); </p> <p> // Get GPS Latitude Info <br/> int LatiTemp [6]; <br/> for (int I = 0; I <6; I ++) <br/>{< br/> ReadFile (tFile, buf, 1, & dwFileRead, NULL); <br/> ReadFile (tFile, buf + 1, 1, & dwFileRead, NULL); <br/> ReadFile (tFile, buf + 2, 1, & dwFileRead, NULL); <br/> ReadFile (tFile, buf + 3, 1, & dwFileRead, NULL); <br/> memcpy (LatiTemp + I, buf, 4 ); <br/>}</p> <p> for (int I = 0; I <3; I ++) <br/> GPSLatitude [I] = LatiTemp [2 * I]/(double) LatiTemp [2 * I + 1]; </p> <p> if (GPSLatitude [0] & GPSLatitude [1] & GPSLatitude [2]) <br/> HasGPSInfo = true; </p> <p> // Get GPS longpolling Info <br/> int LongiTemp [6]; <br/> for (int I = 0; I <6; I ++) <br/>{< br/> ReadFile (tFile, buf, 1, & dwFileRead, NULL); <br/> ReadFile (tFile, buf + 1, 1, & dwFileRead, NULL); <br/> ReadFile (tFile, buf + 2, 1, & dwFileRead, NULL); <br/> ReadFile (tFile, buf + 3, 1, & dwFileRead, NULL); <br/> memcpy (LongiTemp + I, buf, 4 ); <br/>}</p> <p> for (int I = 0; I <3; I ++) <br/> gpslongpolling [I] = LongiTemp [2 * I]/(double) LatiTemp [2 * I + 1]; </p> <p >}< br/> else <br/>{</p> <p> failInfo = "Fail to suit AfterTIFF symbol "; <br/> throw (failInfo); <br/>}</p> <p >}< br/> catch (string e) <br/>{< br/> cout <e <endl; <br/>}< br/> // close handle <br/> /////////////////////// //////////////////////////////////////// /////////////// <br/> CloseHandle (hFile ); </p> <p> if (HasGPSInfo = true) <br/> {<br/> cout <GPSLatitudeRef <"" <GPSLatitude [0] <"[degree]" <GPSLatitude [1] <"[ minute] "<br/> <GPSLatitude [2] <" [second] "<endl; <br/> cout <GPSLongitudeRef <"" <gpslong.pdf [0] <"[degree]" <gpslong.pdf [1] <"[minute]" <br /> <gpslongpolling [2] <"[second]" <endl; <br/>}< br/> else <br/> cout <"No GPS Info" <endl; <br/> cout. flush (); <br/> system ("pause"); </p> <p> return 0; <br/>}< br/>