1548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen/* 2548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * write-exif.c 3548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * 4548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * Placed into the public domain by Daniel Fandrich 5548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * 6548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * Create a new EXIF data block and write it into a JPEG image file. 7548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * 8548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * The JPEG image data used in this example is fixed and is guaranteed not 9548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * to contain an EXIF tag block already, so it is easy to precompute where 10548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * in the file the EXIF data should be. In real life, a library like 11548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * libjpeg (included with the exif command-line tool source code) would 12548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * be used to write to an existing JPEG file. 13548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen */ 14548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 15548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen#include <stdio.h> 16548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen#include <stdlib.h> 17548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen#include <string.h> 18548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen#include <assert.h> 19548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen#include <libexif/exif-data.h> 20548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 21548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen/* this file will be unilaterally overwritten */ 22548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen#define FILE_NAME "write-exif.jpg" 23548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 24548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen/* raw JPEG image data */ 25548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissenstatic const unsigned char image_jpg[] = { 26548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 27548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43, 28548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x00, 0x14, 0x0e, 0x0f, 0x12, 0x0f, 0x0d, 0x14, 0x12, 0x10, 0x12, 0x17, 29548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x15, 0x14, 0x18, 0x1e, 0x32, 0x21, 0x1e, 0x1c, 0x1c, 0x1e, 0x3d, 0x2c, 30548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x2e, 0x24, 0x32, 0x49, 0x40, 0x4c, 0x4b, 0x47, 0x40, 0x46, 0x45, 0x50, 31548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x5a, 0x73, 0x62, 0x50, 0x55, 0x6d, 0x56, 0x45, 0x46, 0x64, 0x88, 0x65, 32548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x6d, 0x77, 0x7b, 0x81, 0x82, 0x81, 0x4e, 0x60, 0x8d, 0x97, 0x8c, 0x7d, 33548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x96, 0x73, 0x7e, 0x81, 0x7c, 0xff, 0xc0, 0x00, 0x0b, 0x08, 0x00, 0x40, 34548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x00, 0x40, 0x01, 0x01, 0x11, 0x00, 0xff, 0xc4, 0x00, 0x1b, 0x00, 0x00, 35548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 36548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x04, 0x03, 0x07, 0x02, 0x01, 0xff, 37548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xc4, 0x00, 0x2f, 0x10, 0x00, 0x01, 0x03, 0x03, 0x02, 0x05, 0x03, 0x03, 38548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x11, 39548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x00, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x81, 0x61, 0x71, 40548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x91, 0x13, 0x32, 0xa1, 0x14, 0x22, 0xc1, 0x15, 0x23, 0x52, 0xd1, 0xf0, 41548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xb3, 0xa2, 42548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x8a, 0x28, 0xa2, 0x8a, 0x28, 0xa2, 0x97, 0x64, 0x72, 0xd6, 0x58, 0xd4, 43548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x8f, 0xd5, 0x3d, 0xca, 0xa5, 0x7d, 0xa8, 0x4e, 0xaa, 0x3e, 0xb0, 0x3a, 44548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x7a, 0x9d, 0x2b, 0x2d, 0x87, 0x13, 0xe3, 0xaf, 0x9f, 0x0c, 0xb6, 0xb5, 45548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xb6, 0xe2, 0xb4, 0x48, 0x71, 0x30, 0x14, 0x7b, 0x02, 0x09, 0x14, 0xee, 46548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x94, 0x64, 0x38, 0x87, 0x1f, 0x8d, 0x5f, 0xd3, 0x7d, 0xe2, 0xa7, 0x46, 47548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xe8, 0x6c, 0x49, 0x1e, 0xfd, 0x07, 0xb1, 0x33, 0x5f, 0xb8, 0xdc, 0xf5, 48548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x96, 0x51, 0x7c, 0x96, 0xee, 0x14, 0xba, 0x04, 0xf2, 0x2c, 0x42, 0xa3, 49548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xd3, 0x70, 0x7c, 0x1a, 0x6d, 0x45, 0x2c, 0xcd, 0xe5, 0x11, 0x89, 0xb1, 50548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x5b, 0xc4, 0x02, 0xe1, 0xd1, 0xb4, 0xcf, 0xdc, 0xa3, 0xfc, 0x0d, 0xcd, 51548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x41, 0xde, 0xe3, 0xb2, 0x2e, 0xda, 0x1c, 0xbd, 0xe2, 0x4a, 0x90, 0xe9, 52548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x04, 0x95, 0x2b, 0xf7, 0x41, 0xd0, 0x18, 0xe8, 0x36, 0x03, 0xc6, 0x91, 53548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x4a, 0x81, 0x20, 0x82, 0x24, 0x10, 0x66, 0x45, 0x5a, 0xdd, 0xf1, 0x32, 54548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xff, 0x00, 0xa2, 0x5a, 0x8b, 0x62, 0x57, 0x7d, 0x70, 0x80, 0x93, 0x1a, 55548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x94, 0x10, 0x79, 0x4a, 0xa3, 0xb9, 0x20, 0xc0, 0xf3, 0xd3, 0x55, 0x59, 56548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x4e, 0x1c, 0x7a, 0xc7, 0x12, 0x9b, 0xc7, 0x94, 0xa7, 0x2e, 0x14, 0xa9, 57548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x74, 0x0d, 0x42, 0x01, 0x04, 0xc9, 0x3b, 0x93, 0x30, 0x09, 0xdb, 0x5f, 58548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x35, 0x9b, 0x85, 0xad, 0xde, 0x7f, 0x39, 0x6e, 0xa6, 0x82, 0xa1, 0xa5, 59548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x73, 0x2d, 0x40, 0x68, 0x13, 0x06, 0x67, 0xdf, 0x6f, 0x35, 0xe9, 0xb4, 60548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x52, 0x4c, 0xbe, 0x0c, 0x65, 0x72, 0x16, 0xcf, 0x3a, 0xff, 0x00, 0xf6, 61548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x5a, 0xd1, 0x4d, 0x11, 0xa1, 0x13, 0x26, 0x0f, 0x73, 0x00, 0x1f, 0x41, 62548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x5b, 0x72, 0xd6, 0xa2, 0xeb, 0x15, 0x73, 0x6e, 0x13, 0xf7, 0x36, 0x42, 63548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x40, 0xee, 0x04, 0x8f, 0xc8, 0x15, 0xe4, 0xf5, 0x59, 0xc1, 0x16, 0x0d, 64548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x3d, 0x70, 0xed, 0xdb, 0x84, 0x29, 0x6c, 0x40, 0x42, 0x3b, 0x13, 0x3f, 65548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xb8, 0xfc, 0x10, 0x3c, 0xd5, 0xc1, 0x00, 0x88, 0x22, 0x41, 0xef, 0x5f, 66548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x0d, 0xb4, 0x86, 0x81, 0x0d, 0xa1, 0x28, 0x07, 0x52, 0x12, 0x00, 0x06, 67548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xba, 0xd1, 0x45, 0x71, 0xb8, 0xb8, 0x6e, 0xd9, 0x85, 0xbc, 0xf2, 0xb9, 68548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x5b, 0x40, 0x25, 0x47, 0xb0, 0xaf, 0x24, 0x79, 0x48, 0x53, 0xce, 0x29, 69548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xb4, 0x94, 0xa0, 0xa8, 0x94, 0xa7, 0xb0, 0x27, 0x41, 0xf1, 0x54, 0x9c, 70548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x09, 0x71, 0xc9, 0x92, 0x7d, 0x82, 0x74, 0x75, 0xa9, 0x1e, 0xa5, 0x27, 71548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xfd, 0x13, 0x55, 0xd9, 0x3c, 0x83, 0x38, 0xbb, 0x45, 0x5c, 0xbf, 0x3c, 72548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xa1, 0x40, 0x40, 0x02, 0x54, 0x4f, 0x41, 0x3e, 0x4f, 0x83, 0x5a, 0x2d, 73548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xae, 0x1b, 0xba, 0xb7, 0x6d, 0xf6, 0x89, 0x28, 0x71, 0x21, 0x49, 0x24, 74548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x41, 0x83, 0xe9, 0x5d, 0xe9, 0x3f, 0x12, 0x64, 0x97, 0x8b, 0xc6, 0x17, 75548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x59, 0x03, 0xea, 0xa9, 0x61, 0x08, 0x24, 0x48, 0x04, 0xc9, 0x9f, 0x80, 76548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x6a, 0x4b, 0x17, 0xc4, 0xd7, 0xac, 0xdf, 0x36, 0xab, 0xbb, 0x85, 0x39, 77548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x6e, 0xb5, 0x00, 0xe0, 0x50, 0x06, 0x01, 0x3a, 0x91, 0x02, 0x44, 0x6f, 78548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x02, 0xb7, 0x65, 0xb2, 0x0e, 0x71, 0x25, 0xf3, 0x58, 0xdc, 0x72, 0x8f, 79548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xe9, 0xc1, 0xe6, 0x52, 0xe0, 0xc2, 0xa3, 0x72, 0x46, 0xe0, 0x0e, 0x83, 80548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xa9, 0xf1, 0x4b, 0x38, 0x9f, 0x16, 0xde, 0x2e, 0xfd, 0xa4, 0x32, 0x92, 81548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x1a, 0x5b, 0x40, 0x83, 0xdc, 0x8d, 0x0f, 0x9d, 0x01, 0x3e, 0xf5, 0x83, 82548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x17, 0x7a, 0xac, 0x76, 0x41, 0x9b, 0xa4, 0xa7, 0x9b, 0xe9, 0xab, 0x51, 83548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x31, 0x20, 0x82, 0x08, 0xf8, 0x34, 0xf9, 0xdb, 0x97, 0xb8, 0xb7, 0x2c, 84548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xcd, 0xba, 0x12, 0xa6, 0xec, 0xda, 0x3c, 0xca, 0x13, 0x24, 0x0e, 0xa4, 85548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x91, 0xa4, 0x9d, 0x87, 0x69, 0xf7, 0xab, 0x74, 0x21, 0x2d, 0xa1, 0x28, 86548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x4a, 0x42, 0x52, 0x90, 0x02, 0x40, 0xd8, 0x01, 0xb0, 0xae, 0x95, 0x87, 87548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x29, 0x8f, 0x6f, 0x27, 0x64, 0xe5, 0xb3, 0xc4, 0x80, 0xa8, 0x29, 0x50, 88548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xdd, 0x24, 0x6c, 0x47, 0xfd, 0xd4, 0xd4, 0x92, 0x78, 0x1e, 0xef, 0xeb, 89548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x42, 0xae, 0x98, 0x0d, 0x7f, 0x90, 0x0a, 0x27, 0xe2, 0x00, 0xfc, 0xd5, 90548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x4e, 0x27, 0x11, 0x6d, 0x89, 0x60, 0xb7, 0x6e, 0x92, 0x54, 0xa8, 0xe6, 91548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x71, 0x5b, 0xa8, 0xff, 0x00, 0x03, 0xd2, 0xbe, 0x73, 0x38, 0x86, 0x72, 92548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xf6, 0xc1, 0xb7, 0x4f, 0x2a, 0xd1, 0x25, 0x0e, 0x01, 0x25, 0x27, 0xae, 93548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x9d, 0x41, 0xed, 0xed, 0x52, 0xe8, 0xe0, 0x7b, 0xcf, 0xab, 0x0e, 0x5d, 94548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x30, 0x96, 0xe7, 0xee, 0x4f, 0x31, 0x57, 0xc1, 0x00, 0x7e, 0x6a, 0xaf, 95548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x15, 0x8b, 0x63, 0x17, 0x6e, 0x1a, 0x61, 0x24, 0x92, 0x65, 0x6b, 0x3b, 96548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xa8, 0xf7, 0x3e, 0x9d, 0x87, 0x4a, 0x63, 0x45, 0x14, 0x51, 0x45, 0x14, 97548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0x51, 0x45, 0x7f, 0xff, 0xd9 98548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen}; 99548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 100548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen/* length of data in image_jpg */ 101548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissenstatic const unsigned int image_jpg_len = sizeof(image_jpg); 102548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 103548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen/* dimensions of image */ 104548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissenstatic const unsigned int image_jpg_x = 64; 105548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissenstatic const unsigned int image_jpg_y = 64; 106548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 107548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen/* start of JPEG image data section */ 108548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissenstatic const unsigned int image_data_offset = 20; 109548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen#define image_data_len (image_jpg_len - image_data_offset) 110548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 111548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen/* raw EXIF header data */ 112548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissenstatic const unsigned char exif_header[] = { 113548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 0xff, 0xd8, 0xff, 0xe1 114548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen}; 115548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen/* length of data in exif_header */ 116548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissenstatic const unsigned int exif_header_len = sizeof(exif_header); 117548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 118548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen/* byte order to use in the EXIF block */ 119548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen#define FILE_BYTE_ORDER EXIF_BYTE_ORDER_INTEL 120548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 121548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen/* comment to write into the EXIF block */ 122548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen#define FILE_COMMENT "libexif demonstration image" 123548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 124548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen/* special header required for EXIF_TAG_USER_COMMENT */ 125548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen#define ASCII_COMMENT "ASCII\0\0\0" 126548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 127548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 128548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen/* Get an existing tag, or create one if it doesn't exist */ 129548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissenstatic ExifEntry *init_tag(ExifData *exif, ExifIfd ifd, ExifTag tag) 130548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen{ 131548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen ExifEntry *entry; 132548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Return an existing tag if one exists */ 133548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen if (!((entry = exif_content_get_entry (exif->ifd[ifd], tag)))) { 134548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Allocate a new entry */ 135548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry = exif_entry_new (); 136548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen assert(entry != NULL); /* catch an out of memory condition */ 137548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry->tag = tag; /* tag must be set before calling 138548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_content_add_entry */ 139548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 140548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Attach the ExifEntry to an IFD */ 141548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_content_add_entry (exif->ifd[ifd], entry); 142548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 143548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Allocate memory for the entry and fill with default data */ 144548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_entry_initialize (entry, tag); 145548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 146548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Ownership of the ExifEntry has now been passed to the IFD. 147548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * One must be very careful in accessing a structure after 148548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * unref'ing it; in this case, we know "entry" won't be freed 149548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * because the reference count was bumped when it was added to 150548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * the IFD. 151548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen */ 152548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_entry_unref(entry); 153548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen } 154548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen return entry; 155548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen} 156548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 157548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen/* Create a brand-new tag with a data field of the given length, in the 158548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * given IFD. This is needed when exif_entry_initialize() isn't able to create 159548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * this type of tag itself, or the default data length it creates isn't the 160548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * correct length. 161548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen */ 162548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissenstatic ExifEntry *create_tag(ExifData *exif, ExifIfd ifd, ExifTag tag, size_t len) 163548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen{ 164548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen void *buf; 165548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen ExifEntry *entry; 166548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 167548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Create a memory allocator to manage this ExifEntry */ 168548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen ExifMem *mem = exif_mem_new_default(); 169548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen assert(mem != NULL); /* catch an out of memory condition */ 170548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 171548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Create a new ExifEntry using our allocator */ 172548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry = exif_entry_new_mem (mem); 173548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen assert(entry != NULL); 174548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 175548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Allocate memory to use for holding the tag data */ 176548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen buf = exif_mem_alloc(mem, len); 177548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen assert(buf != NULL); 178548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 179548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Fill in the entry */ 180548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry->data = buf; 181548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry->size = len; 182548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry->tag = tag; 183548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry->components = len; 184548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry->format = EXIF_FORMAT_UNDEFINED; 185548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 186548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Attach the ExifEntry to an IFD */ 187548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_content_add_entry (exif->ifd[ifd], entry); 188548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 189548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* The ExifMem and ExifEntry are now owned elsewhere */ 190548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_mem_unref(mem); 191548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_entry_unref(entry); 192548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 193548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen return entry; 194548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen} 195548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 196548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissenint main(int argc, char **argv) 197548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen{ 198548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen int rc = 1; 199548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen FILE *f; 200548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen unsigned char *exif_data; 201548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen unsigned int exif_data_len; 202548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen ExifEntry *entry; 203548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen ExifData *exif = exif_data_new(); 204548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen if (!exif) { 205548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen fprintf(stderr, "Out of memory\n"); 206548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen return 2; 207548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen } 208548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 209548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Set the image options */ 210548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_data_set_option(exif, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); 211548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_data_set_data_type(exif, EXIF_DATA_TYPE_COMPRESSED); 212548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_data_set_byte_order(exif, FILE_BYTE_ORDER); 213548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 214548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Create the mandatory EXIF fields with default data */ 215548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_data_fix(exif); 216548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 217548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* All these tags are created with default values by exif_data_fix() */ 218548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Change the data to the correct values for this image. */ 219548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION); 220548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_set_long(entry->data, FILE_BYTE_ORDER, image_jpg_x); 221548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 222548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION); 223548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_set_long(entry->data, FILE_BYTE_ORDER, image_jpg_y); 224548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 225548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_COLOR_SPACE); 226548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_set_short(entry->data, FILE_BYTE_ORDER, 1); 227548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 228548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Create a EXIF_TAG_USER_COMMENT tag. This one must be handled 229548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * differently because that tag isn't automatically created and 230548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * allocated by exif_data_fix(), nor can it be created using 231548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * exif_entry_initialize() so it must be explicitly allocated here. 232548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen */ 233548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry = create_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_USER_COMMENT, 234548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen sizeof(ASCII_COMMENT) + sizeof(FILE_COMMENT) - 2); 235548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Write the special header needed for a comment tag */ 236548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen memcpy(entry->data, ASCII_COMMENT, sizeof(ASCII_COMMENT)-1); 237548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Write the actual comment text, without the trailing NUL character */ 238548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen memcpy(entry->data+8, FILE_COMMENT, sizeof(FILE_COMMENT)-1); 239548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* create_tag() happens to set the format and components correctly for 240548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * EXIF_TAG_USER_COMMENT, so there is nothing more to do. */ 241548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 242548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Create a EXIF_TAG_SUBJECT_AREA tag */ 243548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry = create_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_SUBJECT_AREA, 244548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 4 * exif_format_get_size(EXIF_FORMAT_SHORT)); 245548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry->format = EXIF_FORMAT_SHORT; 246548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen entry->components = 4; 247548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_set_short(entry->data, FILE_BYTE_ORDER, image_jpg_x / 2); 248548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_set_short(entry->data+2, FILE_BYTE_ORDER, image_jpg_y / 2); 249548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_set_short(entry->data+4, FILE_BYTE_ORDER, image_jpg_x); 250548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_set_short(entry->data+6, FILE_BYTE_ORDER, image_jpg_y); 251548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 252548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Get a pointer to the EXIF data block we just created */ 253548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_data_save_data(exif, &exif_data, &exif_data_len); 254548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen assert(exif_data != NULL); 255548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 256548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen f = fopen(FILE_NAME, "wb"); 257548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen if (!f) { 258548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen fprintf(stderr, "Error creating file %s\n", FILE_NAME); 259548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_data_unref(exif); 260548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen return rc; 261548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen } 262548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Write EXIF header */ 263548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen if (fwrite(exif_header, exif_header_len, 1, f) != 1) { 264548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen fprintf(stderr, "Error writing to file %s\n", FILE_NAME); 265548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen goto errout; 266548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen } 267548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Write EXIF block length in big-endian order */ 268548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen if (fputc((exif_data_len+2) >> 8, f) < 0) { 269548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen fprintf(stderr, "Error writing to file %s\n", FILE_NAME); 270548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen goto errout; 271548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen } 272548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen if (fputc((exif_data_len+2) & 0xff, f) < 0) { 273548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen fprintf(stderr, "Error writing to file %s\n", FILE_NAME); 274548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen goto errout; 275548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen } 276548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Write EXIF data block */ 277548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen if (fwrite(exif_data, exif_data_len, 1, f) != 1) { 278548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen fprintf(stderr, "Error writing to file %s\n", FILE_NAME); 279548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen goto errout; 280548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen } 281548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* Write JPEG image data, skipping the non-EXIF header */ 282548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen if (fwrite(image_jpg+image_data_offset, image_data_len, 1, f) != 1) { 283548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen fprintf(stderr, "Error writing to file %s\n", FILE_NAME); 284548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen goto errout; 285548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen } 286548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen printf("Wrote file %s\n", FILE_NAME); 287548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen rc = 0; 288548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 289548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissenerrout: 290548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen if (fclose(f)) { 291548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen fprintf(stderr, "Error writing to file %s\n", FILE_NAME); 292548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen rc = 1; 293548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen } 294548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen /* The allocator we're using for ExifData is the standard one, so use 295548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen * it directly to free this pointer. 296548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen */ 297548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen free(exif_data); 298548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen exif_data_unref(exif); 299548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen 300548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen return rc; 301548dde4863e9a2315e3f327efe63ff55949addb8Marco Nelissen} 302