Reputation: 1123
In my C program I would like to use libexif along with libjpeg to set exif tags on an existing jpeg file present at a given path inputFilePath, and save the resulting jpeg to output path outputFilePath.
The input jpeg file is large (40000 X 40000 pixels) so loading the whole image in memory isn't preferable and shouldn't be needed.
I don't care about other existing Exif tags in the Jpeg, they may be removed.
I have read and tried the example provided with libexif which uses a fixed JPEG, but just can't figure out how to do the same for any JPEG.
Btw, I did get the following code which sets exif tags by loading the jpeg in-memory to work. It uses the libjpeg implementation provided in exif utility that comes along with libexif.
ExifEntry *entry;
ExifData *exif = exif_data_new();
if (!exif) {
//Out of memory
}
/* 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);
/* All these tags are created with default values by exif_data_fix() */
/* Change the data to the correct values for this image. */
entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION);
exif_set_long(entry->data, FILE_BYTE_ORDER, w);
entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION);
exif_set_long(entry->data, FILE_BYTE_ORDER, h);
entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_COLOR_SPACE);
exif_set_short(entry->data, FILE_BYTE_ORDER, 1);
/* Create a EXIF_TAG_USER_COMMENT tag. This one must be handled
* differently because that tag isn't automatically created and
* allocated by exif_data_fix(), nor can it be created using
* exif_entry_initialize() so it must be explicitly allocated here.
*/
entry = create_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_USER_COMMENT,
sizeof(ASCII_COMMENT) + sizeof(FILE_COMMENT) - 2);
/* Write the special header needed for a comment tag */
memcpy(entry->data, ASCII_COMMENT, sizeof(ASCII_COMMENT) - 1);
/* Write the actual comment text, without the trailing NUL character */
memcpy(entry->data + 8, FILE_COMMENT, sizeof(FILE_COMMENT) - 1);
/* create_tag() happens to set the format and components correctly for
* EXIF_TAG_USER_COMMENT, so there is nothing more to do. */
JPEGData *jdata;
unsigned char *d = NULL;
unsigned int ds;
ExifLog *log = NULL;
/* Parse the JPEG file. */
jdata = jpeg_data_new();
jpeg_data_log(jdata, log);
jpeg_data_load_file(jdata, inputFilePath);
/* Make sure the EXIF data is not too big. */
exif_data_save_data(exif, &d, &ds);
if (ds) {
free(d);
if (ds > 0xffff)
//Too much EXIF data
};
jpeg_data_set_exif_data(jdata, exif);
/* Save the modified image. */
jpeg_data_save_file(jdata, outputFilePath);
jpeg_data_unref(jdata);
Upvotes: 3
Views: 2916
Reputation: 837
If you aren't re-compressing or editing the image, then you won't need libjpeg
. It can be done with fopen
and fputc
.
There's a good description of the JPEG file structure and metadata from exiv2. Most jpeg files will start with 0xFFD8
(start of image), then an APP0
block for JFIF data (0xFF E0 <length> <data>
). If there is an EXIF header, it's in the APP1
block (0xFF E1 <length> <data>
).
The blocks in a JPEG file are formatted as
0xFF xx
) where xx
is En
for APPn
blocksContent
So, an outline of your program would be
APP1
blockAPP1
block insteadThe EXIF header contents can be created with exif_data_save_data()
in libexif
.
Upvotes: 3