void imFileFormatJPEG::iWriteExifAttrib(imAttribTable* attrib_table) { ExifData* exif = exif_data_new(); ExifByteOrder byte_order; if (imBinCPUByteOrder() == IM_LITTLEENDIAN) byte_order = EXIF_BYTE_ORDER_INTEL; else byte_order = EXIF_BYTE_ORDER_MOTOROLA; exif_data_set_byte_order(exif, byte_order); attrib_table->ForEach(exif, (imAttribTableCallback)iExifWriteTag); imbyte* data = NULL; unsigned int data_size = 0; exif_data_save_data(exif, &data, &data_size); if (data) { jpeg_write_marker(&this->cinfo, JPEG_APP0+1, data, data_size); free(data); } exif_data_free(exif); }
void jpeg_data_save_data (JPEGData *data, unsigned char **d, unsigned int *ds) { unsigned int i, eds = 0; JPEGSection s; unsigned char *ed = NULL; if (!data) return; if (!d) return; if (!ds) return; for (*ds = i = 0; i < data->count; i++) { s = data->sections[i]; /* Write the marker */ CLEANUP_REALLOC (*d, sizeof (char) * (*ds + 2)); (*d)[*ds + 0] = 0xff; (*d)[*ds + 1] = s.marker; *ds += 2; switch (s.marker) { case JPEG_MARKER_SOI: case JPEG_MARKER_EOI: break; case JPEG_MARKER_APP1: exif_data_save_data (s.content.app1, &ed, &eds); if (!ed) break; CLEANUP_REALLOC (*d, sizeof (char) * (*ds + 2)); (*d)[*ds + 0] = (eds + 2) >> 8; (*d)[*ds + 1] = (eds + 2) >> 0; *ds += 2; CLEANUP_REALLOC (*d, sizeof (char) * (*ds + eds)); memcpy (*d + *ds, ed, eds); *ds += eds; free (ed); break; default: CLEANUP_REALLOC (*d, sizeof (char) * (*ds + s.content.generic.size + 2)); (*d)[*ds + 0] = (s.content.generic.size + 2) >> 8; (*d)[*ds + 1] = (s.content.generic.size + 2) >> 0; *ds += 2; memcpy (*d + *ds, s.content.generic.data, s.content.generic.size); *ds += s.content.generic.size; /* In case of SOS, we need to write the data. */ if (s.marker == JPEG_MARKER_SOS) { CLEANUP_REALLOC (*d, *ds + data->size); memcpy (*d + *ds, data->data, data->size); *ds += data->size; } break; } } }
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; }
int main (int argc, char **argv) { ExifData *d; unsigned int buf_size; unsigned char *buf; int r; if (argc <= 1) { fprintf (stderr, "You need to supply a filename!\n"); return 1; } fprintf (stdout, "Loading '%s'...\n", argv[1]); d = exif_data_new_from_file (argv[1]); if (!d) { fprintf (stderr, "Could not load data from '%s'!\n", argv[1]); return 1; } fprintf (stdout, "Loaded '%s'.\n", argv[1]); fprintf (stdout, "######### Test 1 #########\n"); r = test_exif_data (d); if (r) return r; exif_data_save_data (d, &buf, &buf_size); exif_data_unref (d); d = exif_data_new_from_data (buf, buf_size); free (buf); fprintf (stdout, "######### Test 2 #########\n"); r = test_exif_data (d); if (r) return r; fprintf (stdout, "Test successful!\n"); return 1; }
/* 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 ); }
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 gboolean _save_any_as_jpeg (EomImage *image, const char *file, EomImageSaveInfo *source, EomImageSaveInfo *target, GError **error) { EomImagePrivate *priv; GdkPixbuf *pixbuf; struct jpeg_compress_struct cinfo; guchar *buf = NULL; guchar *ptr; guchar *pixels = NULL; JSAMPROW *jbuf; int y = 0; volatile int quality = 75; /* default; must be between 0 and 100 */ int i, j; int w, h = 0; int rowstride = 0; FILE *outfile; struct error_handler_data jerr; g_return_val_if_fail (EOM_IS_IMAGE (image), FALSE); g_return_val_if_fail (EOM_IMAGE (image)->priv->image != NULL, FALSE); priv = image->priv; pixbuf = priv->image; rowstride = gdk_pixbuf_get_rowstride (pixbuf); w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); /* no image data? abort */ pixels = gdk_pixbuf_get_pixels (pixbuf); g_return_val_if_fail (pixels != NULL, FALSE); outfile = fopen (file, "wb"); if (outfile == NULL) { g_set_error (error, /* FIXME: Better error message */ GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't create temporary file for saving: %s"), file); return FALSE; } /* allocate a small buffer to convert image data */ buf = g_try_malloc (w * 3 * sizeof (guchar)); if (!buf) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for loading JPEG file")); fclose (outfile); return FALSE; } /* set up error handling */ jerr.filename = (char *) file; cinfo.err = jpeg_std_error (&(jerr.pub)); jerr.pub.error_exit = fatal_error_handler; jerr.pub.output_message = output_message_handler; jerr.error = error; /* setup compress params */ jpeg_create_compress (&cinfo); jpeg_stdio_dest (&cinfo, outfile); cinfo.image_width = w; cinfo.image_height = h; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; /* error exit routine */ if (sigsetjmp (jerr.setjmp_buffer, 1)) { g_free (buf); fclose (outfile); jpeg_destroy_compress (&cinfo); return FALSE; } /* set desired jpeg quality if available */ if (target != NULL && target->jpeg_quality >= 0.0) { quality = (int) MIN (target->jpeg_quality, 1.0) * 100; } /* set up jepg compression parameters */ jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, quality, TRUE); jpeg_start_compress (&cinfo, TRUE); /* write EXIF/IPTC data explicitly */ #if HAVE_EXIF /* exif_chunk and exif are mutally exclusvie, this is what we assure here */ g_assert (priv->exif_chunk == NULL); if (priv->exif != NULL) { unsigned char *exif_buf; unsigned int exif_buf_len; exif_data_save_data (priv->exif, &exif_buf, &exif_buf_len); jpeg_write_marker (&cinfo, 0xe1, exif_buf, exif_buf_len); g_free (exif_buf); } #else if (priv->exif_chunk != NULL) { jpeg_write_marker (&cinfo, JPEG_APP0+1, priv->exif_chunk, priv->exif_chunk_len); } #endif /* FIXME: Consider IPTC data too */ /* get the start pointer */ ptr = pixels; /* go one scanline at a time... and save */ i = 0; while (cinfo.next_scanline < cinfo.image_height) { /* convert scanline from ARGB to RGB packed */ for (j = 0; j < w; j++) memcpy (&(buf[j*3]), &(ptr[i*rowstride + j*(rowstride/w)]), 3); /* write scanline */ jbuf = (JSAMPROW *)(&buf); jpeg_write_scanlines (&cinfo, jbuf, 1); i++; y++; } /* finish off */ jpeg_finish_compress (&cinfo); jpeg_destroy_compress(&cinfo); g_free (buf); fclose (outfile); return TRUE; }
static gboolean _save_jpeg_as_jpeg (EomImage *image, const char *file, EomImageSaveInfo *source, EomImageSaveInfo *target, GError **error) { struct jpeg_decompress_struct srcinfo; struct jpeg_compress_struct dstinfo; struct error_handler_data jsrcerr, jdsterr; jpeg_transform_info transformoption; jvirt_barray_ptr *src_coef_arrays; jvirt_barray_ptr *dst_coef_arrays; FILE *output_file; FILE *input_file; EomImagePrivate *priv; gchar *infile_uri; g_return_val_if_fail (EOM_IS_IMAGE (image), FALSE); g_return_val_if_fail (EOM_IMAGE (image)->priv->file != NULL, FALSE); priv = image->priv; init_transform_info (image, &transformoption); /* Initialize the JPEG decompression object with default error * handling. */ jsrcerr.filename = g_file_get_path (priv->file); srcinfo.err = jpeg_std_error (&(jsrcerr.pub)); jsrcerr.pub.error_exit = fatal_error_handler; jsrcerr.pub.output_message = output_message_handler; jsrcerr.error = error; jpeg_create_decompress (&srcinfo); /* Initialize the JPEG compression object with default error * handling. */ jdsterr.filename = (char *) file; dstinfo.err = jpeg_std_error (&(jdsterr.pub)); jdsterr.pub.error_exit = fatal_error_handler; jdsterr.pub.output_message = output_message_handler; jdsterr.error = error; jpeg_create_compress (&dstinfo); dstinfo.err->trace_level = 0; dstinfo.arith_code = FALSE; dstinfo.optimize_coding = FALSE; jsrcerr.pub.trace_level = jdsterr.pub.trace_level; srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use; /* Open the output file. */ /* FIXME: Make this a GIO aware input manager */ infile_uri = g_file_get_path (priv->file); input_file = fopen (infile_uri, "rb"); if (input_file == NULL) { g_warning ("Input file not openable: %s\n", infile_uri); g_free (jsrcerr.filename); g_free (infile_uri); return FALSE; } g_free (infile_uri); output_file = fopen (file, "wb"); if (output_file == NULL) { g_warning ("Output file not openable: %s\n", file); fclose (input_file); g_free (jsrcerr.filename); return FALSE; } if (sigsetjmp (jsrcerr.setjmp_buffer, 1)) { fclose (output_file); fclose (input_file); jpeg_destroy_compress (&dstinfo); jpeg_destroy_decompress (&srcinfo); g_free (jsrcerr.filename); return FALSE; } if (sigsetjmp (jdsterr.setjmp_buffer, 1)) { fclose (output_file); fclose (input_file); jpeg_destroy_compress (&dstinfo); jpeg_destroy_decompress (&srcinfo); g_free (jsrcerr.filename); return FALSE; } /* Specify data source for decompression */ jpeg_stdio_src (&srcinfo, input_file); /* Enable saving of extra markers that we want to copy */ jcopy_markers_setup (&srcinfo, JCOPYOPT_DEFAULT); /* Read file header */ (void) jpeg_read_header (&srcinfo, TRUE); /* Any space needed by a transform option must be requested before * jpeg_read_coefficients so that memory allocation will be done right. */ jtransform_request_workspace (&srcinfo, &transformoption); /* Read source file as DCT coefficients */ src_coef_arrays = jpeg_read_coefficients (&srcinfo); /* Initialize destination compression parameters from source values */ jpeg_copy_critical_parameters (&srcinfo, &dstinfo); /* Adjust destination parameters if required by transform options; * also find out which set of coefficient arrays will hold the output. */ dst_coef_arrays = jtransform_adjust_parameters (&srcinfo, &dstinfo, src_coef_arrays, &transformoption); /* Specify data destination for compression */ jpeg_stdio_dest (&dstinfo, output_file); /* Start compressor (note no image data is actually written here) */ jpeg_write_coefficients (&dstinfo, dst_coef_arrays); /* handle EXIF/IPTC data explicitly */ #if HAVE_EXIF /* exif_chunk and exif are mutally exclusvie, this is what we assure here */ g_assert (priv->exif_chunk == NULL); if (priv->exif != NULL) { unsigned char *exif_buf; unsigned int exif_buf_len; exif_data_save_data (priv->exif, &exif_buf, &exif_buf_len); jpeg_write_marker (&dstinfo, JPEG_APP0+1, exif_buf, exif_buf_len); g_free (exif_buf); } #else if (priv->exif_chunk != NULL) { jpeg_write_marker (&dstinfo, JPEG_APP0+1, priv->exif_chunk, priv->exif_chunk_len); } #endif /* FIXME: Consider IPTC data too */ /* Copy to the output file any extra markers that we want to * preserve */ jcopy_markers_execute (&srcinfo, &dstinfo, JCOPYOPT_DEFAULT); /* Execute image transformation, if any */ jtransform_execute_transformation (&srcinfo, &dstinfo, src_coef_arrays, &transformoption); /* Finish compression and release memory */ jpeg_finish_compress (&dstinfo); jpeg_destroy_compress (&dstinfo); (void) jpeg_finish_decompress (&srcinfo); jpeg_destroy_decompress (&srcinfo); g_free (jsrcerr.filename); /* Close files */ fclose (input_file); fclose (output_file); return TRUE; }
void jpeg_data_save_data (JPEGData *data, unsigned char **d, unsigned int *ds) { unsigned int i, eds = 0; JPEGSection s; unsigned char *ed = NULL; if (!data) return; if (!d) return; if (!ds) return; for (*ds = i = 0; i < data->count; i++) { s = data->sections[i]; #ifdef DEBUG printf ("Writing marker 0x%x at position %i...\n", s.marker, *ds); #endif /* Write the marker */ *d = realloc (*d, sizeof (char) * (*ds + 2)); (*d)[*ds + 0] = 0xff; (*d)[*ds + 1] = s.marker; *ds += 2; switch (s.marker) { case JPEG_MARKER_SOI: case JPEG_MARKER_EOI: break; case JPEG_MARKER_APP1: exif_data_save_data (s.content.app1, &ed, &eds); *d = realloc (*d, sizeof (char) * (*ds + 2)); (*d)[*ds + 0] = (eds + 2) >> 8; (*d)[*ds + 1] = (eds + 2) >> 0; *ds += 2; *d = realloc (*d, sizeof (char) * (*ds + eds)); memcpy (*d + *ds, ed, eds); *ds += eds; break; default: *d = realloc (*d, sizeof (char) * (*ds + s.content.generic.size + 2)); (*d)[*ds + 0] = (s.content.generic.size + 2) >> 8; (*d)[*ds + 1] = (s.content.generic.size + 2) >> 0; *ds += 2; memcpy (*d + *ds, s.content.generic.data, s.content.generic.size); *ds += s.content.generic.size; /* In case of SOS, we need to write the data. */ if (s.marker == JPEG_MARKER_SOS) { *d = realloc (*d, *ds + data->size); memcpy (*d + *ds, data->data, data->size); *ds += data->size; } break; } } }
static int get_file_func (CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, void *user_data, GPContext *context) { char path[1024]; int result = GP_OK; struct stat stbuf; int fd, id; unsigned int curread, toread; unsigned char *buf; #ifdef HAVE_LIBEXIF ExifData *data; unsigned int buf_len; #endif /* HAVE_LIBEXIF */ Camera *camera = (Camera*)user_data; result = _get_path (camera->port, folder, filename, path, sizeof(path)); gp_log (GP_LOG_DEBUG, "directory/get_file_func", "%s %s",folder,filename); if (result < GP_OK) return result; gp_log (GP_LOG_DEBUG, "directory/get_file_func", "->%s",path); switch (type) { case GP_FILE_TYPE_NORMAL: #ifdef DEBUG case GP_FILE_TYPE_PREVIEW: #endif fd = open (path,O_RDONLY); if (fd == -1) return GP_ERROR_IO_READ; break; #ifdef HAVE_LIBEXIF case GP_FILE_TYPE_EXIF: data = exif_data_new_from_file (path); if (!data) { gp_context_error (context, _("Could not open '%s'."), path); return (GP_ERROR); } exif_data_save_data (data, &buf, &buf_len); exif_data_unref (data); gp_file_set_data_and_size (file, buf, buf_len); return (GP_OK); #endif /* HAVE_LIBEXIF */ default: return (GP_ERROR_NOT_SUPPORTED); } if (-1 == fstat(fd,&stbuf)) { close (fd); return GP_ERROR_IO_READ; } #define BLOCKSIZE 65536 /* do it in 64kb blocks */ buf = malloc(BLOCKSIZE); if (!buf) { close (fd); return GP_ERROR_NO_MEMORY; } curread = 0; id = gp_context_progress_start (context, (1.0*stbuf.st_size/BLOCKSIZE), _("Getting file...")); GP_DEBUG ("Progress id: %i", id); result = GP_OK; while (curread < stbuf.st_size) { int ret; toread = stbuf.st_size-curread; if (toread>BLOCKSIZE) toread = BLOCKSIZE; ret = read(fd,buf,toread); if (ret == -1) { result = GP_ERROR_IO_READ; break; } curread += ret; gp_file_append (file, buf, ret); gp_context_progress_update (context, id, (1.0*curread/BLOCKSIZE)); gp_context_idle (context); if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) { result = GP_ERROR_CANCEL; break; } #if 0 /* We could take 2 seconds to download this image. everytime. */ /* But actually this driver is used in production by some frontends, * so do not delay at all */ usleep(2000000/(stbuf.st_size/BLOCKSIZE)); #endif } gp_context_progress_stop (context, id); free (buf); close (fd); return (GP_OK); }
exif_buffer *get_exif_buffer(void *params, void *gpsLocation) { ExifData *pEd; exif_buffer *sEb; ExifRational sR; struct timeval sTv; struct tm *sTime; char *TimeStr = NULL; int res; exif_params *par; if ( NULL == params) return NULL; par = (exif_params *) params; sEb = (exif_buffer *) malloc (sizeof (exif_buffer)); pEd = exif_data_new (); if(pEd == NULL) goto EXIT; exif_entry_set_string (pEd, EXIF_IFD_0, EXIF_TAG_MAKE, "Zoom"); exif_entry_set_string (pEd, EXIF_IFD_0, EXIF_TAG_MODEL, "SONY IU046"); exif_entry_set_short(pEd, EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, par->width); exif_entry_set_short(pEd, EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, par->height); switch( par->rotation ) { case 0: exif_entry_set_short(pEd, EXIF_IFD_0, EXIF_TAG_ORIENTATION, 1); break; case 90: exif_entry_set_short(pEd, EXIF_IFD_0, EXIF_TAG_ORIENTATION, 6); break; case 180: exif_entry_set_short(pEd, EXIF_IFD_0, EXIF_TAG_ORIENTATION, 3); break; case 270: exif_entry_set_short(pEd, EXIF_IFD_0, EXIF_TAG_ORIENTATION, 8); break; }; sR.numerator = 4*100+68; sR.denominator = 100; exif_entry_set_rational(pEd, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, sR); exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_FLASH, 0); switch( par->metering_mode ) { case EXIF_CENTER: exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_METERING_MODE, 1); break; case EXIF_AVERAGE: exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_METERING_MODE, 2); break; }; switch( par->iso ) { case EXIF_ISO_AUTO: exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, 0); break; case EXIF_ISO_100: exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, 100); break; case EXIF_ISO_200: exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, 200); break; case EXIF_ISO_400: exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, 400); break; case EXIF_ISO_800: exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, 800); break; case EXIF_ISO_1000: exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, 1000); break; case EXIF_ISO_1200: exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, 1200); break; case EXIF_ISO_1600: exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, 1600); break; }; sR.numerator = par->zoom*100; sR.denominator = 100; exif_entry_set_rational (pEd, EXIF_IFD_EXIF, EXIF_TAG_DIGITAL_ZOOM_RATIO, sR); if ( EXIF_WB_AUTO == par->wb ) exif_entry_set_short (pEd, EXIF_IFD_EXIF, EXIF_TAG_WHITE_BALANCE, 0); else exif_entry_set_short (pEd, EXIF_IFD_EXIF, EXIF_TAG_WHITE_BALANCE, 1); sR.numerator = par->exposure; sR.denominator = 1000000; exif_entry_set_rational (pEd, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, sR); /* resolution */ sR.numerator = 72; sR.denominator = 1; exif_entry_set_rational (pEd, EXIF_IFD_0, EXIF_TAG_X_RESOLUTION, sR); exif_entry_set_rational (pEd, EXIF_IFD_0, EXIF_TAG_Y_RESOLUTION, sR); exif_entry_set_short (pEd, EXIF_IFD_0, EXIF_TAG_RESOLUTION_UNIT, 2); /* inches */ exif_entry_set_short (pEd, EXIF_IFD_0, EXIF_TAG_YCBCR_POSITIONING, 1); /* centered */ exif_entry_set_short(pEd, EXIF_IFD_0, EXIF_TAG_YCBCR_SUB_SAMPLING, 0); /* Exif version */ exif_entry_set_undefined (pEd, EXIF_IFD_EXIF, EXIF_TAG_EXIF_VERSION, NULL); /* flashpix version */ exif_entry_set_undefined(pEd, EXIF_IFD_EXIF, EXIF_TAG_FLASH_PIX_VERSION, NULL); /* file source */ exif_entry_set_undefined(pEd, EXIF_IFD_EXIF, EXIF_TAG_FILE_SOURCE, NULL); /* file name */ exif_entry_set_undefined(pEd, EXIF_IFD_EXIF, EXIF_TAG_DOCUMENT_NAME, NULL); /* scene type */ exif_entry_set_undefined(pEd, EXIF_IFD_EXIF, EXIF_TAG_SCENE_TYPE, NULL); /* Color Components */ exif_entry_set_undefined(pEd, EXIF_IFD_EXIF, EXIF_TAG_COMPONENTS_CONFIGURATION, NULL); /* Bits per sample */ exif_entry_set_undefined (pEd, EXIF_IFD_0, EXIF_TAG_BITS_PER_SAMPLE, NULL); /* Color space */ exif_entry_set_short (pEd, EXIF_IFD_EXIF, EXIF_TAG_COLOR_SPACE, 1); /* Interoperability index */ exif_entry_set_string(pEd, EXIF_IFD_INTEROPERABILITY, EXIF_TAG_INTEROPERABILITY_INDEX, "R98"); /* time */ /* this sould be last resort */ res = gettimeofday (&sTv, NULL); sTime = localtime (&sTv.tv_sec); if (res == 0 && sTime != NULL) { TimeStr = (char *) malloc(20);/* No data for secondary sensor */ if (TimeStr != NULL) { snprintf(TimeStr, 20, "%04d:%02d:%02d %02d:%02d:%02d", sTime->tm_year + 1900, sTime->tm_mon + 1, sTime->tm_mday, sTime->tm_hour, sTime->tm_min, sTime->tm_sec ); exif_entry_set_string (pEd, EXIF_IFD_0, EXIF_TAG_DATE_TIME, TimeStr); exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, TimeStr); exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, TimeStr); snprintf(TimeStr, 20, "%06d", (int) sTv.tv_usec); exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME, TimeStr); exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_ORIGINAL, TimeStr); exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_DIGITIZED, TimeStr); free (TimeStr); TimeStr = NULL; } else { printf ("%s():%d:!!!!!ERROR: malloc Failed.\n",__FUNCTION__,__LINE__); } } else { printf ("Error in time recognition. res: %d sTime: %p\n%s\n", res, sTime, strerror(errno)); } exif_entry_set_short (pEd, EXIF_IFD_1, EXIF_TAG_COMPRESSION, 6); /* JPEG */ exif_entry_set_long (pEd, EXIF_IFD_1, EXIF_TAG_JPEG_INTERCHANGE_FORMAT, 0xFFFFFFFF); exif_entry_set_long (pEd, EXIF_IFD_1, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 0xFFFFFFFF); if ( NULL != gpsLocation ) { ExifRational r1, r2, r3; gps_data *gps = (gps_data *) gpsLocation; /* gps data */ r1.denominator = 1; r2.denominator = 1; r3.denominator = 1; r1.numerator = gps->longDeg; r2.numerator = gps->longMin; r3.numerator = gps->longSec; exif_entry_set_gps_coord(pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_LONGITUDE, r1, r2, r3); r1.numerator = gps->latDeg; r2.numerator = gps->latMin; r3.numerator = gps->latSec; exif_entry_set_gps_coord(pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_LATITUDE, r1, r2, r3); r1.numerator = gps->altitude; exif_entry_set_gps_altitude(pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_ALTITUDE, r1); sTime = localtime ((const time_t*) &gps->timestamp); if ( NULL != sTime ) { r1.numerator = sTime->tm_hour; r2.numerator = sTime->tm_min; r3.numerator = sTime->tm_sec; exif_entry_set_gps_coord(pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_TIME_STAMP, r1, r2, r3); } exif_entry_set_byte(pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_ALTITUDE_REF, (ExifByte) gps->altitudeRef); if( NULL != gps->latRef ) exif_entry_set_string (pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_LATITUDE_REF, gps->latRef); if( NULL != gps->longRef ) exif_entry_set_string (pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_LONGITUDE_REF, gps->longRef); if( NULL != gps->procMethod ) { //using strlen since i don't want the terminating null unsigned char* data = (unsigned char*)malloc(strlen(gps->procMethod) + sizeof(ExifAsciiPrefix)); exif_buffer buffer; if(data != NULL) { memcpy(data, ExifAsciiPrefix, sizeof(ExifAsciiPrefix)); memcpy(data+sizeof(ExifAsciiPrefix), gps->procMethod, strlen(gps->procMethod)); buffer.data = data; buffer.size = strlen(gps->procMethod)+sizeof(ExifAsciiPrefix); exif_entry_set_undefined (pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_PROCESSING_METHOD, &buffer); free(data); } } if( NULL != gps->mapdatum ) exif_entry_set_string (pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_MAP_DATUM, gps->mapdatum); if( strlen(gps->datestamp) == 10) exif_entry_set_string (pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_DATE_STAMP, gps->datestamp); if( NULL != gps->versionId ) exif_entry_set_gps_version(pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_VERSION_ID, gps->versionId[0], gps->versionId[1], gps->versionId[2], gps->versionId[3]); } /* copy data to our buffer */ exif_data_save_data (pEd, &sEb->data, &sEb->size); /* destroy exif structure */ exif_data_unref(pEd); return sEb; EXIT: if(sEb != NULL) free(sEb); return NULL; }
static int write_exif( Write *write ) { unsigned char *data; size_t data_length; unsigned int idl; #ifdef HAVE_EXIF ExifData *ed; /* Either parse from the embedded EXIF, or if there's none, make * some fresh EXIF we can write the resolution to. */ if( im_header_get_typeof( write->in, IM_META_EXIF_NAME ) ) { if( im_meta_get_blob( write->in, IM_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(); /* Update EXIF resolution from VIPS. */ if( set_exif_resolution( 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 ) { im_error( "im_jpeg2vips", "%s", _( "error saving EXIF" ) ); exif_data_free( ed ); return( -1 ); } data_length = idl; #ifdef DEBUG printf( "im_vips2jpeg: 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( im_header_get_typeof( write->in, IM_META_EXIF_NAME ) ) { if( im_meta_get_blob( write->in, IM_META_EXIF_NAME, (void *) &data, &data_length ) ) return( -1 ); #ifdef DEBUG printf( "im_vips2jpeg: attaching %d bytes of EXIF\n", data_length ); #endif /*DEBUG*/ jpeg_write_marker( &write->cinfo, JPEG_APP0 + 1, data, data_length ); } #endif /*!HAVE_EXIF*/ return( 0 ); }
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 ); }