入门客AI创业平台(我带你入门,你带我飞行)
博文笔记

读取JPG图片的Exif属性(三) - Exif属性读取GPS信息代码(C/C++实现)

创建时间:2017-01-06 投稿人: 浏览次数:5102

Exif中GPS格式

本文是最后一篇关于Exif文章,终于要挑战最大的boss了,这个GPS信息的读取,我找了国内外很多资料都没有找 真正的实例。所以自己前两篇的基础上推断而来的。

读取JPG图片的Exif属性 - Exif信息简介

读取JPG图片的Exif属性 - C代码实现

 其实这个只要能够理解前面两篇的内容也就很容易获得GPS信息,但是还是要理解GPS的格式和各种tag参数。可以重新学习一下其格式如下:    GPS Info IFD Pointer 0x02AE  从上面数据2A0行的后面看数据
   00 05       count of TAGs
   
   00 00       GPSVersionID
   00 01       BYTE
   00 00 00 04 count
   02 02 00 00 value 2.2.0.0
   
   00 01       GPSLatitudeRef
   00 02       ASCII
   00 00 00 02 count
   4E 00 00 00 N North  
   
   00 02       GPSLatitude
   00 05       RATIONAL               前4字节为分子,后4字节为分母,十六进制先转为十进制
   00 00 00 03 count
   00 00 05 46 offset+0c=0x552 16 00 00 00 01 00 00 00 22 00 00 00 01 00 00 00 51 00 00 00 04 00 00 00
                                                       22/1=22                             34/1=34                              81/4= 20.25
                                                      通过windows的右键属性看详细信息:22;34;20.249999999999915
   00 03       GPSLongitudeRef
   00 02
   00 00 00 02 count
   45 00 00 00 East
   
   00 04       GPSLongitude
   00 05       RATIONAL
   00 00 00 03 count
   00 00 05 5E offset+0c=0x56A 71 00 00 00 01 00 00 00 37 00 00 00 01 00 00 00 6C 00 00 00 04 00
                                                       113/1=113                          55/1=55                             108/4=27
                                                    通过windows的右键属性看详细信息:113;55;27.000000000000171
主要的函数还是要进入到如下得函数中:  DecodeExif 函数主要是获取到Eixf属性在图片数据中入口地址: process_EXIF 主要是对Exif属性做一个前期的处理,为了进一步详细的分析做处理 ProcessExifDir主要是对Exif属性详细的分析和处理。

GPS入口的定位

GPS入口的定位就同上篇中关于Exif属性的定位入口是一个道理,因为GPS本身就是一个大section,在这个section中又有很多tag,而且tag的格式也是Exif属性中tag的格式是一样的。所以看到这里就比较简单了,其实就是利用上篇中读取Exif属性的代码来事项GPS。具体是现在Exif中定位到GPS入口下代码: 可以看到在最后的Tag中是可以找到GPS信息的入口,这是就可以定位GPS属性了,所以找到入口地址,进入到GPS所在位置进行分析。
  1. case TAG_GPS_INFO:
  2. unsigned char * SubdirStart;
  3. SubdirStart = OffsetBase + Get32u(ValuePtr);
  4. CalGPS(SubdirStart, OffsetBase);
  5. break;
  1. /*--------------------------------------------------------------------------
  2. Process one of the nested EXIF directories.
  3. --------------------------------------------------------------------------*/
  4. bool Cexif::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength,
  5. EXIFINFO * const m_exifinfo, unsigned char ** const LastExifRefdP )
  6. {
  7. int de;
  8. int a;
  9. int NumDirEntries;
  10. unsigned ThumbnailOffset = 0;
  11. unsigned ThumbnailSize = 0;
  12. unsigned long gps = 0;
  13. NumDirEntries = Get16u(DirStart);
  14. if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength)){
  15. strcpy(m_szLastError,"Illegally sized directory");
  16. return 0;
  17. }
  18. for (de=0;de<NumDirEntries;de++)
  19. {
  20. int Tag, Format, Components;
  21. unsigned char * ValuePtr;
  22. /* This actually can point to a variety of things; it must be
  23. cast to other types when used. But we use it as a unsigned char-by-unsigned char
  24. cursor, so we declare it as a pointer to a generic unsigned char here.
  25. */
  26. int BytesCount;
  27. unsigned char * DirEntry;
  28. DirEntry = DirStart+2+12*de;
  29. Tag = Get16u(DirEntry);
  30. Format = Get16u(DirEntry+2);
  31. Components = Get32u(DirEntry+4);
  32. if ((Format-1) >= NUM_FORMATS) {
  33. /* (-1) catches illegal zero case as unsigned underflows to positive large */
  34. strcpy(m_szLastError,"Illegal format code in EXIF dir");
  35. return 0;
  36. }
  37. BytesCount = Components * BytesPerFormat[Format];
  38. if (BytesCount > 4){
  39. unsigned OffsetVal;
  40. OffsetVal = Get32u(DirEntry+8);
  41. /* If its bigger than 4 unsigned chars, the dir entry contains an offset.*/
  42. if (OffsetVal+BytesCount > ExifLength){
  43. /* Bogus pointer offset and / or unsigned charcount value */
  44. strcpy(m_szLastError,"Illegal pointer offset value in EXIF.");
  45. return 0;
  46. }
  47. ValuePtr = OffsetBase+OffsetVal;
  48. }else{
  49. /* 4 unsigned chars or less and value is in the dir entry itself */
  50. ValuePtr = DirEntry+8;
  51. }
  52. if (*LastExifRefdP < ValuePtr+BytesCount){
  53. /* Keep track of last unsigned char in the exif header that was
  54. actually referenced. That way, we know where the
  55. discardable thumbnail data begins.
  56. */
  57. *LastExifRefdP = ValuePtr+BytesCount;
  58. }
  59. /* Extract useful components of tag */
  60. switch(Tag){
  61. case TAG_MAKE:
  62. strncpy(m_exifinfo->CameraMake, (char*)ValuePtr, 31);
  63. break;
  64. case TAG_MODEL:
  65. strncpy(m_exifinfo->CameraModel, (char*)ValuePtr, 39);
  66. break;
  67. case TAG_EXIF_VERSION:
  68. strncpy(m_exifinfo->Version,(char*)ValuePtr, 4);
  69. break;
  70. case TAG_DATETIME_ORIGINAL:
  71. strncpy(m_exifinfo->DateTime, (char*)ValuePtr, 19);
  72. break;
  73. case TAG_USERCOMMENT:
  74. // Olympus has this padded with trailing spaces. Remove these first.
  75. for (a=BytesCount;;){
  76. a--;
  77. if (((char*)ValuePtr)[a] == " "){
  78. ((char*)ValuePtr)[a] = "";
  79. }else{
  80. break;
  81. }
  82. if (a == 0) break;
  83. }
  84. /* Copy the comment */
  85. if (memcmp(ValuePtr, "ASCII",5) == 0){
  86. for (a=5;a<10;a++){
  87. char c;
  88. c = ((char*)ValuePtr)[a];
  89. if (c != "" && c != " "){
  90. strncpy(m_exifinfo->Comments, (char*)ValuePtr+a, 199);
  91. break;
  92. }
  93. }
  94. }else{
  95. strncpy(m_exifinfo->Comments, (char*)ValuePtr, 199);
  96. }
  97. break;
  98. case TAG_FNUMBER:
  99. /* Simplest way of expressing aperture, so I trust it the most.
  100. (overwrite previously computd value if there is one)
  101. */
  102. m_exifinfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
  103. break;
  104. case TAG_APERTURE:
  105. case TAG_MAXAPERTURE:
  106. /* More relevant info always comes earlier, so only
  107. use this field if we don"t have appropriate aperture
  108. information yet.
  109. */
  110. if (m_exifinfo->ApertureFNumber == 0){
  111. m_exifinfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)*0.5);
  112. }
  113. break;
  114. case TAG_BRIGHTNESS:
  115. m_exifinfo->Brightness = (float)ConvertAnyFormat(ValuePtr, Format);
  116. break;
  117. case TAG_FOCALLENGTH:
  118. /* Nice digital cameras actually save the focal length
  119. as a function of how farthey are zoomed in.
  120. */
  121. m_exifinfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
  122. break;
  123. case TAG_SUBJECT_DISTANCE:
  124. /* Inidcates the distacne the autofocus camera is focused to.
  125. Tends to be less accurate as distance increases.
  126. */
  127. m_exifinfo->Distance = (float)ConvertAnyFormat(ValuePtr, Format);
  128. break;
  129. case TAG_EXPOSURETIME:
  130. /* Simplest way of expressing exposure time, so I
  131. trust it most. (overwrite previously computd value
  132. if there is one)
  133. */
  134. m_exifinfo->ExposureTime =
  135. (float)ConvertAnyFormat(ValuePtr, Format);
  136. break;
  137. case TAG_SHUTTERSPEED:
  138. /* More complicated way of expressing exposure time,
  139. so only use this value if we don"t already have it
  140. from somewhere else.
  141. */
  142. if (m_exifinfo->ExposureTime == 0){
  143. m_exifinfo->ExposureTime = (float)
  144. (1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)));
  145. }
  146. break;
  147. case TAG_FLASH:
  148. if ((int)ConvertAnyFormat(ValuePtr, Format) & 7){
  149. m_exifinfo->FlashUsed = 1;
  150. 声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。
    • 上一篇:没有了
    • 下一篇:没有了
未上传头像