void metadatamux_exif_create_chunk_from_tag_list (guint8 ** buf, guint32 * size, const GstTagList * taglist, const MetaExifWriteOptions * opts) { ExifData *ed = NULL; GstBuffer *exif_chunk = NULL; const GValue *val = NULL; if (!(buf && size)) goto done; g_free (*buf); *buf = NULL; *size = 0; val = gst_tag_list_get_value_index (taglist, GST_TAG_EXIF, 0); if (val) { exif_chunk = gst_value_get_buffer (val); if (exif_chunk) { ed = exif_data_new_from_data (GST_BUFFER_DATA (exif_chunk), GST_BUFFER_SIZE (exif_chunk)); } } if (!ed) { ed = exif_data_new (); GST_DEBUG ("setting byteorder %d", opts->byteorder); switch (opts->byteorder) { case GST_META_EXIF_BYTE_ORDER_MOTOROLA: exif_data_set_byte_order (ed, EXIF_BYTE_ORDER_MOTOROLA); break; case GST_META_EXIF_BYTE_ORDER_INTEL: exif_data_set_byte_order (ed, EXIF_BYTE_ORDER_INTEL); break; default: break; } exif_data_set_data_type (ed, EXIF_DATA_TYPE_COMPRESSED); exif_data_fix (ed); } gst_tag_list_foreach (taglist, metadatamux_exif_for_each_tag_in_list, ed); exif_data_save_data (ed, buf, size); done: if (ed) exif_data_unref (ed); return; }
ExifData * exif_data_new_mem (ExifMem *mem) { ExifData *data; unsigned int i; if (!mem) return NULL; data = exif_mem_alloc (mem, sizeof (ExifData)); if (!data) return (NULL); data->priv = exif_mem_alloc (mem, sizeof (ExifDataPrivate)); if (!data->priv) { exif_mem_free (mem, data); return (NULL); } data->priv->ref_count = 1; data->priv->mem = mem; exif_mem_ref (mem); for (i = 0; i < EXIF_IFD_COUNT; i++) { data->ifd[i] = exif_content_new_mem (data->priv->mem); if (!data->ifd[i]) { exif_data_free (data); return (NULL); } data->ifd[i]->parent = data; } /* Default options */ #ifndef NO_VERBOSE_TAG_STRINGS /* * When the tag list is compiled away, setting this option prevents * any tags from being loaded */ exif_data_set_option (data, EXIF_DATA_OPTION_IGNORE_UNKNOWN_TAGS); #endif exif_data_set_option (data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); /* Default data type: none */ exif_data_set_data_type (data, EXIF_DATA_TYPE_COUNT); return (data); }
/* Examine the metadata tags on the image and update the EXIF block. */ int vips__exif_update( VipsImage *image ) { unsigned char *data; size_t length; unsigned int idl; ExifData *ed; /* Either parse from the embedded EXIF, or if there's none, make * some fresh EXIF we can write the resolution to. */ if( vips_image_get_typeof( image, VIPS_META_EXIF_NAME ) ) { if( vips_image_get_blob( image, VIPS_META_EXIF_NAME, (void *) &data, &length ) ) return( -1 ); if( !(ed = exif_data_new_from_data( data, length )) ) return( -1 ); } else { ed = exif_data_new(); exif_data_set_option( ed, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION ); exif_data_set_data_type( ed, EXIF_DATA_TYPE_COMPRESSED ); exif_data_set_byte_order( ed, EXIF_BYTE_ORDER_INTEL ); /* Create the mandatory EXIF fields with default data. */ exif_data_fix( ed ); } /* Update EXIF tags from the image metadata. */ vips_exif_update( ed, image ); /* Update EXIF resolution from the vips image header. */ if( vips_exif_resolution_from_image( ed, image ) ) { exif_data_free( ed ); return( -1 ); } /* Update EXIF image dimensions from the vips image header. */ if( vips_exif_set_dimensions( ed, image ) ) { exif_data_free( ed ); return( -1 ); } /* Update EXIF orientation from the vips image header. */ if( vips_exif_set_orientation( ed, image ) ) { exif_data_free( ed ); return( -1 ); } /* Update the thumbnail. */ if( vips_exif_set_thumbnail( ed, image ) ) { exif_data_free( ed ); return( -1 ); } /* Reserialise and write. exif_data_save_data() returns an int for some * reason. */ exif_data_save_data( ed, &data, &idl ); if( !idl ) { vips_error( "exif", "%s", _( "error saving EXIF" ) ); exif_data_free( ed ); return( -1 ); } length = idl; #ifdef DEBUG printf( "vips__exif_update: generated %zd bytes of EXIF\n", length ); #endif /*DEBUG*/ vips_image_set_blob( image, VIPS_META_EXIF_NAME, (VipsCallbackFn) vips_free, data, length ); exif_data_free( ed ); return( 0 ); }
ExifData* createExifData(const CameraParameters& params) { ExifData* exifData = exif_data_new(); exif_data_set_option(exifData, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); exif_data_set_data_type(exifData, EXIF_DATA_TYPE_COMPRESSED); exif_data_set_byte_order(exifData, EXIF_BYTE_ORDER_INTEL); // Create mandatory exif fields and set their default values exif_data_fix(exifData); float triplet[3]; float floatValue = 0.0f; const char* stringValue; int64_t degrees; // Datetime, creating and initializing a datetime tag will automatically // set the current date and time in the tag so just do that. createEntry(exifData, EXIF_IFD_0, EXIF_TAG_DATE_TIME); // Make and model createEntry(exifData, EXIF_IFD_0, EXIF_TAG_MAKE, "Emulator-Goldfish"); createEntry(exifData, EXIF_IFD_0, EXIF_TAG_MODEL, "Emulator-Goldfish"); // Picture size int width = -1, height = -1; params.getPictureSize(&width, &height); if (width >= 0 && height >= 0) { createEntry(exifData, EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, width); createEntry(exifData, EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, height); } // Orientation if (getCameraParam(params, CameraParameters::KEY_ROTATION, °rees)) { // Exif orientation values, please refer to // http://www.exif.org/Exif2-2.PDF, Section 4.6.4-A-Orientation // Or these websites: // http://sylvana.net/jpegcrop/exif_orientation.html // http://www.impulseadventure.com/photo/exif-orientation.html enum { EXIF_ROTATE_CAMERA_CW0 = 1, EXIF_ROTATE_CAMERA_CW90 = 6, EXIF_ROTATE_CAMERA_CW180 = 3, EXIF_ROTATE_CAMERA_CW270 = 8, }; uint16_t exifOrien = 1; switch (degrees) { case 0: exifOrien = EXIF_ROTATE_CAMERA_CW0; break; case 90: exifOrien = EXIF_ROTATE_CAMERA_CW90; break; case 180: exifOrien = EXIF_ROTATE_CAMERA_CW180; break; case 270: exifOrien = EXIF_ROTATE_CAMERA_CW270; break; } createEntry(exifData, EXIF_IFD_0, EXIF_TAG_ORIENTATION, exifOrien); } // Focal length if (getCameraParam(params, CameraParameters::KEY_FOCAL_LENGTH, &floatValue)) { createEntry(exifData, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, floatValue); } // GPS latitude and reference, reference indicates sign, store unsigned if (getCameraParam(params, CameraParameters::KEY_GPS_LATITUDE, &floatValue)) { convertGpsCoordinate(floatValue, &triplet); createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE, triplet); const char* ref = floatValue < 0.0f ? "S" : "N"; createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF, ref); } // GPS longitude and reference, reference indicates sign, store unsigned if (getCameraParam(params, CameraParameters::KEY_GPS_LONGITUDE, &floatValue)) { convertGpsCoordinate(floatValue, &triplet); createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE, triplet); const char* ref = floatValue < 0.0f ? "W" : "E"; createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF, ref); } // GPS altitude and reference, reference indicates sign, store unsigned if (getCameraParam(params, CameraParameters::KEY_GPS_ALTITUDE, &floatValue)) { createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_ALTITUDE, static_cast<float>(fabs(floatValue))); // 1 indicated below sea level, 0 indicates above sea level uint8_t ref = floatValue < 0.0f ? 1 : 0; createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_ALTITUDE_REF, ref); } // GPS timestamp and datestamp int64_t timestamp = 0; if (getCameraParam(params, CameraParameters::KEY_GPS_TIMESTAMP, ×tamp)) { std::string date; if (convertTimestampToTimeAndDate(timestamp, &triplet, &date)) { createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_TIME_STAMP, triplet, 1.0f); createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_DATE_STAMP, date.c_str()); } } // GPS processing method if (getCameraParam(params, CameraParameters::KEY_GPS_PROCESSING_METHOD, &stringValue)) { std::vector<unsigned char> data; // Because this is a tag with an undefined format it has to be prefixed // with the encoding type. Insert an ASCII prefix first, then the // actual string. Undefined tags do not have to be null terminated. data.insert(data.end(), std::begin(kAsciiPrefix), std::end(kAsciiPrefix)); data.insert(data.end(), stringValue, stringValue + strlen(stringValue)); createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_PROCESSING_METHOD, &data[0], data.size()); } return exifData; }
GstTagList * gst_droidcamsrc_exif_tags_from_jpeg_data (void *data, size_t size) { GstTagList *tags = NULL; ExifMem *mem = exif_mem_new (g_malloc0, g_realloc, g_free); ExifData *exif = exif_data_new_mem (mem); unsigned char *exif_data = NULL; void *_exif_data = NULL; unsigned int exif_data_size = 0; GstBuffer *buffer; ExifEntry *iso; int x, i; exif_data_load_data (exif, data, size); exif_data_set_data_type (exif, EXIF_DATA_TYPE_COMPRESSED); exif_data_save_data (exif, &exif_data, &exif_data_size); if (!exif_data_size) { goto out; } if (exif_data_size <= 6) { goto out; } /* dump the data. based on libexif code */ for (x = 0; x < EXIF_IFD_COUNT; x++) { if (exif->ifd[x] && exif->ifd[x]->count) { for (i = 0; i < exif->ifd[x]->count; i++) { char val[1024]; ExifEntry *e = exif->ifd[x]->entries[i]; GST_LOG ("Exif IFD: %s. Tag 0x%x (%s) = %s", exif_ifd_get_name (x), e->tag, exif_tag_get_name_in_ifd (e->tag, exif_entry_get_ifd (e)), exif_entry_get_value (e, val, sizeof (val))); } } } _exif_data = exif_data; exif_data += 6; exif_data_size -= 6; buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, exif_data, exif_data_size, 0, exif_data_size, NULL, NULL); tags = gst_tag_list_from_exif_buffer_with_tiff_header (buffer); gst_buffer_unref (buffer); /* We don't want these tags */ gst_tag_list_remove_tag (tags, GST_TAG_DEVICE_MANUFACTURER); gst_tag_list_remove_tag (tags, GST_TAG_DEVICE_MODEL); gst_tag_list_remove_tag (tags, GST_TAG_APPLICATION_NAME); gst_tag_list_remove_tag (tags, GST_TAG_DATE_TIME); /* we have a mess with ISO so we will just behave as N9 */ iso = exif_content_get_entry (exif->ifd[EXIF_IFD_EXIF], EXIF_TAG_ISO_SPEED_RATINGS); if (iso) { #ifdef __arm__ guint16 val = exif_get_short (iso->data, EXIF_BYTE_ORDER_MOTOROLA); #else guint16 val = exif_get_short (iso->data, EXIF_BYTE_ORDER_INTEL); #endif gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CAPTURING_ISO_SPEED, val, NULL); } /* TODO: the following are being dropped * * 0x213 EXIF_TAG_YCBCR_POSITIONING * 0x9004 EXIF_TAG_DATE_TIME_DIGITIZED * 0x9101 EXIF_TAG_COMPONENTS_CONFIGURATION * 0xa001 EXIF_TAG_COLOR_SPACE * 0xa002 EXIF_TAG_PIXEL_X_DIMENSION * 0xa003 EXIF_TAG_PIXEL_Y_DIMENSION * 0xa005 EXIF_TAG_INTEROPERABILITY_IFD_POINTER * thumbnail. * 0x100 EXIF_TAG_IMAGE_WIDTH * 0x101 EXIF_TAG_IMAGE_LENGTH * 0x9203 EXIF_TAG_BRIGHTNESS_VALUE * 0x9205 EXIF_TAG_MAX_APERTURE_VALUE * 0x9206 EXIF_TAG_SUBJECT_DISTANCE * 0x9208 EXIF_TAG_LIGHT_SOURCE * 0x9286 EXIF_TAG_USER_COMMENT */ out: if (_exif_data) { exif_mem_free (mem, _exif_data); } if (exif) { exif_data_free (exif); } exif_mem_unref (mem); return tags; }
static int write_exif( Write *write ) { #ifdef HAVE_EXIF unsigned char *data; size_t data_length; unsigned int idl; ExifData *ed; /* Either parse from the embedded EXIF, or if there's none, make * some fresh EXIF we can write the resolution to. */ if( vips_image_get_typeof( write->in, VIPS_META_EXIF_NAME ) ) { if( vips_image_get_blob( write->in, VIPS_META_EXIF_NAME, (void *) &data, &data_length ) ) return( -1 ); if( !(ed = exif_data_new_from_data( data, data_length )) ) return( -1 ); } else { ed = exif_data_new(); exif_data_set_option( ed, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION ); exif_data_set_data_type( ed, EXIF_DATA_TYPE_COMPRESSED ); exif_data_set_byte_order( ed, EXIF_BYTE_ORDER_INTEL ); /* Create the mandatory EXIF fields with default data. */ exif_data_fix( ed ); } /* Update EXIF tags from the image metadata. */ vips_exif_update( ed, write->in ); /* Update EXIF resolution from the vips image header. */ if( vips__set_exif_resolution( ed, write->in ) ) { exif_data_free( ed ); return( -1 ); } /* Update EXIF image dimensions from the vips image header. */ if( set_exif_dimensions( ed, write->in ) ) { exif_data_free( ed ); return( -1 ); } /* Update EXIF orientation from the vips image header. */ if( set_exif_orientation( ed, write->in ) ) { exif_data_free( ed ); return( -1 ); } /* Reserialise and write. exif_data_save_data() returns an int for some * reason. */ exif_data_save_data( ed, &data, &idl ); if( !idl ) { vips_error( "VipsJpeg", "%s", _( "error saving EXIF" ) ); exif_data_free( ed ); return( -1 ); } data_length = idl; #ifdef DEBUG printf( "write_exif: attaching %zd bytes of EXIF\n", data_length ); #endif /*DEBUG*/ exif_data_free( ed ); jpeg_write_marker( &write->cinfo, JPEG_APP0 + 1, data, data_length ); free( data ); #else /*!HAVE_EXIF*/ /* No libexif ... just copy the embedded EXIF over. */ if( write_blob( write, VIPS_META_EXIF_NAME, JPEG_APP0 + 1 ) ) return( -1 ); #endif /*!HAVE_EXIF*/ return( 0 ); }