2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 基于libexif写入/读取自定义Exif 信息(曝光模式 感光度 GPS等信息)

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

时间:2019-06-17 18:30:08

相关推荐

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

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);/*/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步骤:

创建一个entry入口设置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.jpsAdd customer exif info for test.jpg ok! #正常会有这个输出读取写入的exif信息:./read_jpeg_exif test_exif.jps-------------->ExifInfo:test_exif.jps Start<--------------======IFD: 0 0======X-Resolution: 72Y-Resolution: 72Resolution Unit: Inch======IFD: 1 1============IFD: 2 EXIF======Exposure Time: 1/18 sec.F-Number: f/4.0ISO Speed Ratings: 60Exposure Bias: 0.00 EVMaximum Aperture Value: 4.00 EV (f/4.0)Subject Distance: 0.0 mMetering Mode: PatternFlash: Flash firedFocal Length: 35.0 mmFlash Energy: 65535Exif Version: Exif Version 2.1FlashPixVersion: FlashPix Version 1.0Color Space: Uncalibrated======IFD: 3 GPS======North or South Latitude: WLatitude: 38.0, 132897/0, 0/0, 0/0, 0/0, 0/0, 0/0, 0/0East or West Longitude: NLongitude: 9.0, 132833/0, 0/0, 0/0, 0/0, 0/0, 0/0, 0/0======IFD: 4 Interoperability======-------------->ExifInfo:test_exif.jps End<--------------

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。