公司项目需要在jpeg图片里面添加exif信息,同事完成了这部分代码;但是有些手机兼容性有问题;

libexif 地址:http://libexif.sourceforge.net/

注意相关资料来之:

http://blog.csdn.net/fioletfly/article/details/53605959

注意使用的工具为:PowerExif.exe,因为项目太多了,需要对比添加~有工具可以比较好的参考.

手机兼容有问题,注意是因为一些项目没按照exif标准来添加;按标准来添加,添加后用PowerExif.exe解析,如果每项都正常了,基本手机解析不会有问题;

代码如下:

1.前面代码来至src sample下面的;

2.添加了一些必要的exif信息;

3.添加到结果如最后.

  1. static const unsigned char exif_header[] = {
  2. 0xff, 0xd8, 0xff, 0xe1,
  3. };
  4. /* length of data in exif_header */
  5. static const unsigned int exif_header_len = sizeof(exif_header);
  6. /* length of data in image_jpg */
  7. static const unsigned int image_jpg_len ;//= sizeof(image_jpg);
  8. /* start of JPEG image data section */
  9. static const unsigned int image_data_offset = ;
  10. #define image_data_len (image_jpg_len - image_data_offset)
  11.  
  12. const char *pucMaker = "xx公司";
  13. const char *pucModel = "拍照设备";
  14.  
  15. /* Create a brand-new tag with a data field of the given length, in the
  16. * given IFD. This is needed when exif_entry_initialize() isn't able to create
  17. * this type of tag itself, or the default data length it creates isn't the
  18. * correct length.
  19. */
  20. static ExifEntry *create_tag(ExifData *exif, ExifIfd ifd, ExifTag tag, size_t len)
  21. {
  22. void *buf;
  23. ExifEntry *entry;
  24.  
  25. /* Create a memory allocator to manage this ExifEntry */
  26. ExifMem *mem = exif_mem_new_default();
  27. assert(mem != NULL); /* catch an out of memory condition */
  28.  
  29. /* Create a new ExifEntry using our allocator */
  30. entry = exif_entry_new_mem (mem);
  31. assert(entry != NULL);
  32.  
  33. /* Allocate memory to use for holding the tag data */
  34. buf = exif_mem_alloc(mem, len);
  35. assert(buf != NULL);
  36.  
  37. /* Fill in the entry */
  38. entry->data = buf;
  39. entry->size = len;
  40. entry->tag = tag;
  41. entry->components = len;
  42. entry->format = EXIF_FORMAT_UNDEFINED;
  43.  
  44. /* Attach the ExifEntry to an IFD */
  45. exif_content_add_entry (exif->ifd[ifd], entry);
  46.  
  47. /* The ExifMem and ExifEntry are now owned elsewhere */
  48. exif_mem_unref(mem);
  49. exif_entry_unref(entry);
  50. return entry;
  51. }
  52.  
  53. //需要参考PowerExif.exe软件打开图片
  54. //添加对应的只需要对应的代码ID,exifname、数据类型、和数据长度;
  55. int cdr_write_exif_to_jpg(char *pSrcFileName, GPS_INFO sGpsInfo)
  56. {
  57. int rc = ;
  58. char GPSversionid[]={0x02,0x02,0x00,0x00,0x00};
  59. FILE *f = NULL;
  60.  
  61. unsigned char *exif_data;
  62. unsigned int exif_data_len;
  63. FILE *f2 = fopen(pSrcFileName, "r");
  64. if (!f2) {
  65. fprintf(stderr, "Error creating file \n");
  66. return -;
  67. }
  68. fseek (f2, , SEEK_END); ///将文件指针移动文件结尾
  69. int iFileSize = ftell (f2); ///求出当前文件指针距离文件开始的字节数
  70. fseek (f2, , SEEK_SET);
  71.  
  72. char *buf = calloc(iFileSize,sizeof(char));
  73. if(buf == NULL){
  74. printf("calloc fails!\n");
  75. fclose(f2);
  76. return -;
  77. }
  78.  
  79. int i = ;
  80. int pos = ;
  81. char temp = ;
  82.  
  83. for(i=; i<iFileSize-; i++)
  84. {
  85. temp = fgetc(f2);
  86. if(EOF == temp) break;
  87. buf[pos++] = temp;
  88. }
  89. buf[pos] = ;
  90. fclose(f2);
  91.  
  92. ExifEntry *entry = NULL;
  93.  
  94. ExifData *exif = exif_data_new();
  95. if (!exif) {
  96. fprintf(stderr, "Out of memory\n");
  97. free(buf);
  98. buf=NULL;
  99. return ;
  100. }
  101.  
  102. /* Set the image options */
  103. exif_data_set_option(exif, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
  104. exif_data_set_data_type(exif, EXIF_DATA_TYPE_COMPRESSED);
  105. exif_data_set_byte_order(exif, FILE_BYTE_ORDER);
  106.  
  107. /* Create the mandatory EXIF fields with default data */
  108. //exif_data_fix(exif);
  109.  
  110. entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_VERSION_ID,);
  111. /* Write the special header needed for a comment tag */
  112. entry->format = EXIF_FORMAT_BYTE;
  113. entry->components = ;
  114. exif_set_sshort(entry->data, FILE_BYTE_ORDER, GPSversionid[]);
  115. exif_set_sshort(entry->data+, FILE_BYTE_ORDER, GPSversionid[]);
  116. exif_set_sshort(entry->data+, FILE_BYTE_ORDER, GPSversionid[]);
  117. exif_set_sshort(entry->data+, FILE_BYTE_ORDER, GPSversionid[]);
  118.  
  119. entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF,);
  120. entry->format = EXIF_FORMAT_ASCII;
  121. memcpy(entry->data, "N", );
  122. ExifRational a;
  123. ExifRational b;
  124. ExifRational c;
  125. a.numerator = sGpsInfo.latitude_Degree;//纬度
  126. a.denominator = ;
  127. b.numerator = sGpsInfo.latitude_Cent;
  128. b.denominator = ;
  129. c.numerator = sGpsInfo.latitude_Second;
  130. c.denominator = ;
  131. entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE,);
  132. entry->format = EXIF_FORMAT_RATIONAL;
  133. entry->components = ;
  134. exif_set_rational(entry->data,FILE_BYTE_ORDER,a);
  135. exif_set_rational(entry->data+,FILE_BYTE_ORDER,b);
  136. exif_set_rational(entry->data+,FILE_BYTE_ORDER,c);
  137.  
  138. entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF,);
  139. entry->format = EXIF_FORMAT_ASCII;
  140. entry->components = ;
  141. memcpy(entry->data, "E", );
  142.  
  143. a.numerator = sGpsInfo.longitude_Degree;
  144. a.denominator = ;
  145. b.numerator = sGpsInfo.longitude_Cent;
  146. b.denominator = ;
  147. c.numerator = sGpsInfo.longitude_Second;
  148. c.denominator = ;
  149. entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE,);
  150. entry->format = EXIF_FORMAT_RATIONAL;
  151. entry->components = ;
  152. exif_set_rational(entry->data,FILE_BYTE_ORDER,a);
  153. exif_set_rational(entry->data+,FILE_BYTE_ORDER,b);
  154. exif_set_rational(entry->data+,FILE_BYTE_ORDER,c);
  155.  
  156. //GPS速度单位K KM/H
  157. entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_SPEED_REF,);
  158. entry->format = EXIF_FORMAT_ASCII;
  159. //entry->components = 1;
  160. memcpy(entry->data, "K", );
  161.  
  162. //GPS速度值.
  163. entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_SPEED,);
  164. entry->format = EXIF_FORMAT_RATIONAL;
  165. entry->components = ;
  166. a.numerator = sGpsInfo.speed;
  167. a.denominator = ;
  168. exif_set_rational(entry->data,FILE_BYTE_ORDER,a);
  169.  
  170. /*date time*/
  171. entry = create_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL,);
  172. entry->format = EXIF_FORMAT_ASCII;
  173. //entry->components = 20;
  174. char pDataTime[] = {};
  175. sprintf(pDataTime,"%04d-%02d-%02d %02d:%02d:%02d",sGpsInfo.D.year,sGpsInfo.D.month,sGpsInfo.D.day,
  176. sGpsInfo.D.hour,sGpsInfo.D.minute,sGpsInfo.D.second);
  177. memcpy(entry->data,pDataTime,);
  178. //厂商信息和设备信息
  179. entry = create_tag(exif, EXIF_IFD_0, EXIF_TAG_MAKE,strlen(pucMaker)+);
  180. entry->format = EXIF_FORMAT_ASCII;
  181. memcpy(entry->data,pucMaker,strlen(pucMaker));
  182.  
  183. entry = create_tag(exif, EXIF_IFD_0, EXIF_TAG_MODEL,strlen(pucModel)+);
  184. entry->format = EXIF_FORMAT_ASCII;
  185. memcpy(entry->data,pucModel,strlen(pucModel));
  186.  
  187. exif_data_save_data(exif, &exif_data, &exif_data_len);
  188. assert(exif_data != NULL);
  189.  
  190. f = fopen(pSrcFileName, "wb");//write exif to this file pSrcFileName
  191. if (!f) {
  192. exif_data_unref(exif);
  193. free(buf);
  194. buf=NULL;
  195. return rc;
  196. }
  197. /* Write EXIF header */
  198. if (fwrite(exif_header, exif_header_len, , f) != ) {
  199. goto errout;
  200. }
  201. /* Write EXIF block length in big-endian order */
  202. if (fputc((exif_data_len+) >> , f) < ) {
  203. goto errout;
  204. }
  205. if (fputc((exif_data_len+) & 0xff, f) < ) {
  206. goto errout;
  207. }
  208. /* Write EXIF data block */
  209. if (fwrite(exif_data, exif_data_len, , f) != ) {
  210. goto errout;
  211. }
  212.  
  213. int image_data_len2 = iFileSize - image_data_offset;
  214. /* Write JPEG image data, skipping the non-EXIF header */
  215. if (fwrite(buf+image_data_offset, image_data_len2, , f) != ) {
  216. goto errout;
  217. }
  218. rc = ;
  219. free(buf);
  220. buf = NULL;
  221. fflush(f);
  222. errout:
  223. if (fclose(f)) {
  224. fprintf(stderr, "Error writing to file %s\n", FILE_NAME);
  225. rc = ;
  226. }
  227. /* The allocator we're using for ExifData is the standard one, so use
  228. * it directly to free this pointer.
  229. */
  230. free(exif_data);
  231. exif_data_unref(exif);
  232. return rc;
  233. }

添加后的图片效果如下:

jpeg exif的更多相关文章

  1. wechall.net/stegano 解题心得

    /* 转载请注明出处:http://www.cnblogs.com/Martinium/p/wechall_stegano.html */ 最近迷上了 www.wechall.net 网站,里面都是些 ...

  2. C# GDI+学习笔记1

    —前言 本文是学习C# GDI+系列的第一篇文章,简单的介绍了GDI+的一些基本绘图内容,比较粗糙.但本文主要是让大家简单的回顾一下GDI+的基本概念.本篇文章的参考代码请在此下载 . GDIPTes ...

  3. Win32中GDI+应用(一)

    GDI+, Microsoft Graphics Device Interface Plus, 是微软在继GDI(Microsoft Graphics Device Interface)后推出的图形编 ...

  4. 【转】高通平台android 环境配置编译及开发经验总结

    原文网址:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通 ...

  5. Java 遍历文件下jpg图片并解析图片

      package filetest; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; ...

  6. JS实现图片base64转blob对象,压缩图片,预览图片,图片旋转到正确角度

    base64转blob对象 /** 将base64转换为文件对象 * @param {String} base64 base64字符串 * */ var convertBase64ToBlob = f ...

  7. 女朋友会 Python 是多么可怕的一件事!

    ​ 阅读文本大概需要 8 分钟. 1 目 标 场 景 女朋友会 Python 是多么可怕的一件事! 一位朋友告诉忽略了一件事,假设女朋友会 Python 的话,那岂不是要翻车?如果是这样的话,女朋友发 ...

  8. thinkphp 根据文件后缀的不同返回不同的结果

    ** * 根据文件后缀的不同返回不同的结果 * @param string $str 需要判断的文件名或者文件的id * @return integer 1:图片 2:视频 3:压缩文件 4:文档 5 ...

  9. 【纯净软件】三款照片EXIF信息删除软件 Clear Exif、JPEG & PNG Stripper、Easy Exif Delete 非专业横向对比

    商业软件:需支付费用后方可使用. 共享软件:需支付费用,但可以先免费试用(有使用期限.功能限制). 免费软件:无需支付费用,无使用期限,无功能限制. 纯净软件:无广告.无联网行为的免费软件. 自由软件 ...

随机推荐

  1. vue之cli脚手架项目中组件的使用

    在webpack-simple模板中,包括webpck模板.一个.vue文件就是一个组件. 为什么会这样呢?因为webpack干活了!webpack的将我们所有的资源文件进行打包.同时webpack还 ...

  2. [CentOS_7.4]Linux安装与网络配置

    一 安装 官网下载ISO安装文件:https://www.centos.org/download/ 然后自行安装. 二 配置网络 a.配置动态ip 1 2 3 1)# vi /etc/sysconfi ...

  3. <input type=file>上传唯一控件

    值得注意的是:当一个表单里面包含这个上传元素的时候,表单的enctype必须指定为multipart/form-data,method必须指定为post,浏览器才会认识并正确执行.但是还有一点,浏览器 ...

  4. nginx处理问题笔记

    1. 处理所有请求到单一入口 (  rewrite all requests to index.php with nginx ) 目前我们做开发一般都是单入口的,所以都会使用web服务器做重定向到入口 ...

  5. curl获取公网IP地址

    curl ip.cn curl cip.cc https://blog.csdn.net/orangleliu/article/details/51994513 https://blog.csdn.n ...

  6. django源码笔记-【2】(转)

    add by zhj: 在原文的基础上有修改 原文:http://www.cnblogs.com/gaott/archive/2012/02/28/2371238.html 上一期完理解了WSGI处理 ...

  7. kubernetes实战(十五):k8s使用helm持久化部署jenkins集成openLDAP登录

    1.基本概念 Jenkins在DevOps工具链中是核心的流程管理中心,负责串联系统的构建流程.测试流程.镜像制作流程.部署流程等,在持续集成中常用到的工具如下: Maven:源代码编译工具 Robo ...

  8. iptables 常用命令

    iptables service iptables save \\保存 iptables -F \\清空所有规则 iptables -F -t nat \\清空nat表 iptables -t nat ...

  9. python接口自动化 -参数关联(一)

    原文地址https://www.cnblogs.com/yoyoketang/p/6886610.html 原文地址https://www.cnblogs.com/yoyoketang/ 原文地址ht ...

  10. The Air Jordan 11 Gym Red will be available December 9

    A few years ago Carmelo Anthony set the internet on fire when he was spotted rocking a never before ...