公司项目需要在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.添加到结果如最后.

static const unsigned char exif_header[] = {
0xff, 0xd8, 0xff, 0xe1,
};
/* length of data in exif_header */
static const unsigned int exif_header_len = sizeof(exif_header);
/* length of data in image_jpg */
static const unsigned int image_jpg_len ;//= sizeof(image_jpg);
/* start of JPEG image data section */
static const unsigned int image_data_offset = ;
#define image_data_len (image_jpg_len - image_data_offset) const char *pucMaker = "xx公司";
const char *pucModel = "拍照设备"; /* 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();
assert(mem != NULL); /* catch an out of memory condition */ /* Create a new ExifEntry using our allocator */
entry = exif_entry_new_mem (mem);
assert(entry != NULL); /* Allocate memory to use for holding the tag data */
buf = exif_mem_alloc(mem, len);
assert(buf != NULL); /* 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 */
exif_content_add_entry (exif->ifd[ifd], entry); /* The ExifMem and ExifEntry are now owned elsewhere */
exif_mem_unref(mem);
exif_entry_unref(entry);
return entry;
} //需要参考PowerExif.exe软件打开图片
//添加对应的只需要对应的代码ID,exifname、数据类型、和数据长度;
int cdr_write_exif_to_jpg(char *pSrcFileName, GPS_INFO sGpsInfo)
{
int rc = ;
char GPSversionid[]={0x02,0x02,0x00,0x00,0x00};
FILE *f = NULL; unsigned char *exif_data;
unsigned int exif_data_len;
FILE *f2 = fopen(pSrcFileName, "r");
if (!f2) {
fprintf(stderr, "Error creating file \n");
return -;
}
fseek (f2, , SEEK_END); ///将文件指针移动文件结尾
int iFileSize = ftell (f2); ///求出当前文件指针距离文件开始的字节数
fseek (f2, , SEEK_SET); char *buf = calloc(iFileSize,sizeof(char));
if(buf == NULL){
printf("calloc fails!\n");
fclose(f2);
return -;
} int i = ;
int pos = ;
char temp = ; for(i=; i<iFileSize-; i++)
{
temp = fgetc(f2);
if(EOF == temp) break;
buf[pos++] = temp;
}
buf[pos] = ;
fclose(f2); ExifEntry *entry = NULL; ExifData *exif = exif_data_new();
if (!exif) {
fprintf(stderr, "Out of memory\n");
free(buf);
buf=NULL;
return ;
} /* Set the image options */
exif_data_set_option(exif, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
exif_data_set_data_type(exif, EXIF_DATA_TYPE_COMPRESSED);
exif_data_set_byte_order(exif, FILE_BYTE_ORDER); /* Create the mandatory EXIF fields with default data */
//exif_data_fix(exif); entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_VERSION_ID,);
/* Write the special header needed for a comment tag */
entry->format = EXIF_FORMAT_BYTE;
entry->components = ;
exif_set_sshort(entry->data, FILE_BYTE_ORDER, GPSversionid[]);
exif_set_sshort(entry->data+, FILE_BYTE_ORDER, GPSversionid[]);
exif_set_sshort(entry->data+, FILE_BYTE_ORDER, GPSversionid[]);
exif_set_sshort(entry->data+, FILE_BYTE_ORDER, GPSversionid[]); entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF,);
entry->format = EXIF_FORMAT_ASCII;
memcpy(entry->data, "N", );
ExifRational a;
ExifRational b;
ExifRational c;
a.numerator = sGpsInfo.latitude_Degree;//纬度
a.denominator = ;
b.numerator = sGpsInfo.latitude_Cent;
b.denominator = ;
c.numerator = sGpsInfo.latitude_Second;
c.denominator = ;
entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE,);
entry->format = EXIF_FORMAT_RATIONAL;
entry->components = ;
exif_set_rational(entry->data,FILE_BYTE_ORDER,a);
exif_set_rational(entry->data+,FILE_BYTE_ORDER,b);
exif_set_rational(entry->data+,FILE_BYTE_ORDER,c); entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF,);
entry->format = EXIF_FORMAT_ASCII;
entry->components = ;
memcpy(entry->data, "E", ); a.numerator = sGpsInfo.longitude_Degree;
a.denominator = ;
b.numerator = sGpsInfo.longitude_Cent;
b.denominator = ;
c.numerator = sGpsInfo.longitude_Second;
c.denominator = ;
entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE,);
entry->format = EXIF_FORMAT_RATIONAL;
entry->components = ;
exif_set_rational(entry->data,FILE_BYTE_ORDER,a);
exif_set_rational(entry->data+,FILE_BYTE_ORDER,b);
exif_set_rational(entry->data+,FILE_BYTE_ORDER,c); //GPS速度单位K KM/H
entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_SPEED_REF,);
entry->format = EXIF_FORMAT_ASCII;
//entry->components = 1;
memcpy(entry->data, "K", ); //GPS速度值.
entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_SPEED,);
entry->format = EXIF_FORMAT_RATIONAL;
entry->components = ;
a.numerator = sGpsInfo.speed;
a.denominator = ;
exif_set_rational(entry->data,FILE_BYTE_ORDER,a); /*date time*/
entry = create_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL,);
entry->format = EXIF_FORMAT_ASCII;
//entry->components = 20;
char pDataTime[] = {};
sprintf(pDataTime,"%04d-%02d-%02d %02d:%02d:%02d",sGpsInfo.D.year,sGpsInfo.D.month,sGpsInfo.D.day,
sGpsInfo.D.hour,sGpsInfo.D.minute,sGpsInfo.D.second);
memcpy(entry->data,pDataTime,);
//厂商信息和设备信息
entry = create_tag(exif, EXIF_IFD_0, EXIF_TAG_MAKE,strlen(pucMaker)+);
entry->format = EXIF_FORMAT_ASCII;
memcpy(entry->data,pucMaker,strlen(pucMaker)); entry = create_tag(exif, EXIF_IFD_0, EXIF_TAG_MODEL,strlen(pucModel)+);
entry->format = EXIF_FORMAT_ASCII;
memcpy(entry->data,pucModel,strlen(pucModel)); exif_data_save_data(exif, &exif_data, &exif_data_len);
assert(exif_data != NULL); f = fopen(pSrcFileName, "wb");//write exif to this file pSrcFileName
if (!f) {
exif_data_unref(exif);
free(buf);
buf=NULL;
return rc;
}
/* Write EXIF header */
if (fwrite(exif_header, exif_header_len, , f) != ) {
goto errout;
}
/* Write EXIF block length in big-endian order */
if (fputc((exif_data_len+) >> , f) < ) {
goto errout;
}
if (fputc((exif_data_len+) & 0xff, f) < ) {
goto errout;
}
/* Write EXIF data block */
if (fwrite(exif_data, exif_data_len, , f) != ) {
goto errout;
} int image_data_len2 = iFileSize - image_data_offset;
/* Write JPEG image data, skipping the non-EXIF header */
if (fwrite(buf+image_data_offset, image_data_len2, , f) != ) {
goto errout;
}
rc = ;
free(buf);
buf = NULL;
fflush(f);
errout:
if (fclose(f)) {
fprintf(stderr, "Error writing to file %s\n", FILE_NAME);
rc = ;
}
/* The allocator we're using for ExifData is the standard one, so use
* it directly to free this pointer.
*/
free(exif_data);
exif_data_unref(exif);
return rc;
}

添加后的图片效果如下:

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. Docker 学习应用篇之二: Docker的介绍和安装

    之前说过Docker的好处,Docker可以集装箱化的部署应用程序.那么Docker是通过什么实现的呢.要理解Docker内部构建,需要先理解Docker的四种部件 1)images:镜像,docke ...

  2. 字符串匹配-KMP

    节选自 https://www.cnblogs.com/zhangtianq/p/5839909.html 字符串匹配 KMP O(m+n) O原来的暴力算法 当不匹配的时候 尽管之前文本串和模式串已 ...

  3. 肖俊:HPE IT 的DevOps 实践分享

    本篇文章来自于HPE和msup共同举办的技术开放日HPE测试技术总监肖俊的分享,由壹佰案例整理编辑. 一.DevOps含义解析 这是DevOps的趋势图.DevOps这个概念大概是在2009年被提出来 ...

  4. OpenCV学习笔记之课后习题练习2-3

    3.使用例2-10中的视频捕捉和存储方法,结合例2-5中的doPyrDown()创建一个程序,使其从摄像机读入视频数据并将缩放变换后的彩色图像存入磁盘. 例2-10中所用的方法虽然能正常运行,但却不能 ...

  5. H-数学考试 想法题+最新头文件 2018年长沙理工大学第十三届程序设计竞赛

    https://www.nowcoder.com/acm/contest/96/H 坑点:INF开太小了... #define _CRT_SECURE_NO_WARNINGS #include< ...

  6. iOS核心动画の摘记

  7. linux系统java的安装

    (一)下载java8 下载链接:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html ...

  8. 迷宫城堡--hdu1269(连通图)

    题目链接 连通图模板题:   #include<cstdio> #include<cstdlib> #include<cmath> #include<iost ...

  9. mysql 内置功能 存储过程 创建无参存储过程

    操作哪个数据库,就把存储过程建到那个数据库 例如 现在use db2; 应该把存储过程 建立到db2数据库里 创建无参存储过程 delimiter // # 设置mysql结束符合为// create ...

  10. python中各种数据类型

    数字类型 整型int 作用:年纪,等级,身份证号,qq号等与整型数字有关 定义: age=10 #本质age=int(10) 浮点型float 作用:薪资,身高,体重等与浮点数相关 salary=3. ...