int main () { ExifData *d; ExifEntry *e; char v[1024]; ExifSRational r = {1., 20.}; unsigned int i; d = exif_data_new (); if (!d) { printf ("Error running exif_data_new()\n"); exit(13); } e = exif_entry_new (); if (!e) { printf ("Error running exif_entry_new()\n"); exit(13); } exif_content_add_entry (d->ifd[EXIF_IFD_0], e); exif_entry_initialize (e, EXIF_TAG_SHUTTER_SPEED_VALUE); exif_set_srational (e->data, exif_data_get_byte_order (d), r); for (i = 30; i > 0; i--) { printf ("Length %2i: '%s'\n", i, exif_entry_get_value (e, v, i)); } exif_entry_unref (e); exif_data_unref (d); return 0; }
/* Write a tag. Update what's there, or make a new one. */ static void vips_exif_set_tag( ExifData *ed, int ifd, ExifTag tag, write_fn fn, void *data ) { ExifEntry *entry; if( (entry = exif_content_get_entry( ed->ifd[ifd], tag )) ) { fn( ed, entry, 0, data ); } else { entry = exif_entry_new(); /* tag must be set before calling exif_content_add_entry. */ entry->tag = tag; exif_content_add_entry( ed->ifd[ifd], entry ); exif_entry_unref( entry ); /* libexif makes us have a special path for string-valued * fields :( */ if( tag_is_encoding( tag ) ) vips_exif_set_string_encoding( ed, entry, 0, data ); else if( tag_is_ascii( tag ) ) vips_exif_set_string_ascii( ed, entry, 0, data ); else if( tag_is_utf16( tag ) ) vips_exif_set_string_utf16( ed, entry, 0, data ); else { exif_entry_initialize( entry, tag ); fn( ed, entry, 0, data ); } } }
void exif_content_free (ExifContent * content) { unsigned int i; for (i = 0; i < content->count; i++) exif_entry_unref (content->entries[i]); free (content->entries); free (content->priv); free (content); }
// Create an entry and place it in |exifData|, the entry is default initialized // by the exif library based on |tag| static bool createEntry(ExifData* exifData, ExifIfd ifd, int tag) { removeExistingEntry(exifData, ifd, tag); ExifEntry* entry = exif_entry_new(); exif_content_add_entry(exifData->ifd[ifd], entry); exif_entry_initialize(entry, static_cast<ExifTag>(tag)); // Unref entry after changing owner to the ExifData struct exif_entry_unref(entry); return true; }
void exif_content_fix (ExifContent *c) { ExifIfd ifd = exif_content_get_ifd (c); ExifDataType dt; ExifEntry *e; unsigned int i, num; if (!c) return; dt = exif_data_get_data_type (c->parent); /* * First of all, fix all existing entries. */ exif_content_foreach_entry (c, fix_func, NULL); /* * Go through each tag and if it's not recorded, remove it. If one * is removed, exif_content_foreach_entry() will skip the next entry, * so if this happens do the loop again from the beginning to ensure * they're all checked. This could be avoided if we stop relying on * exif_content_foreach_entry but loop intelligently here. */ do { num = c->count; exif_content_foreach_entry (c, remove_not_recorded, NULL); } while (num != c->count); /* * Then check for non-existing mandatory tags and create them if needed */ num = exif_tag_table_count(); for (i = 0; i < num; ++i) { const ExifTag t = exif_tag_table_get_tag (i); if (exif_tag_get_support_level_in_ifd (t, ifd, dt) == EXIF_SUPPORT_LEVEL_MANDATORY) { if (exif_content_get_entry (c, t)) /* This tag already exists */ continue; exif_log (c->priv->log, EXIF_LOG_CODE_DEBUG, "exif-content", "Tag '%s' is mandatory in IFD '%s' and has therefore been added.", exif_tag_get_name_in_ifd (t, ifd), exif_ifd_get_name (ifd)); e = exif_entry_new (); exif_content_add_entry (c, e); exif_entry_initialize (e, t); exif_entry_unref (e); } } }
// Create an entry and place it in |exifData|, the entry contains the raw data // pointed to by |data| of length |size|. static bool createEntry(ExifData* exifData, ExifIfd ifd, int tag, const unsigned char* data, size_t size, ExifFormat format = EXIF_FORMAT_UNDEFINED) { removeExistingEntry(exifData, ifd, tag); ExifEntry* entry = allocateEntry(tag, format, size); memcpy(entry->data, data, size); exif_content_add_entry(exifData->ifd[ifd], entry); // Unref entry after changing owner to the ExifData struct exif_entry_unref(entry); return true; }
// Create an entry with a single EXIF LONG (32-bit value) and place it in // |exifData|. static bool createEntry(ExifData* exifData, ExifIfd ifd, int tag, int value) { removeExistingEntry(exifData, ifd, tag); ExifByteOrder byteOrder = exif_data_get_byte_order(exifData); ExifEntry* entry = allocateEntry(tag, EXIF_FORMAT_LONG, 1); exif_content_add_entry(exifData->ifd[ifd], entry); exif_set_long(entry->data, byteOrder, value); // Unref entry after changing owner to the ExifData struct exif_entry_unref(entry); return true; }
void exif_entry_set_gps_altitude(ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifRational r1) { ExifEntry *pE; ExifByteOrder eO; pE = exif_entry_new (); exif_content_add_entry (pEdata->ifd[eEifd], pE); exif_entry_gps_initialize(pE, eEtag); eO = exif_data_get_byte_order (pE->parent->parent); if (pE->data) { exif_set_rational (pE->data, eO, r1); } else { printf ("ERROR: unallocated e->data Tag %d\n", eEtag); } exif_entry_fix (pE); exif_entry_unref (pE); }
void exif_content_fix (ExifContent *c) { ExifIfd ifd = exif_content_get_ifd (c); ExifDataType dt; ExifTag t; ExifEntry *e; if (!c) return; dt = exif_data_get_data_type (c->parent); /* First of all, fix all existing entries. */ exif_content_foreach_entry (c, fix_func, NULL); /* * Then check for existing tags that are not allowed and for * non-existing mandatory tags. */ for (t = 0; t <= 0xffff; t++) { switch (exif_tag_get_support_level_in_ifd (t, ifd, dt)) { case EXIF_SUPPORT_LEVEL_MANDATORY: if (exif_content_get_entry (c, t)) break; exif_log (c->priv->log, EXIF_LOG_CODE_DEBUG, "exif-content", "Tag '%s' is mandatory in IFD '%s' and has therefore been added.", exif_tag_get_name_in_ifd (t, ifd), exif_ifd_get_name (ifd)); e = exif_entry_new (); exif_content_add_entry (c, e); exif_entry_initialize (e, t); exif_entry_unref (e); break; case EXIF_SUPPORT_LEVEL_NOT_RECORDED: e = exif_content_get_entry (c, t); if (!e) break; exif_log (c->priv->log, EXIF_LOG_CODE_DEBUG, "exif-content", "Tag '%s' is not recoreded in IFD '%s' and has therefore been " "removed.", exif_tag_get_name_in_ifd (t, ifd), exif_ifd_get_name (ifd)); exif_content_remove_entry (c, e); break; case EXIF_SUPPORT_LEVEL_OPTIONAL: default: break; } } }
void exif_entry_set_byte(ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifByte n) { ExifEntry *pE; unsigned char *pData; pE = exif_entry_new (); exif_content_add_entry (pEdata->ifd[eEifd], pE); exif_entry_initialize (pE, eEtag); pData = (unsigned char *) (pE->data); if (pData) { *pData = n; } else { printf ("ERROR: unallocated e->data Tag %d\n", eEtag); } exif_entry_fix (pE); exif_entry_unref (pE); }
void exif_content_free (ExifContent *content) { ExifMem *mem = (content && content->priv) ? content->priv->mem : NULL; unsigned int i; if (!content) return; for (i = 0; i < content->count; i++) exif_entry_unref (content->entries[i]); exif_mem_free (mem, content->entries); if (content->priv) { exif_log_unref (content->priv->log); } exif_mem_free (mem, content->priv); exif_mem_free (mem, content); exif_mem_unref (mem); }
void exif_content_remove_entry (ExifContent *c, ExifEntry *e) { unsigned int i; if (!c || !c->priv || !e || (e->parent != c)) return; /* Search the entry */ for (i = 0; i < c->count; i++) if (c->entries[i] == e) break; if (i == c->count) return; /* Remove the entry */ memmove (&c->entries[i], &c->entries[i + 1], sizeof (ExifEntry*) * (c->count - i - 1)); c->count--; e->parent = NULL; exif_entry_unref (e); c->entries = exif_mem_realloc (c->priv->mem, c->entries, sizeof(ExifEntry*) * c->count); }
void exif_entry_set_string (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, const char *s) { ExifEntry *pE; pE = exif_entry_new (); exif_content_add_entry (pEdata->ifd[eEifd], pE); exif_entry_initialize (pE, eEtag); if (pE->data) free (pE->data); pE->components = strlen (s) + 1; pE->size = sizeof (char) * pE->components; pE->data = (unsigned char *) malloc (pE->size); if (!pE->data) { printf ("Cannot allocate %d bytes.\nTerminating.\n", (int) pE->size); exit (1); } strcpy ((char *) pE->data, (char *) s); exif_entry_fix (pE); exif_entry_unref (pE); }
void exif_entry_set_gps_version(ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifByte r1, ExifByte r2, ExifByte r3, ExifByte r4) { ExifEntry *pE; ExifByteOrder eO; pE = exif_entry_new (); exif_content_add_entry (pEdata->ifd[eEifd], pE); exif_entry_gps_initialize(pE, eEtag); eO = exif_data_get_byte_order (pE->parent->parent); if (pE->data) { pE->data[0] = r1; pE->data[1] = r2; pE->data[2] = r3; pE->data[3] = r4; } else { printf ("ERROR: unallocated e->data Tag %d\n", eEtag); } exif_entry_fix (pE); exif_entry_unref (pE); }
void exif_content_remove_entry (ExifContent * content, ExifEntry * entry) { unsigned int i; if (entry->parent != content) return; for (i = 0; i < content->count; i++) if (content->entries[i] == entry) break; if (i == content->count) return; memmove (&content->entries[i], &content->entries[i + 1], sizeof (ExifEntry) * (content->count - i - 1)); content->count--; entry->parent = NULL; exif_entry_unref (entry); }
/* Write a tag. Update what's there, or make a new one. */ static void write_tag( ExifData *ed, int ifd, ExifTag tag, write_fn fn, void *data ) { ExifEntry *entry; if( (entry = exif_content_get_entry( ed->ifd[ifd], tag )) ) { fn( ed, entry, 0, data ); } else { entry = exif_entry_new(); /* tag must be set before calling exif_content_add_entry. */ entry->tag = tag; exif_content_add_entry( ed->ifd[ifd], entry ); exif_entry_initialize( entry, tag ); exif_entry_unref( entry ); fn( ed, entry, 0, data ); } }
ExifEntry *create_tag_in_content(ExifContent *content, ExifTag tag, size_t len, ExifFormat exifFormat) { void *buf; ExifEntry *entry; size_t size; /* Create a memory allocator to manage this ExifEntry */ ExifMem *mem = exif_mem_new_default(); if (!mem) return NULL; /* Create a new ExifEntry using our allocator */ entry = exif_entry_new_mem (mem); if (entry) { /* Allocate memory to use for holding the tag data */ size = len * exif_format_get_size(exifFormat); buf = exif_mem_alloc(mem, size); if (buf) { /* Fill in the entry */ entry->data = (unsigned char*)buf; entry->size = size; entry->tag = tag; entry->components = len; entry->format = exifFormat; /* Attach the ExifEntry to an IFD */ exif_content_add_entry (content, entry); } exif_entry_unref(entry); } exif_mem_unref(mem); return entry; }
void exif_content_fix (ExifContent *c) { ExifIfd ifd = exif_content_get_ifd (c); ExifDataType dt; ExifEntry *e; unsigned int i, num; if (!c) return; dt = exif_data_get_data_type (c->parent); exif_content_foreach_entry (c, fix_func, NULL); do { num = c->count; exif_content_foreach_entry (c, remove_not_recorded, NULL); } while (num != c->count); num = exif_tag_table_count(); for (i = 0; i < num; ++i) { const ExifTag t = exif_tag_table_get_tag (i); if (exif_tag_get_support_level_in_ifd (t, ifd, dt) == EXIF_SUPPORT_LEVEL_MANDATORY) { if (exif_content_get_entry (c, t)) continue; exif_log (c->priv->log, EXIF_LOG_CODE_DEBUG, "exif-content", "Tag '%s' is mandatory in IFD '%s' and has therefore been added.", exif_tag_get_name_in_ifd (t, ifd), exif_ifd_get_name (ifd)); e = exif_entry_new (); exif_content_add_entry (c, e); exif_entry_initialize (e, t); exif_entry_unref (e); } } }
void exif_content_remove_entry (ExifContent *c, ExifEntry *e) { unsigned int i; ExifEntry **t, *temp; if (!c || !c->priv || !e || (e->parent != c)) return; for (i = 0; i < c->count; i++) if (c->entries[i] == e) break; if (i == c->count) return; temp = c->entries[c->count-1]; if (c->count > 1) { t = exif_mem_realloc (c->priv->mem, c->entries, sizeof(ExifEntry*) * (c->count - 1)); if (!t) { return; } c->entries = t; c->count--; if (i != c->count) { memmove (&t[i], &t[i + 1], sizeof (ExifEntry*) * (c->count - i - 1)); t[c->count-1] = temp; } } else { exif_mem_free (c->priv->mem, c->entries); c->entries = NULL; c->count = 0; } e->parent = NULL; exif_entry_unref (e); }
static bool createEntry(ExifData* exifData, ExifIfd ifd, int tag, const float (&values)[N], float denominator = 1000.0) { removeExistingEntry(exifData, ifd, tag); ExifByteOrder byteOrder = exif_data_get_byte_order(exifData); ExifEntry* entry = allocateEntry(tag, EXIF_FORMAT_RATIONAL, N); exif_content_add_entry(exifData->ifd[ifd], entry); unsigned int rationalSize = exif_format_get_size(EXIF_FORMAT_RATIONAL); for (size_t i = 0; i < N; ++i) { ExifRational rational = { static_cast<uint32_t>(values[i] * denominator), static_cast<uint32_t>(denominator) }; exif_set_rational(&entry->data[i * rationalSize], byteOrder, rational); } // Unref entry after changing owner to the ExifData struct exif_entry_unref(entry); return true; }
void exif_entry_set_undefined (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, exif_buffer * buf) { ExifEntry *pE; pE = exif_entry_new (); exif_content_add_entry (pEdata->ifd[eEifd], pE); exif_entry_initialize (pE, eEtag); if (buf != NULL) { if (pE->data) free (pE->data); pE->components = buf->size; pE->size = buf->size; pE->data = (unsigned char *) malloc (pE->size); if (!pE->data) { printf ("Cannot allocate %d bytes.\nTerminating.\n", (int) pE->size); exit (1); } memcpy ((void *) pE->data, (void *) buf->data, buf->size); } exif_entry_fix (pE); exif_entry_unref (pE); }
int createEXIF(dc1394featureset_t *xFeatures, ExifData ** pParentEd) { ExifEntry *pE; ExifData * pEd; int i = !xFeatures->feature[DC1394_FEATURE_WHITE_BALANCE - DC1394_FEATURE_MIN].auto_active; ExifSRational xR = {xFeatures->feature[DC1394_FEATURE_BRIGHTNESS - DC1394_FEATURE_MIN].value, xFeatures->feature[DC1394_FEATURE_BRIGHTNESS - DC1394_FEATURE_MIN].max};; printf ("Creating EXIF data...\n"); pEd = exif_data_new (); printf ("Adding a Make reference\n"); pE = exif_entry_new (); exif_content_add_entry (pEd->ifd[EXIF_IFD_0], pE); exif_entry_initialize (pE, EXIF_TAG_MAKE); pE->data="AVT"; exif_entry_unref (pE); printf ("Adding a Model reference\n"); pE = exif_entry_new (); exif_content_add_entry (pEd->ifd[EXIF_IFD_0], pE); exif_entry_initialize (pE, EXIF_TAG_MODEL); pE->data="510c"; exif_entry_unref (pE); printf ("Adding a Tag to reference # samples per pixel\n"); pE = exif_entry_new (); exif_content_add_entry (pEd->ifd[EXIF_IFD_0], pE); exif_entry_initialize (pE, EXIF_TAG_SAMPLES_PER_PIXEL); exif_entry_unref (pE); printf ("Adding a White Balance Reference\n"); pE = exif_entry_new (); exif_content_add_entry (pEd->ifd[EXIF_IFD_0], pE); exif_entry_initialize (pE, EXIF_TAG_WHITE_BALANCE); exif_set_short(pE->data, exif_data_get_byte_order (pEd), i); exif_entry_unref (pE); printf ("Adding a Sharpness Reference\n"); pE = exif_entry_new (); exif_content_add_entry (pEd->ifd[EXIF_IFD_0], pE); exif_entry_initialize (pE, EXIF_TAG_SHARPNESS); exif_set_short(pE->data, exif_data_get_byte_order (pEd), 0); exif_entry_unref (pE); printf ("Adding a Brightness reference\n"); pE = exif_entry_new (); exif_content_add_entry (pEd->ifd[EXIF_IFD_0], pE); exif_entry_initialize (pE, EXIF_TAG_BRIGHTNESS_VALUE); exif_set_srational (pE->data, exif_data_get_byte_order (pEd), xR); *pParentEd = pEd; printf("Done!\n"); return 0; }
void add_sgeo_app2(JPEGData *jdata, SGeoTags *sgeo_tags, ExifData *exif) { int number = 2; int i; JPEGSection *section = NULL; JPEGSection temp; int section_for_sgeo_need = 1;// + (int)sgeo_tags->StaticMapCount; int index_insert = 0; int is_insert_map = 0; ExifData *exif_sgeo = NULL; ExifEntry *entry_version_id = NULL;// store SGEO_TAG_VERSIONID for SGEO Map ExifByteOrder order; order = exif_data_get_byte_order(exif); if (jdata == NULL) return; // find and exclude all SGEO in APP2 for (i = 0; i < (int)jdata->count; i++) { section = &jdata->sections[i]; if (section->marker == JPEG_MARKER_APP2) { // detecting SGEO by data if (is_sgeo_app2(section->content._generic.data)) { jpeg_data_exclude_section(jdata, section); i = -1; } } } section = NULL; for (i = 0; i < (int)jdata->count; i++) { section = &jdata->sections[i]; if (section->marker == JPEG_MARKER_APP1) { index_insert = i + 1; break; } } while (section_for_sgeo_need--) { // add section jpeg_data_append_section(jdata); // move section to index_insert i = jdata->count - 1; temp = jdata->sections[i]; for (; i > index_insert; i--) jdata->sections[i] = jdata->sections[i - 1]; jdata->sections[i] = temp; exif_sgeo = exif_data_new_mem (exif->priv->mem); exif_sgeo->priv->order = exif->priv->order; // write exif_sgeo if (is_insert_map) { // add enrty with SGEO version //if (entry_version_id != NULL) // exif_content_add_entry (exif_sgeo->ifd[EXIF_IFD_SGEO], entry_version_id); //write_sgeo_tags_map(exif_sgeo, EXIF_IFD_SGEO, &sgeo_tags->StaticMapData[is_insert_map - 1]); } else { write_sgeo_tags(exif_sgeo, EXIF_IFD_SGEO, sgeo_tags); entry_version_id = exif_content_get_entry(exif_sgeo->ifd[EXIF_IFD_SGEO], (ExifTag)SGEO_TAG_VERSIONID); entry_version_id->priv->ref_count++; } // write data write_sgeo_app2(&jdata->sections[i], exif_sgeo); exif_data_unref(exif_sgeo); exif_sgeo = NULL; entry_version_id->parent = NULL; // increase index index_insert++; is_insert_map++; } exif_entry_unref (entry_version_id); }
/*! Load data for an IFD. * * \param[in,out] data #ExifData * \param[in] ifd IFD to load * \param[in] d pointer to buffer containing raw IFD data * \param[in] ds size of raw data in buffer at \c d * \param[in] offset offset into buffer at \c d at which IFD starts * \param[in] recursion_depth number of times this function has been * recursively called without returning */ static void exif_data_load_data_content (ExifData *data, ExifIfd ifd, const unsigned char *d, unsigned int ds, unsigned int offset, unsigned int recursion_depth) { ExifLong o, thumbnail_offset = 0, thumbnail_length = 0; ExifShort n; ExifEntry *entry; unsigned int i; ExifTag tag; if (!data || !data->priv) return; /* check for valid ExifIfd enum range */ if ((((int)ifd) < 0) || ( ((int)ifd) >= EXIF_IFD_COUNT)) return; if (recursion_depth > 30) { exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifData", "Deep recursion detected!"); return; } /* Read the number of entries */ if ((offset + 2 < offset) || (offset + 2 < 2) || (offset + 2 > ds)) { exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifData", "Tag data past end of buffer (%u > %u)", offset+2, ds); return; } n = exif_get_short (d + offset, data->priv->order); exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "Loading %hu entries...", n); offset += 2; /* Check if we have enough data. */ if (offset + 12 * n > ds) { n = (ds - offset) / 12; exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "Short data; only loading %hu entries...", n); } for (i = 0; i < n; i++) { tag = exif_get_short (d + offset + 12 * i, data->priv->order); switch (tag) { case EXIF_TAG_EXIF_IFD_POINTER: case EXIF_TAG_GPS_INFO_IFD_POINTER: case EXIF_TAG_INTEROPERABILITY_IFD_POINTER: case EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH: case EXIF_TAG_JPEG_INTERCHANGE_FORMAT: o = exif_get_long (d + offset + 12 * i + 8, data->priv->order); /* FIXME: IFD_POINTER tags aren't marked as being in a * specific IFD, so exif_tag_get_name_in_ifd won't work */ exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "Sub-IFD entry 0x%x ('%s') at %u.", tag, exif_tag_get_name(tag), o); switch (tag) { case EXIF_TAG_EXIF_IFD_POINTER: CHECK_REC (EXIF_IFD_EXIF); exif_data_load_data_content (data, EXIF_IFD_EXIF, d, ds, o, recursion_depth + 1); break; case EXIF_TAG_GPS_INFO_IFD_POINTER: CHECK_REC (EXIF_IFD_GPS); exif_data_load_data_content (data, EXIF_IFD_GPS, d, ds, o, recursion_depth + 1); break; case EXIF_TAG_INTEROPERABILITY_IFD_POINTER: CHECK_REC (EXIF_IFD_INTEROPERABILITY); exif_data_load_data_content (data, EXIF_IFD_INTEROPERABILITY, d, ds, o, recursion_depth + 1); break; case EXIF_TAG_JPEG_INTERCHANGE_FORMAT: thumbnail_offset = o; if (thumbnail_offset && thumbnail_length) exif_data_load_data_thumbnail (data, d, ds, thumbnail_offset, thumbnail_length); break; case EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH: thumbnail_length = o; if (thumbnail_offset && thumbnail_length) exif_data_load_data_thumbnail (data, d, ds, thumbnail_offset, thumbnail_length); break; default: return; } break; default: /* * If we don't know the tag, don't fail. It could be that new * versions of the standard have defined additional tags. Note that * 0 is a valid tag in the GPS IFD. */ if (!exif_tag_get_name_in_ifd (tag, ifd)) { /* * Special case: Tag and format 0. That's against specification * (at least up to 2.2). But Photoshop writes it anyways. */ if (!memcmp (d + offset + 12 * i, "\0\0\0\0", 4)) { exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "Skipping empty entry at position %u in '%s'.", i, exif_ifd_get_name (ifd)); break; } exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "Unknown tag 0x%04x (entry %u in '%s'). Please report this tag " "to <*****@*****.**>.", tag, i, exif_ifd_get_name (ifd)); if (data->priv->options & EXIF_DATA_OPTION_IGNORE_UNKNOWN_TAGS) break; } entry = exif_entry_new_mem (data->priv->mem); if (exif_data_load_data_entry (data, entry, d, ds, offset + 12 * i)) exif_content_add_entry (data->ifd[ifd], entry); exif_entry_unref (entry); break; } } }
static void metadatamux_exif_for_each_tag_in_list (const GstTagList * list, const gchar * tag, gpointer user_data) { ExifData *ed = (ExifData *) user_data; ExifTag exif_tag; GType type = G_TYPE_INVALID; ExifEntry *entry = NULL; ExifIfd ifd = EXIF_IFD_COUNT; const ExifByteOrder byte_order = exif_data_get_byte_order (ed); exif_tag = metadatamux_exif_get_exif_from_tag (tag, &type, &ifd); if (!exif_tag) goto done; entry = exif_data_get_entry (ed, exif_tag); if (entry) exif_entry_ref (entry); else { entry = exif_entry_new (); exif_content_add_entry (ed->ifd[ifd], entry); exif_entry_initialize (entry, exif_tag); } if (entry->data == NULL) { if (entry->tag == EXIF_TAG_GPS_ALTITUDE) { entry->format = EXIF_FORMAT_RATIONAL; entry->components = 1; entry->size = exif_format_get_size (entry->format) * entry->components; entry->data = g_malloc (entry->size); } else if (entry->tag == EXIF_TAG_GPS_LATITUDE || entry->tag == EXIF_TAG_GPS_LONGITUDE) { entry->format = EXIF_FORMAT_RATIONAL; entry->components = 3; entry->size = exif_format_get_size (entry->format) * entry->components; entry->data = g_malloc (entry->size); } } if (type == GST_TYPE_FRACTION) { const GValue *gvalue = gst_tag_list_get_value_index (list, tag, 0); gint numerator = gst_value_get_fraction_numerator (gvalue); gint denominator = gst_value_get_fraction_denominator (gvalue); switch (entry->format) { case EXIF_FORMAT_SRATIONAL: { ExifSRational sr = { numerator, denominator }; exif_set_srational (entry->data, byte_order, sr); } break; case EXIF_FORMAT_RATIONAL: { ExifRational r; if (entry->tag == EXIF_TAG_X_RESOLUTION || entry->tag == EXIF_TAG_Y_RESOLUTION) { ExifEntry *unit_entry = NULL; unit_entry = exif_data_get_entry (ed, EXIF_TAG_RESOLUTION_UNIT); if (unit_entry) { ExifShort vsh = exif_get_short (unit_entry->data, byte_order); if (vsh != 2) /* inches */ exif_set_short (unit_entry->data, byte_order, 2); } } r.numerator = numerator; r.denominator = denominator; if (numerator < 0) r.numerator = -numerator; if (denominator < 0) r.denominator = -denominator; exif_set_rational (entry->data, byte_order, r); } break; default: break; } } else if (type == GST_TYPE_BUFFER) { const GValue *val = NULL; GstBuffer *buf; val = gst_tag_list_get_value_index (list, tag, 0); buf = gst_value_get_buffer (val); entry->components = GST_BUFFER_SIZE (buf); entry->size = GST_BUFFER_SIZE (buf); entry->data = g_malloc (entry->size); memcpy (entry->data, GST_BUFFER_DATA (buf), entry->size); } else { switch (type) { case G_TYPE_STRING: { gchar *value = NULL; if (gst_tag_list_get_string (list, tag, &value)) { if (entry->tag == EXIF_TAG_DATE_TIME_DIGITIZED || entry->tag == EXIF_TAG_DATE_TIME || entry->tag == EXIF_TAG_DATE_TIME_ORIGINAL) { GString *datetime = g_string_new_len (value, 20); /* enough memory to hold "YYYY:MM:DD HH:MM:SS" */ if (metadatamux_exif_convert_from_datetime (datetime)) { } else { GST_ERROR ("Unexpected date & time format for %s", tag); } g_free (value); value = datetime->str; g_string_free (datetime, FALSE); } else if (value) { entry->components = strlen (value) + 1; entry->size = exif_format_get_size (entry->format) * entry->components; entry->data = (guint8 *) value; value = NULL; } } } break; case G_TYPE_UINT: case G_TYPE_INT: { gint value; ExifShort v_short; if (G_TYPE_UINT == type) { gst_tag_list_get_uint (list, tag, (guint *) & value); } else { gst_tag_list_get_int (list, tag, &value); } switch (entry->format) { case EXIF_FORMAT_SHORT: if (entry->tag == EXIF_TAG_CONTRAST || entry->tag == EXIF_TAG_SATURATION) { if (value < -33) value = 1; /* low */ else if (value < 34) value = 0; /* normal */ else value = 2; /* high */ } v_short = value; exif_set_short (entry->data, byte_order, v_short); break; case EXIF_FORMAT_LONG: exif_set_long (entry->data, byte_order, value); break; default: break; } } break; case G_TYPE_DOUBLE: { gdouble value; gst_tag_list_get_double (list, tag, &value); if (entry->tag == EXIF_TAG_GPS_LATITUDE || entry->tag == EXIF_TAG_GPS_LONGITUDE) { ExifRational *rt = (ExifRational *) entry->data; gdouble v = fabs (value); ExifEntry *ref_entry = NULL; char ref; const ExifTag ref_tag = entry->tag == EXIF_TAG_GPS_LATITUDE ? EXIF_TAG_GPS_LATITUDE_REF : EXIF_TAG_GPS_LONGITUDE_REF; /* DDD - degrees */ rt->numerator = (gulong) v; rt->denominator = 1; GST_DEBUG ("deg: %lf : %lu / %lu", v, (gulong) rt->numerator, (gulong) rt->denominator); v -= rt->numerator; rt++; /* MM - minutes */ rt->numerator = (gulong) (v * 60.0); rt->denominator = 1; GST_DEBUG ("min: %lf : %lu / %lu", v, (gulong) rt->numerator, (gulong) rt->denominator); v -= ((gdouble) rt->numerator / 60.0); rt++; /* SS - seconds */ rt->numerator = (gulong) (0.5 + v * 3600.0); rt->denominator = 1; GST_DEBUG ("sec: %lf : %lu / %lu", v, (gulong) rt->numerator, (gulong) rt->denominator); if (entry->tag == EXIF_TAG_GPS_LONGITUDE) { GST_DEBUG ("longitude : %lf", value); ref = (value < 0.0) ? 'W' : 'E'; } else { GST_DEBUG ("latitude : %lf", value); ref = (value < 0.0) ? 'S' : 'N'; } ref_entry = exif_data_get_entry (ed, ref_tag); if (ref_entry) { exif_entry_ref (ref_entry); } else { ref_entry = exif_entry_new (); exif_content_add_entry (ed->ifd[EXIF_IFD_GPS], ref_entry); exif_entry_initialize (ref_entry, ref_tag); } if (ref_entry->data == NULL) { ref_entry->format = EXIF_FORMAT_ASCII; ref_entry->components = 2; ref_entry->size = 2; ref_entry->data = g_malloc (2); } ref_entry->data[0] = ref; ref_entry->data[1] = 0; exif_entry_unref (ref_entry); } else if (entry->tag == EXIF_TAG_GPS_ALTITUDE) { ExifEntry *ref_entry = NULL; ExifRational *rt = (ExifRational *) entry->data; rt->numerator = (gulong) fabs (10.0 * value); rt->denominator = 10; GST_DEBUG ("altitude : %lf", value); ref_entry = exif_data_get_entry (ed, EXIF_TAG_GPS_ALTITUDE_REF); if (ref_entry) { exif_entry_ref (ref_entry); } else { ref_entry = exif_entry_new (); exif_content_add_entry (ed->ifd[EXIF_IFD_GPS], ref_entry); exif_entry_initialize (ref_entry, EXIF_TAG_GPS_ALTITUDE_REF); } if (ref_entry->data == NULL) { ref_entry->format = EXIF_FORMAT_BYTE; ref_entry->components = 1; ref_entry->size = 1; ref_entry->data = g_malloc (1); } if (value > 0.0) { ref_entry->data[0] = 0; } else { ref_entry->data[0] = 1; } exif_entry_unref (ref_entry); } } break; default: break; } } done: if (entry) exif_entry_unref (entry); }