从jpg文件中读取出GPS信息

        在网上很难找相关的资料,我自己实现了一种,但是其中的一些偏移量与标准中的不一致。个别偏移量是根据我自己的三星手机拍的照片得到的。目前测试我自己的手机拍的照片得到的结果是正确的,现在把代码贴在这里,希望大家能够提出其中的错误,共同提高。


从JPG文件中获取GPS信息的方法
提取Exif(Exchangeable image file format)数据结构中与GPS对应的IFD(Image File Directory)信息,即GPS_TAG。
关键是要明确JPEG文件的文件结构。


//Get GPS Info From JPG File //Johnny.cxx@gmail.com //2012.4.30 #include <Windows.h> #include <iostream> #include <string> using namespace std; //const values const unsigned char SOF[2] = {0xff, 0xd8}; const unsigned char APP1[2] = {0xff, 0xe1}; const unsigned char TIFF_Header_Length = 6; const unsigned char TIF_Header[TIFF_Header_Length] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; const unsigned char BUFFERSIZE = 255; const unsigned char BIG_ENDIAN = 0x4d; const unsigned char SMALL_ENDIAN = 0x49; const unsigned char AfterTIFF[2] = {0x2a, 0x00}; const unsigned char IFD_DISTANCE_LENGTH = 4; const unsigned char COMPONENT_NUM_LENGTH = 4; const unsigned char DATA_LENGTH = 4; const unsigned char DISTANCE_TO_NEXT_IFD = 4; const unsigned int GPS_TAG = 0x8825; //global variable bool IsSmallEndian = false; int GPSVersion[4]; char GPSLatitudeRef, GPSLongitudeRef; int GPSLatitude[3]; int GPSLongitude[3]; bool HasGPSInfo = false; string failInfo; int main(int argc, char *argv[]) { if(argc <= 1) { cout << "[No file input!]" << endl; system("pause"); return 0; } unsigned char buf[BUFFERSIZE]; DWORD dwFileRead = 0; //HANDLE hTIFF = 0; //Open jpg file HANDLE hFile = CreateFile(argv[1], //LPCTSTR lpcszFileName GENERIC_WRITE|GENERIC_READ, //DWORD dwAccess FILE_SHARE_WRITE|FILE_SHARE_READ, //DWORD dwShareMode NULL, //LPSECURITY_ATTRIBUTES lpSecurityAttributes OPEN_ALWAYS, //DWORD dwCreate FILE_ATTRIBUTE_NORMAL, //DWORD dwFlagsAndAttributes NULL //HANDLE hTemplateFile ); try { if(hFile == 0) { failInfo = "fail to open file!"; throw(failInfo); } //check SOF //read the first 2 bytes of jpg ReadFile(hFile, buf, 1, &dwFileRead, NULL); ReadFile(hFile, buf +1, 1, &dwFileRead, NULL); //check whether this file is of jpg format //if buf suit SOF, it is jpg if (buf[0] != SOF[0] || buf[1] != SOF[1]) { failInfo = "Current file is not of Jpg format!"; throw(failInfo); } //chech APP1 symbol //read the next 2 bytes of jpg ReadFile(hFile, buf, 1, &dwFileRead, NULL); ReadFile(hFile, buf +1, 1, &dwFileRead, NULL); //check whether APP1 symbol //if buf suit APP1, it is APP1 symbol if (buf[0] != APP1[0] || buf[1] != APP1[1]) { failInfo = "Fail to suit APP1 symbol"; throw(failInfo); } //get the capacity of APP1 field unsigned int APP1_Capacity = 0; //read the next 2 bytes of jpg ReadFile(hFile, buf, 1, &dwFileRead, NULL); ReadFile(hFile, buf +1, 1, &dwFileRead, NULL); memcpy(&APP1_Capacity, buf, 2); //check TIFF header //read the next TIFF_Header_Length bytes of jpg for(int i = 0; i < TIFF_Header_Length; i++) ReadFile(hFile, buf + i, 1, &dwFileRead, NULL); //check TIFF header bool IsTIFFHeader = true; for(int i = 0; i < TIFF_Header_Length; i++) { if(buf[i] == TIF_Header[i]) ; else IsTIFFHeader = false; } if(IsTIFFHeader == false) { failInfo = "Bad TIFF header"; throw(failInfo); } //check for Big_Endian or Small_Endian //Intel->SmallEndian //Motorola->BigEndian //hex: 0x12345678 //Motorola -> 0x12,0x34,0x56,0x78 //Intel -> 0x78,0x56,0x34,0x12 //Almost all camera are using Intel Small Endian //read the next 2 bytes of jpg ReadFile(hFile, buf, 1, &dwFileRead, NULL); ReadFile(hFile, buf +1, 1, &dwFileRead, NULL); if(buf[0] != buf[1]) { failInfo = "Bad Endian"; throw(failInfo); } else { if(buf[0] == BIG_ENDIAN) IsSmallEndian = false; else if(buf[0] = SMALL_ENDIAN) IsSmallEndian = true; else { failInfo = "Bad Endian"; throw(failInfo); }} //if it is Small Endian format if(IsSmallEndian == true) { //chech 2 bytes after TIFF //read the next 2 bytes of jpg ReadFile(hFile, buf, 1, &dwFileRead, NULL); ReadFile(hFile, buf +1, 1, &dwFileRead, NULL); //check whether AfterTIFF symbol //if buf suit AfterTIFF, it is AfterTIFF symbol if (buf[0] != AfterTIFF[0] || buf[1] != AfterTIFF[1]) { failInfo = "Fail to suit AfterTIFF symbol"; throw(failInfo); } //get diatance to IFD(Image File Directory) //read the next IFD_DISTANCE_LENGTH bytes of jpg unsigned int distance2IFD = 0; for(int i = 0; i < IFD_DISTANCE_LENGTH; i++) ReadFile(hFile, buf + i, 1, &dwFileRead, NULL); memcpy(&distance2IFD, buf, 2); //get IFD count //read the next 2 bytes of jpg unsigned int IFDCount = 0; for(int i = 0; i < 2; i++) ReadFile(hFile, buf + i, 1, &dwFileRead, NULL); memcpy(&IFDCount, buf, 2); //iterate every tag unsigned int TagID = 0, DataFormat = 0, ComponentNum = 0; unsigned long Value = 0; for(unsigned int i = 0; i < IFDCount; i++) { //get Tag Id //read the next 2 bytes of jpg for(int i = 0; i < 2; i++) ReadFile(hFile, buf + i, 1, &dwFileRead, NULL); memcpy(&TagID, buf, 2); //get data format //read the next 2 bytes of jpg for(int i = 0; i < 2; i++) ReadFile(hFile, buf + i, 1, &dwFileRead, NULL); memcpy(&DataFormat, buf, 2); //get ComponentNum //read the next 2 bytes of jpg for(int i = 0; i < COMPONENT_NUM_LENGTH; i++) ReadFile(hFile, buf + i, 1, &dwFileRead, NULL); memcpy(&ComponentNum, buf, COMPONENT_NUM_LENGTH); //get Value //read the next 2 bytes of jpg for(int i = 0; i < DATA_LENGTH; i++) ReadFile(hFile, buf + i, 1, &dwFileRead, NULL); memcpy(&Value, buf, DATA_LENGTH); //Is GPS Info if(TagID == GPS_TAG) { HANDLE tFile = hFile; //SetFilePointer(tFile, Value + 34, NULL, FILE_BEGIN); SetFilePointer(tFile, Value + 0x1a/*?guess?*/, NULL, FILE_BEGIN); //Get GPS Version for(int i = 0; i < 4; i++) { ReadFile(tFile, buf, 1, &dwFileRead, NULL); ReadFile(tFile, buf + 1, 1, &dwFileRead, NULL); memcpy(GPSVersion + i, buf, 2); } //Read GPSLatitudeRef ReadFile(tFile, buf, 1, &dwFileRead, NULL); memcpy(&GPSLatitudeRef, buf, 1); //Move file pointer to GPSLongitudeRef SetFilePointer(tFile, 0x17, NULL, FILE_CURRENT); ReadFile(tFile, buf, 1, &dwFileRead, NULL); memcpy(&GPSLongitudeRef, buf, 1); //Move file pointer to GPS Info SetFilePointer(tFile, 0x4f, NULL, FILE_CURRENT); //Get GPS Latitude Info int LatiTemp[6]; for(int i = 0; i < 6; i++) { ReadFile(tFile, buf, 1, &dwFileRead, NULL); ReadFile(tFile, buf + 1, 1, &dwFileRead, NULL); ReadFile(tFile, buf + 2, 1, &dwFileRead, NULL); ReadFile(tFile, buf + 3, 1, &dwFileRead, NULL); memcpy(LatiTemp + i, buf, 4); } for(int i = 0; i < 3; i++) GPSLatitude[i] = LatiTemp[2 * i] / (double)LatiTemp[2 * i + 1]; if(GPSLatitude[0] && GPSLatitude[1] && GPSLatitude[2]) HasGPSInfo = true; //Get GPS Longitude Info int LongiTemp[6]; for(int i = 0; i < 6; i++) { ReadFile(tFile, buf, 1, &dwFileRead, NULL); ReadFile(tFile, buf + 1, 1, &dwFileRead, NULL); ReadFile(tFile, buf + 2, 1, &dwFileRead, NULL); ReadFile(tFile, buf + 3, 1, &dwFileRead, NULL); memcpy(LongiTemp + i, buf, 4); } for(int i = 0; i < 3; i++) GPSLongitude[i] = LongiTemp[2 * i] / (double)LatiTemp[2 * i + 1]; } } } else { failInfo = "Fail to suit AfterTIFF symbol"; throw(failInfo); } } catch(string e) { cout << e << endl; } //close handle CloseHandle(hFile); if(HasGPSInfo == true) { cout << GPSLatitudeRef << " " << GPSLatitude[0] << "[degree] " << GPSLatitude[1] << "[minute] " << GPSLatitude[2] << "[second]" << endl; cout << GPSLongitudeRef << " " << GPSLongitude[0] << "[degree] " << GPSLongitude[1] << "[minute] " << GPSLongitude[2] << "[second]" << endl; } else cout << "No GPS Info" << endl; cout.flush(); system("pause"); return 0; }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值