static void vips_exif_update( ExifData *ed, VipsImage *image ) { VipsExifRemove ve; VIPS_DEBUG_MSG( "vips_exif_update: \n" ); /* If this exif came from the image (rather than being an exif block we * have made afresh), then any fields which are in the block but not on * the image must have been deliberately removed. Remove them from the * block as well. * * If there are any string-valued fields (eg. comment etc.) which * exist as libvips metadata tags, we must also remove those from the * exif block. * * libexif does not allow you to change string lengths, you must make * new tags, so we have to remove ready to re-add. */ if( vips_image_get_typeof( image, VIPS_META_EXIF_NAME ) ) { ve.image = image; ve.ed = ed; exif_data_foreach_content( ed, (ExifDataForeachContentFunc) vips_exif_exif_content, &ve ); } /* Walk the image and add any exif- that's set in image metadata. */ vips_image_map( image, vips_exif_image_field, ed ); }
void eog_exif_details_update (EogExifDetails *exif_details, ExifData *data) { g_return_if_fail (EOG_IS_EXIF_DETAILS (exif_details)); eog_exif_details_reset (exif_details); if (data) { exif_data_foreach_content (data, exif_content_cb, exif_details); } }
static void show_values( ExifData *data ) { ExifByteOrder order; int ifd; order = exif_data_get_byte_order( data ); printf( "EXIF tags in '%s' byte order\n", exif_byte_order_get_name( order ) ); printf( "Title|Value|Format|Size\n" ); ifd = 0; exif_data_foreach_content( data, show_ifd, &ifd ); if( data->size ) printf( "contains thumbnail of %d bytes\n", data->size ); }
void show_values( ExifData *data ) { ExifByteOrder order; order = exif_data_get_byte_order( data ); printf( "EXIF tags in '%s' byte order\n", exif_byte_order_get_name( order ) ); printf( "%-20.20s", "Tag" ); printf( "|" ); printf( "%-58.58s", "Value" ); printf( "\n" ); exif_data_foreach_content( data, show_ifd, NULL ); if( data->size ) printf( "contains thumbnail of %d bytes\n", data->size ); }
static int parse_exif( VipsImage *im, void *data, int data_length ) { #ifdef HAVE_EXIF { ExifData *ed; VipsExif ve; if( !(ed = exif_data_new_from_data( data, data_length )) ) return( -1 ); #ifdef DEBUG_VERBOSE show_tags( ed ); show_values( ed ); #endif /*DEBUG_VERBOSE*/ /* Attach informational fields for what we find. FIXME ... better to have this in the UI layer? Or we could attach non-human-readable tags here (int, double etc) and then move the human stuff to the UI layer? */ ve.image = im; ve.ed = ed; exif_data_foreach_content( ed, (ExifDataForeachContentFunc) attach_exif_content, &ve ); /* Look for resolution fields and use them to set the VIPS * xres/yres fields. */ res_from_exif( im, ed ); attach_thumbnail( im, ed ); exif_data_free( ed ); } #endif /*HAVE_EXIF*/ return( 0 ); }
static char * exifdata_get_tag_value_utf8 (ExifData *data, ExifTag tag) { struct ExifAttribute attribute; char *utf8_value; attribute.tag = tag; attribute.value = NULL; attribute.found = FALSE; exif_data_foreach_content (data, exif_content_callback, &attribute); if (attribute.found) { utf8_value = exif_string_to_utf8 (attribute.value); g_free (attribute.value); } else { utf8_value = NULL; } return utf8_value; }
static void vips_exif_update( ExifData *ed, VipsImage *image ) { VipsExif ve; VIPS_DEBUG_MSG( "vips_exif_update: \n" ); /* Walk the image and update any stuff that's been changed in image * metadata. */ vips_image_map( image, vips_exif_image_field, ed ); /* Walk the exif and look for any fields which are NOT in image * metadata. They must have been removed ... remove them from exif as * well. */ ve.image = image; ve.ed = ed; exif_data_foreach_content( ed, (ExifDataForeachContentFunc) vips_exif_exif_content, &ve ); }
void metadataparse_exif_tag_list_add (GstTagList * taglist, GstTagMergeMode mode, GstAdapter * adapter, MetadataTagMapping mapping) { const guint8 *buf; guint32 size; ExifData *exif = NULL; MEUserData user_data = { taglist, mode, 2, -1, 'k', 'k' }; if (adapter == NULL || (size = gst_adapter_available (adapter)) == 0) { goto done; } /* add chunk tag */ if (mapping & METADATA_TAG_MAP_WHOLECHUNK) metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_EXIF, adapter); if (!(mapping & METADATA_TAG_MAP_INDIVIDUALS)) goto done; buf = gst_adapter_peek (adapter, size); exif = exif_data_new_from_data (buf, size); if (exif == NULL) { goto done; } exif_data_foreach_content (exif, metadataparse_exif_data_foreach_content_func, (void *) &user_data); done: if (exif) exif_data_unref (exif); return; }
/* Scan the exif block on the image, if any, and make a set of vips metadata * tags for what we find. */ int vips__exif_parse( VipsImage *image ) { void *data; size_t length; ExifData *ed; VipsExifParams params; const char *str; if( !vips_image_get_typeof( image, VIPS_META_EXIF_NAME ) ) return( 0 ); if( vips_image_get_blob( image, VIPS_META_EXIF_NAME, &data, &length ) ) return( -1 ); if( !(ed = vips_exif_load_data_without_fix( data, length )) ) return( -1 ); #ifdef DEBUG_VERBOSE show_tags( ed ); show_values( ed ); #endif /*DEBUG_VERBOSE*/ /* Look for resolution fields and use them to set the VIPS xres/yres * fields. * * If the fields are missing, set them from the image, which will have * previously had them set from something like JFIF. */ if( vips_image_resolution_from_exif( image, ed ) && vips_exif_resolution_from_image( ed, image ) ) { exif_data_free( ed ); return( -1 ); } /* Make sure all required fields are there before we attach the vips * metadata. */ exif_data_fix( ed ); /* Attach informational fields for what we find. */ params.image = image; params.ed = ed; exif_data_foreach_content( ed, (ExifDataForeachContentFunc) vips_exif_get_content, ¶ms ); vips_exif_get_thumbnail( image, ed ); exif_data_free( ed ); /* Orientation handling. ifd0 has the Orientation tag for the main * image. */ if( vips_image_get_typeof( image, "exif-ifd0-Orientation" ) != 0 && !vips_image_get_string( image, "exif-ifd0-Orientation", &str ) ) { int orientation; orientation = atoi( str ); orientation = VIPS_CLIP( 1, orientation, 8 ); vips_image_set_int( image, VIPS_META_ORIENTATION, orientation ); } return( 0 ); }
static int read_exif( IMAGE *im, void *data, int data_length ) { char *data_copy; /* Horrifyingly, some JPEGs have several APP1 sections. We must only * use the first one that starts "Exif.." */ if( ((char *) data)[0] != 'E' || ((char *) data)[1] != 'x' || ((char *) data)[2] != 'i' || ((char *) data)[3] != 'f' ) return( 0 ); if( im_header_get_typeof( im, IM_META_EXIF_NAME ) ) return( 0 ); /* Always attach a copy of the unparsed exif data. */ if( !(data_copy = im_malloc( NULL, data_length )) ) return( -1 ); memcpy( data_copy, data, data_length ); if( im_meta_set_blob( im, IM_META_EXIF_NAME, (im_callback_fn) im_free, data_copy, data_length ) ) { im_free( data_copy ); return( -1 ); } #ifdef HAVE_EXIF { ExifData *ed; if( !(ed = exif_data_new_from_data( data, data_length )) ) return( -1 ); if( ed->size > 0 ) { #ifdef DEBUG_VERBOSE show_tags( ed ); show_values( ed ); #endif /*DEBUG_VERBOSE*/ /* Attach informational fields for what we find. FIXME ... better to have this in the UI layer? Or we could attach non-human-readable tags here (int, double etc) and then move the human stuff to the UI layer? */ exif_data_foreach_content( ed, (ExifDataForeachContentFunc) attach_exif_content, im ); /* Look for resolution fields and use them to set the VIPS * xres/yres fields. */ set_vips_resolution( im, ed ); attach_thumbnail( im, ed ); } exif_data_free( ed ); } #endif /*HAVE_EXIF*/ return( 0 ); }
static int Difds (lua_State *L) { /** data:ifds() */ ExifData *data = checkdata(L); lua_newtable(L); exif_data_foreach_content(data, contentfunc, (void *)L); return 1; }
int image_jpeg_read_header(MediaScanImage *i, MediaScanResult *r) { int ret = 1; int x; JPEGData *j = malloc(sizeof(JPEGData)); i->_jpeg = (void *)j; LOG_MEM("new JPEGData @ %p\n", i->_jpeg); j->cinfo = malloc(sizeof(struct jpeg_decompress_struct)); j->jpeg_error_pub = malloc(sizeof(struct jpeg_error_mgr)); LOG_MEM("new JPEG cinfo @ %p\n", j->cinfo); LOG_MEM("new JPEG error_pub @ %p\n", j->jpeg_error_pub); j->cinfo->err = jpeg_std_error(j->jpeg_error_pub); j->jpeg_error_pub->error_exit = libjpeg_error_handler; j->jpeg_error_pub->output_message = libjpeg_output_message; if (setjmp(setjmp_buffer)) { image_jpeg_destroy(i); return 0; } // Save filename in case any warnings/errors occur strncpy(Filename, r->path, FILENAME_LEN); if (strlen(r->path) > FILENAME_LEN) Filename[FILENAME_LEN] = 0; jpeg_create_decompress(j->cinfo); // Init custom source manager to read from existing buffer image_jpeg_buf_src(i, r); // Save APP1 marker for EXIF jpeg_save_markers(j->cinfo, 0xE1, 1024 * 64); jpeg_read_header(j->cinfo, TRUE); i->width = j->cinfo->image_width; i->height = j->cinfo->image_height; i->channels = j->cinfo->num_components; r->mime_type = MIME_IMAGE_JPEG; // Match with DLNA profile for (x = 0; jpeg_profiles_mapping[x].profile; x++) { if (i->width <= jpeg_profiles_mapping[x].max_width && i->height <= jpeg_profiles_mapping[x].max_height) { r->dlna_profile = jpeg_profiles_mapping[x].profile->id; break; } } // Process Exif tag if (j->cinfo->marker_list != NULL) { jpeg_saved_marker_ptr marker = j->cinfo->marker_list; while (marker != NULL) { if (marker->marker == 0xE1 && marker->data[0] == 'E' && marker->data[1] == 'x' && marker->data[2] == 'i' && marker->data[3] == 'f') { ExifData *exif; result_create_tag(r, "Exif"); LOG_DEBUG("Parsing EXIF tag of size %d\n", marker->data_length); exif = exif_data_new_from_data(marker->data, marker->data_length); LOG_MEM("new EXIF data @ %p\n", exif); if (exif != NULL) { exif_data_foreach_content(exif, parse_exif_ifd, (void *)r); LOG_MEM("destroy EXIF data @ %p\n", exif); exif_data_free(exif); } break; } marker = marker->next; } } return ret; }
static int analyzer_jpeg_pload_analyze(struct analyzer *analyzer, struct analyzer_pload_buffer *pload, void *buffer, size_t buff_len) { struct analyzer_jpeg_pload_priv *priv = analyzer_pload_buffer_get_priv(pload); if (!priv) { priv = malloc(sizeof(struct analyzer_jpeg_pload_priv)); if (!priv) { pom_oom(sizeof(struct analyzer_jpeg_pload_priv)); return POM_ERR; } memset(priv, 0, sizeof(struct analyzer_jpeg_pload_priv)); priv->pload_buff = buffer; priv->pload_buff_len = buff_len; // Setup error handler struct jpeg_error_mgr *jerr = malloc(sizeof(struct jpeg_error_mgr)); if (!jerr) { free(priv); pom_oom(sizeof(struct jpeg_error_mgr)); return POM_ERR; } memset(jerr, 0, sizeof(struct jpeg_error_mgr)); priv->cinfo.err = jpeg_std_error(jerr); priv->cinfo.err->error_exit = analyzer_jpeg_lib_error_exit; // Allocate the decompressor jpeg_create_decompress(&priv->cinfo); priv->cinfo.client_data = priv; #ifdef HAVE_LIBEXIF // Save APP1 jpeg_save_markers(&priv->cinfo, JPEG_APP0 + 1, 0xFFFF); #endif // Allocate the source struct jpeg_source_mgr *src = malloc(sizeof(struct jpeg_source_mgr)); if (!src) { free(priv->cinfo.err); pom_oom(sizeof(struct jpeg_source_mgr)); jpeg_destroy_decompress(&priv->cinfo); free(priv); return POM_ERR; } memset(src, 0, sizeof(struct jpeg_source_mgr)); src->init_source = analyzer_jpeg_lib_init_source; src->fill_input_buffer = analyzer_jpeg_lib_fill_input_buffer; src->skip_input_data = analyzer_jpeg_lib_skip_input_data; src->resync_to_restart = jpeg_resync_to_restart; src->term_source = analyzer_jpeg_lib_term_source; priv->cinfo.src = src; analyzer_pload_buffer_set_priv(pload, priv); } else { priv->pload_buff = buffer; priv->pload_buff_len = buff_len; } if (priv->jpeg_lib_pos >= buff_len) // Nothing more to process return POM_OK; int res = POM_OK; if (!setjmp(priv->jmp_buff)) { if (priv->jpeg_lib_pos) { // It's not garanteed that buffer points to the // same memory area after each call, so we reset it here priv->cinfo.src->next_input_byte = buffer + priv->jpeg_lib_pos; } if (jpeg_read_header(&priv->cinfo, TRUE) == JPEG_SUSPENDED) return POM_OK; // Headers are incomplete struct data *data = analyzer_pload_buffer_get_data(pload); PTYPE_UINT16_SETVAL(data[analyzer_jpeg_pload_width].value, priv->cinfo.image_width); data_set(data[analyzer_jpeg_pload_width]); PTYPE_UINT16_SETVAL(data[analyzer_jpeg_pload_height].value, priv->cinfo.image_height); data_set(data[analyzer_jpeg_pload_height]); debug_jpeg("JPEG read header returned %u, image is %ux%u", res, priv->cinfo.image_width, priv->cinfo.image_height); #ifdef HAVE_LIBEXIF // Parse the exif data jpeg_saved_marker_ptr marker; for (marker = priv->cinfo.marker_list; marker && marker->marker != JPEG_APP0 + 1; marker = marker->next); if (marker) { ExifData *exif_data = exif_data_new_from_data(marker->data, marker->data_length); if (!exif_data) { pomlog(POMLOG_DEBUG "Unable to parse EXIF data"); } exif_data_foreach_content(exif_data, analyzer_jpeg_exif_content_process, pload); exif_data_free(exif_data); } #endif analyzer_pload_buffer_set_state(pload, analyzer_pload_buffer_state_analyzed); } else { pomlog(POMLOG_DEBUG "Error while parsing JPEG headers"); res = POM_ERR; } free(priv->cinfo.err); free(priv->cinfo.src); jpeg_destroy_decompress(&priv->cinfo); free(priv); analyzer_pload_buffer_set_priv(pload, NULL); return res; }