libexif 简介

libexif 是一个用来读取数码相机照片中包含的 EXIF 信息的 C 语言库,支持多种平台。可以使用libexif 库对jpeg图片进行exif信息的写入,读取,修改等操作

libexif官网
libexif-github地址

使用libexif 给jepg图片添加exif信息

/* Get an existing tag, or create one if it doesn't exist */
static ExifEntry *init_tag(ExifData *exif, ExifIfd ifd, ExifTag tag)
{ExifEntry *entry;/* Return an existing tag if one exists */if (!((entry = exif_content_get_entry (exif->ifd[ifd], tag)))) {/* Allocate a new entry */entry = exif_entry_new ();assert(entry != NULL); /* catch an out of memory condition */entry->tag = tag; /* tag must be set before callingexif_content_add_entry *//* Attach the ExifEntry to an IFD */exif_content_add_entry (exif->ifd[ifd], entry);/* Allocate memory for the entry and fill with default data */exif_entry_initialize (entry, tag);/* Ownership of the ExifEntry has now been passed to the IFD.* One must be very careful in accessing a structure after* unref'ing it; in this case, we know "entry" won't be freed* because the reference count was bumped when it was added to* the IFD.*/exif_entry_unref(entry);}return entry;
}/* 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, ExifFormat format)
{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 = format;/* 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;
}long filesize( FILE *fp )
{long int save_pos;long size_of_file;/* Save the current position. */save_pos = ftell( fp );/* Jump to the end of the file. */fseek( fp, 0L, SEEK_END );/* Get the end position. */size_of_file = ftell( fp );/* Jump back to the original position. */fseek( fp, save_pos, SEEK_SET );return( size_of_file );
}/*给jpeg图片添加 exif信息input_file_fath 输入jpeg图片output_file_path 加exif信息的jpeg图片保存路径*/
int add_customer_exif_info_jpeg(char *input_file_fath, char *output_file_path)
{int rc = 1;unsigned char *exif_data = NULL;unsigned int exif_data_len;ExifEntry *entry = NULL;ExifData *exif = NULL;FILE *fp_src_file = NULL;FILE *fp_dst_file = NULL;unsigned long src_file_length;unsigned char *ptr_src_file_buf = NULL;char camera_maker[32];   // 相机制造商char camera_model[32];   // 实际型号unsigned short iso_val = 60;   //isoExifRational exposure_time;   //曝光时间ExifRational f_number;    //光圈值ExifSRational exposure_bias_value;ExifRational focal_length;    //光圈值ExifRational max_aperture_value;    //光圈值ExifShort metering_mode;          //测光模式ExifRational subject_distance;    //光圈值ExifShort flash_mode;              //闪光灯模式 ExifRational flash_energy;    //闪光灯能量ExifRational gps_lat;         //gps 经度ExifRational gps_long;         //gps 维度 char gps_lat_ref[2] = "W";char gps_long_ref[2] = "N";exif = exif_data_new();if (!exif) {fprintf(stderr, "Out of memory\n");return rc;}/* 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);/************EXIF信息添加**************************///相机制造商sprintf(camera_maker, "%s", "Sony");entry = create_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_MAKE, strlen(camera_maker) + 1, EXIF_FORMAT_ASCII);memcpy(entry->data, camera_maker, strlen(camera_maker) + 1);//相机型号sprintf(camera_model, "%s", "imx274");entry = create_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_MODEL, strlen(camera_model) + 1, EXIF_FORMAT_ASCII);memcpy(entry->data, camera_model, strlen(camera_model) + 1);//曝光时间设置 uint:sexposure_time.numerator = 1;exposure_time.denominator = 18;entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME);   exif_set_rational(entry->data, FILE_BYTE_ORDER, exposure_time);//ISO 大小entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS);exif_set_short(entry->data, FILE_BYTE_ORDER, iso_val);//曝光补偿 unit EVexposure_bias_value.numerator = 0;exposure_bias_value.denominator = 1;entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_BIAS_VALUE);exif_set_srational(entry->data, FILE_BYTE_ORDER, exposure_bias_value);//焦距 numerator/denominator,  uint mm focal_length.numerator = 35;focal_length.denominator = 1;entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH);exif_set_rational(entry->data, FILE_BYTE_ORDER, focal_length);/*https://baike.baidu.com/item/%E5%85%89%E5%9C%88%E5%80%BC/10310445?fr=aladdin最大光圈 AV f/(max_aperture_value.numerator/max_aperture_value.denominator)光圈值(AV) 0  1    2  3   4  5   6 7  8  9 10光圈数值(F)1  1.4  2  2.8 4  5.6 8 11 16 2232*///光圈值 最大光值f_number.numerator = 4;f_number.denominator = 1;entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_FNUMBER);exif_set_rational(entry->data, FILE_BYTE_ORDER, f_number);max_aperture_value.numerator = 4;max_aperture_value.denominator = 1;entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_MAX_APERTURE_VALUE);exif_set_rational(entry->data, FILE_BYTE_ORDER, max_aperture_value);/*测光模式 1~61 平均测光2 中央重点测光3 点测光4 多点测光5 矩阵测光6 部分测光*/metering_mode = 5;entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_METERING_MODE);exif_set_short(entry->data, FILE_BYTE_ORDER, metering_mode);//目标距离subject_distance.numerator = 0;subject_distance.denominator = 1;entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_SUBJECT_DISTANCE);exif_set_rational(entry->data, FILE_BYTE_ORDER, subject_distance);/*闪光灯模式0 - 关闭1 - 开启*/flash_mode = 1;entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_FLASH);exif_set_short(entry->data, FILE_BYTE_ORDER, flash_mode);//闪光灯能量 这里根据flash mode简单设置下 Unit:bcpsflash_energy.numerator = flash_mode > 0 ? 0xffff : 0;flash_energy.denominator = 1;entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_FLASH_ENERGY);exif_set_rational(entry->data, FILE_BYTE_ORDER, flash_energy);//gps 经度参考entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF, 2, EXIF_FORMAT_ASCII);memcpy(entry->data, gps_lat_ref, 2);//gps 经度gps_lat.numerator = 114;gps_lat.denominator = 3;entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE, sizeof(gps_lat), EXIF_FORMAT_RATIONAL);exif_set_rational(entry->data, FILE_BYTE_ORDER, gps_lat);//gps 纬度参考entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF,2, EXIF_FORMAT_ASCII);memcpy(entry->data, gps_long_ref, 2);//gps 纬度gps_long.numerator = 18;gps_long.denominator = 2;entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE, sizeof(gps_lat), EXIF_FORMAT_RATIONAL);exif_set_rational(entry->data, FILE_BYTE_ORDER, gps_long);/* Get a pointer to the EXIF data block we just created */exif_data_save_data(exif, &exif_data, &exif_data_len);assert(exif_data != NULL);fp_src_file = fopen(input_file_fath, "rb");if (!fp_src_file) {fprintf(stderr, "Error creating file %s\n", input_file_fath);exif_data_unref(exif);return rc;}/*read src jpeg file to buff*/src_file_length = filesize(fp_src_file);ptr_src_file_buf = (unsigned char *)malloc(src_file_length);if (!ptr_src_file_buf) {printf("Allocate buf for %s failed.\n", input_file_fath);goto errout;}if(fread(ptr_src_file_buf, src_file_length, 1, fp_src_file) != 1) {printf("Read %s error\n", input_file_fath);goto errout;}fclose(fp_src_file);if (!(ptr_src_file_buf[0] == 0xFF && ptr_src_file_buf[1] == 0xD8)) {printf("%s is not jpeg file,won't add exif for it!\n", input_file_fath);goto errout;}if ((ptr_src_file_buf[6] == 'E' && ptr_src_file_buf[7] == 'x' && ptr_src_file_buf[8] == 'i' && ptr_src_file_buf[9] == 'f')) {printf("%s adready add exif,won't overwrite exif info!\n", input_file_fath);goto errout;}fp_dst_file = fopen(output_file_path, "wb");if (!fp_dst_file) {fprintf(stderr, "Error creating file %s\n", output_file_path);exif_data_unref(exif);return rc;}/* Write EXIF header */if (fwrite(exif_header, exif_header_len, 1, fp_dst_file) != 1) {fprintf(stderr, "Error writing to file %s\n", output_file_path);goto errout;}/* Write EXIF block length in big-endian order */if (fputc((exif_data_len+2) >> 8, fp_dst_file) < 0) {fprintf(stderr, "Error writing to file %s\n", output_file_path);goto errout;}if (fputc((exif_data_len+2) & 0xff, fp_dst_file) < 0) {fprintf(stderr, "Error writing to file %s\n", output_file_path);goto errout;}/* Write EXIF data block */if (fwrite(exif_data, exif_data_len, 1, fp_dst_file) != 1) {fprintf(stderr, "Error writing to file %s\n", output_file_path);goto errout;}/* Write JPEG image data, skipping the non-EXIF header */if (fwrite(ptr_src_file_buf +image_data_offset, src_file_length-image_data_offset, 1, fp_dst_file) != 1) {fprintf(stderr, "Error writing to file %s\n", output_file_path);goto errout;}rc = 0;errout:if (ptr_src_file_buf) {free(ptr_src_file_buf);}/* 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;
}

int add_customer_exif_info_jpeg(char *input_file_fath, char *output_file_path)
这个函数就是对input_file_fath 图片添加自定义的exif信息,然后输出到output_file_path
从这个函数可以看到libexif添加exif信息的步骤也是相当简单,添加流程如下:

entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_METERING_MODE);
exif_set_short(entry->data, FILE_BYTE_ORDER, metering_mode);
或者
//gps 纬度
gps_long.numerator = 18;
gps_long.denominator = 2;
entry = create_tag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE, sizeof(gps_lat), EXIF_FORMAT_RATIONAL);
exif_set_rational(entry->data, FILE_BYTE_ORDER, gps_long);

init_tag()create_tag() 有点差异:
init_tag() 提供了常见的IFD及tag的初始化操作
create_tag() 如果init_tag() 没有默认支持你要操作IFD及tag,就用这个接口初始化一个entry

插入exif步骤:

  1. 创建一个entry入口
  2. 设置entery->data就可以了

使用libexif 读取jepg的exif信息

void read_exif_entry(ExifEntry *ee, void* ifd)
{char v[1024];
//  strncpy(t, exif_tag_get_title_in_ifd(ee->tag, exif_entry_get_ifd(ee)), sizeof(t));
//  strncpy(t, exif_tag_get_title_in_ifd(ee->tag, *((ExifIfd*)ifd)), sizeof(t));//trim tprintf("%s: %s\n"
//          , exif_tag_get_name_in_ifd(ee->tag, *((ExifIfd*)ifd)), exif_tag_get_title_in_ifd(ee->tag, *((ExifIfd*)ifd))
//          , exif_tag_get_description_in_ifd(ee->tag, *((ExifIfd*)ifd)), exif_entry_get_value(ee, v, sizeof(v)));
}void read_exif_content(ExifContent *ec, void *user_data)
{ExifIfd ifd = exif_content_get_ifd(ec);if (ifd == EXIF_IFD_COUNT)fprintf(stderr, "exif_content_get_ifd error");printf("======IFD: %d %s======\n", ifd, exif_ifd_get_name(ifd));exif_content_foreach_entry(ec, read_exif_entry, &ifd);
}int main(int argc, char** argv)
{if (argc < 2) {printf("Usage %s jpeg_list\n", argv[0]);}for (int i = 1; i<argc; i++) {printf("-------------->ExifInfo:%s Start<--------------\n", argv[i]);ExifData* ed = exif_data_new_from_file(argv[1]);if (!ed) {fprintf(stderr, "An error occur\n");return 1;}//exif_data_set_option(ed, exif_data_foreach_content(ed, read_exif_content, NULL);exif_data_unref(ed);printf("-------------->ExifInfo:%s End<--------------\n\n", argv[i]);}return 0;
}
···

读取exif信息过程也比较简单就是依次遍历各个entry,然后打印出entry相关的信息

exif_data_foreach_contentread_exif_content(ExifContent *ec, void *user_data)exif_content_foreach_entry(ec, read_exif_entry, &ifd);read_exif_entry(ExifEntry *ee, void* ifd) //这个函数最终会打印出各个Entery的内容

代码资源地址及使用方法

csdn资源地址
代码使用SourceInsight 或者notepad++ 打开,否则可能出现中文乱码
资源详细的使用见里面的MyReadme.txt,这里简单的介绍下资源的使用:

1.编译库运行libexif-mater 文件夹的mybuild_ubuntu.sh运行后当前目录build的文件夹会有编译文件ls build/include  lib  share2. 编译示例democd contrib/examples/./compile_exampale.shgcc -Wall -I ../../build/include/ --static -o photographer photographer.c -L ../../build/lib/ -lexif -lmgcc -Wall -I ../../build/include/ --static -o thumbnail thumbnail.c -L ../../build/lib/ -lexif -lmgcc -Wall -I ../../build/include/ --static -o write-exif write-exif.c -L ../../build/lib/ -lexif -lmgcc -Wall -I ../../build/include/ --static -o test_jpeg_exif_new test_jpeg_exif_new.c -L ../../build/lib/ -lexif -lmgcc -Wall -I ../../build/include/ --static -o read_jpeg_exif read_jpeg_exif.c -L ../../build/lib/ -lexif -lmAll done!!!test_jpeg_exif_new  写自定义exif 信息
read_jpeg_exif 读取写入的exif信息写exif 信息使用:
用windows自带画图软件随便产生一个jpg文件或者使用自带的test.jpg文件
./test_jpeg_exif_new test.jpg test_exif.jps
Add customer exif info for test.jpg ok! #正常会有这个输出读取写入的exif信息:./read_jpeg_exif test_exif.jps
-------------->ExifInfo:test_exif.jps Start<--------------
======IFD: 0 0======
X-Resolution: 72
Y-Resolution: 72
Resolution Unit: Inch
======IFD: 1 1======
======IFD: 2 EXIF======
Exposure Time: 1/18 sec.
F-Number: f/4.0
ISO Speed Ratings: 60
Exposure Bias: 0.00 EV
Maximum Aperture Value: 4.00 EV (f/4.0)
Subject Distance: 0.0 m
Metering Mode: Pattern
Flash: Flash fired
Focal Length: 35.0 mm
Flash Energy: 65535
Exif Version: Exif Version 2.1
FlashPixVersion: FlashPix Version 1.0
Color Space: Uncalibrated
======IFD: 3 GPS======
North or South Latitude: W
Latitude: 38.0, 132897/0, 0/0, 0/0, 0/0, 0/0, 0/0, 0/0
East or West Longitude: N
Longitude: 9.0, 132833/0, 0/0, 0/0, 0/0, 0/0, 0/0, 0/0
======IFD: 4 Interoperability======
-------------->ExifInfo:test_exif.jps End<--------------

基于libexif写入/读取自定义Exif 信息(曝光模式,感光度,GPS等信息)相关推荐

  1. 从EXIF JPEG图片中提取GPS位置信息

    符合EXIFJPEG标准的图片,除了记录图片压缩数据之外,在存储了拍摄参数,其中包括拍摄时GPS参数信息,因此,可以利用程序从EXIF元数据信息中解析提取GPS位置信息. 1. Java读取EXIF信 ...

  2. php 写入exif,PHP写入读取图片自定义信息_exif或者什么的?

    PHP 图片 需求描述: 使用PHP对图片文件进行优化处理,但此优化处理只能进行一次,二次进行会对图片造成不可恢复的损坏.期望在图片一次处理之后,在图片文件中写入一个自定义的字符串,什么都行,仅用于判 ...

  3. Python读取DJI无人机拍摄照片中的DJI自定义EXIF信息

    Python读取DJI无人机拍摄照片中的DJI自定义EXIF信息 b = b"\x3c\x2f\x72\x64\x66\x3a\x44\x65\x73\x63\x72\x69\x70\x74 ...

  4. java exif 语言编码_Java读取图片EXIF信息的代码

    Java读取图片EXIF信息的代码 本文实例讲述了Java读取图片EXIF信息的方法.分享给大家供大家参考.具体分析如下: 首先介绍一下什么是EXIF,EXIF是Exchangeable Image ...

  5. 纯 python 开发批量读取照片 Exif 信息的小程序

    自己动手写一些小程序解决工作中的问题,是学习 python 的高效途径.这中间会遇到一些不动手想不到的问题,一个一个地解决它们,你 python 开发水平就会突飞猛进! 本文总结一下实战 python ...

  6. 基于python实现读取区块信息

    基于python实现读取区块信息 编写简单的服务器与客户端. socket编程思路: TCP服务端 (1)建套接字,绑定套接字到本地IP与端口 socket.socket(socket.AF_INET ...

  7. php 获取照片信息,PHP中读取照片exif信息的方法

    这篇文章主要介绍了PHP中读取照片exif信息的方法,本文从什么是exif信息开始讲解,使用PHP需要什么扩展.及它的安装方法和使用代码示例等,需要的朋友可以参考下 先来了解什么是图片的Exif信息 ...

  8. java exif 怎么获取属性_Java如何读取图片EXIF信息

    Java如何读取图片EXIF信息 大家知道Java如何读取图片属性信息吗?下面小编为大家整理了Java读取图片EXIF信息的方法,希望能帮到大家! 首先介绍一下什么是EXIF,EXIF是Exchang ...

  9. STM32挂载SD卡基于Fatfs文件系统读取文件信息

    STM32挂载SD卡基于Fatfs文件系统读取文件信息

  10. JAVA 拍照 exif GPS_读取图片EXIF块中GPS信息,转换为高德地图API坐标

    最近两天做了一个需求,从APP端上传的照片信息里面读取出GPS位置信息,然后翻译成可读的地点信息. 总结一下,分为三步: (1)提取图片中的GPS信息,使用到了metadata-extractor; ...

最新文章

  1. js 原生跨页面通信_DOM操作是跨线程的你知道吗?
  2. Stixel_World(single)学习笔记
  3. 最小正连续子序列和 问题
  4. SVN服务器与客户端的配置
  5. c语言int val,c语言不定参数与printf函数的实现
  6. MacBook/MacOS/Mac OS 关于启动/停止/重启服务(进程/程序)的命令
  7. MySQL多项模糊查询
  8. JDBC学习笔记——事务、存储过程以及批量处理
  9. 权威预测:未来一年,企业云服务将会如何发展?
  10. ell服务器专用pe系统,GitHub - elltor/smpe-admin: 后端通用开发框架
  11. 2021年中国电子签名行业研究报告
  12. 机器学习课程笔记【五】- 支持向量机(1)
  13. Linux内核探索之路——关于书
  14. html语言个人网页,个人网页介绍家乡纯html
  15. 微信公众号H5支付的两种方式
  16. 「手绘控笔技巧」最有效的控笔练习,让你少走很多弯路
  17. 通过Jquery实现文本高亮及取消高亮
  18. oracle有dba角色用户,ORACLE管理-查看拥有DBA角色的用户
  19. 解决Outlook不能打开的问题
  20. wpf图表-Visifire使用教程分享

热门文章

  1. DNS解析出错导致网站在部分地区无法打开
  2. Mysql UDF Bug “ERROR 1125 (HY000): Function ‘xxx‘ already exists“
  3. 【电子知识摘要】合金电阻
  4. h61 nvme硬盘_免装系统!机械硬盘系统迁移至固态硬盘技巧
  5. GD32E230按键软件消抖程序
  6. 常用技术网站2017-2018
  7. 根据投资回报率(ROI)进行决策
  8. 沙箱环境和正式环境【PayPal接入(java)】【IPN通知问题】项目实战干货总结记录!
  9. h5截长图(html2canvas保存图片)
  10. 电壁挂炉该如何配电表和电线