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