Sync with trunk head (part 1 of x)
[reactos.git] / dll / 3rdparty / libjpeg / jpegexiforient.c
1 /*
2 * jpegexiforient.c
3 *
4 * This is a utility program to get and set the Exif Orientation Tag.
5 * It can be used together with jpegtran in scripts for automatic
6 * orientation correction of digital camera pictures.
7 *
8 * The Exif orientation value gives the orientation of the camera
9 * relative to the scene when the image was captured. The relation
10 * of the '0th row' and '0th column' to visual position is shown as
11 * below.
12 *
13 * Value | 0th Row | 0th Column
14 * ------+-------------+-----------
15 * 1 | top | left side
16 * 2 | top | rigth side
17 * 3 | bottom | rigth side
18 * 4 | bottom | left side
19 * 5 | left side | top
20 * 6 | right side | top
21 * 7 | right side | bottom
22 * 8 | left side | bottom
23 *
24 * For convenience, here is what the letter F would look like if it were
25 * tagged correctly and displayed by a program that ignores the orientation
26 * tag:
27 *
28 * 1 2 3 4 5 6 7 8
29 *
30 * 888888 888888 88 88 8888888888 88 88 8888888888
31 * 88 88 88 88 88 88 88 88 88 88 88 88
32 * 8888 8888 8888 8888 88 8888888888 8888888888 88
33 * 88 88 88 88
34 * 88 88 888888 888888
35 *
36 */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40
41 static FILE * myfile; /* My JPEG file */
42
43 static unsigned char exif_data[65536L];
44
45 /* Return next input byte, or EOF if no more */
46 #define NEXTBYTE() getc(myfile)
47
48 /* Error exit handler */
49 #define ERREXIT(msg) (exit(0))
50
51 /* Read one byte, testing for EOF */
52 static int
53 read_1_byte (void)
54 {
55 int c;
56
57 c = NEXTBYTE();
58 if (c == EOF)
59 ERREXIT("Premature EOF in JPEG file");
60 return c;
61 }
62
63 /* Read 2 bytes, convert to unsigned int */
64 /* All 2-byte quantities in JPEG markers are MSB first */
65 static unsigned int
66 read_2_bytes (void)
67 {
68 int c1, c2;
69
70 c1 = NEXTBYTE();
71 if (c1 == EOF)
72 ERREXIT("Premature EOF in JPEG file");
73 c2 = NEXTBYTE();
74 if (c2 == EOF)
75 ERREXIT("Premature EOF in JPEG file");
76 return (((unsigned int) c1) << 8) + ((unsigned int) c2);
77 }
78
79 static const char * progname; /* program name for error messages */
80
81 static void
82 usage (FILE *out)
83 /* complain about bad command line */
84 {
85 fprintf(out, "jpegexiforient reads or writes the Exif Orientation Tag ");
86 fprintf(out, "in a JPEG Exif file.\n");
87
88 fprintf(out, "Usage: %s [switches] jpegfile\n", progname);
89
90 fprintf(out, "Switches:\n");
91 fprintf(out, " --help display this help and exit\n");
92 fprintf(out, " --version output version information and exit\n");
93 fprintf(out, " -n Do not output the trailing newline\n");
94 fprintf(out, " -1 .. -8 Set orientation value 1 .. 8\n");
95 }
96
97 /*
98 * The main program.
99 */
100
101 int
102 main (int argc, char **argv)
103 {
104 int n_flag, set_flag;
105 unsigned int length, i;
106 int is_motorola; /* Flag for byte order */
107 unsigned int offset, number_of_tags, tagnum;
108
109 progname = argv[0];
110 if (progname == NULL || progname[0] == 0)
111 progname = "jpegexiforient"; /* in case C library doesn't provide it */
112
113 if (argc < 2) { usage(stderr); return 1; }
114
115 n_flag = 0; set_flag = 0;
116
117 i = 1;
118 while (argv[i][0] == '-') {
119 switch (argv[i][1]) {
120 case '-':
121 switch (argv[i][2]) {
122 case 'h': usage(stdout); return 0;
123 case 'v': fprintf(stdout,"jpegexiforient\n"); return 0;
124 }
125 case 'n':
126 n_flag = 1;
127 break;
128 case '1':
129 case '2':
130 case '3':
131 case '4':
132 case '5':
133 case '6':
134 case '7':
135 case '8':
136 set_flag = argv[i][1] - '0';
137 break;
138 default:
139 usage(stderr); return 1;
140 }
141 if (++i >= argc) { usage(stderr); return 1; }
142 }
143
144 if (set_flag) {
145 if ((myfile = fopen(argv[i], "rb+")) == NULL) {
146 fprintf(stderr, "%s: can't open %s\n", progname, argv[i]);
147 return 0;
148 }
149 } else {
150 if ((myfile = fopen(argv[i], "rb")) == NULL) {
151 fprintf(stderr, "%s: can't open %s\n", progname, argv[i]);
152 return 0;
153 }
154 }
155
156 /* Read File head, check for JPEG SOI + Exif APP1 */
157 for (i = 0; i < 4; i++)
158 exif_data[i] = (unsigned char) read_1_byte();
159 if (exif_data[0] != 0xFF ||
160 exif_data[1] != 0xD8 ||
161 exif_data[2] != 0xFF ||
162 exif_data[3] != 0xE1)
163 return 0;
164
165 /* Get the marker parameter length count */
166 length = read_2_bytes();
167 /* Length includes itself, so must be at least 2 */
168 /* Following Exif data length must be at least 6 */
169 if (length < 8)
170 return 0;
171 length -= 8;
172 /* Read Exif head, check for "Exif" */
173 for (i = 0; i < 6; i++)
174 exif_data[i] = (unsigned char) read_1_byte();
175 if (exif_data[0] != 0x45 ||
176 exif_data[1] != 0x78 ||
177 exif_data[2] != 0x69 ||
178 exif_data[3] != 0x66 ||
179 exif_data[4] != 0 ||
180 exif_data[5] != 0)
181 return 0;
182 /* Read Exif body */
183 for (i = 0; i < length; i++)
184 exif_data[i] = (unsigned char) read_1_byte();
185
186 if (length < 12) return 0; /* Length of an IFD entry */
187
188 /* Discover byte order */
189 if (exif_data[0] == 0x49 && exif_data[1] == 0x49)
190 is_motorola = 0;
191 else if (exif_data[0] == 0x4D && exif_data[1] == 0x4D)
192 is_motorola = 1;
193 else
194 return 0;
195
196 /* Check Tag Mark */
197 if (is_motorola) {
198 if (exif_data[2] != 0) return 0;
199 if (exif_data[3] != 0x2A) return 0;
200 } else {
201 if (exif_data[3] != 0) return 0;
202 if (exif_data[2] != 0x2A) return 0;
203 }
204
205 /* Get first IFD offset (offset to IFD0) */
206 if (is_motorola) {
207 if (exif_data[4] != 0) return 0;
208 if (exif_data[5] != 0) return 0;
209 offset = exif_data[6];
210 offset <<= 8;
211 offset += exif_data[7];
212 } else {
213 if (exif_data[7] != 0) return 0;
214 if (exif_data[6] != 0) return 0;
215 offset = exif_data[5];
216 offset <<= 8;
217 offset += exif_data[4];
218 }
219 if (offset > length - 2) return 0; /* check end of data segment */
220
221 /* Get the number of directory entries contained in this IFD */
222 if (is_motorola) {
223 number_of_tags = exif_data[offset];
224 number_of_tags <<= 8;
225 number_of_tags += exif_data[offset+1];
226 } else {
227 number_of_tags = exif_data[offset+1];
228 number_of_tags <<= 8;
229 number_of_tags += exif_data[offset];
230 }
231 if (number_of_tags == 0) return 0;
232 offset += 2;
233
234 /* Search for Orientation Tag in IFD0 */
235 for (;;) {
236 if (offset > length - 12) return 0; /* check end of data segment */
237 /* Get Tag number */
238 if (is_motorola) {
239 tagnum = exif_data[offset];
240 tagnum <<= 8;
241 tagnum += exif_data[offset+1];
242 } else {
243 tagnum = exif_data[offset+1];
244 tagnum <<= 8;
245 tagnum += exif_data[offset];
246 }
247 if (tagnum == 0x0112) break; /* found Orientation Tag */
248 if (--number_of_tags == 0) return 0;
249 offset += 12;
250 }
251
252 if (set_flag) {
253 /* Set the Orientation value */
254 if (is_motorola) {
255 exif_data[offset+2] = 0; /* Format = unsigned short (2 octets) */
256 exif_data[offset+3] = 3;
257 exif_data[offset+4] = 0; /* Number Of Components = 1 */
258 exif_data[offset+5] = 0;
259 exif_data[offset+6] = 0;
260 exif_data[offset+7] = 1;
261 exif_data[offset+8] = 0;
262 exif_data[offset+9] = (unsigned char)set_flag;
263 exif_data[offset+10] = 0;
264 exif_data[offset+11] = 0;
265 } else {
266 exif_data[offset+2] = 3; /* Format = unsigned short (2 octets) */
267 exif_data[offset+3] = 0;
268 exif_data[offset+4] = 1; /* Number Of Components = 1 */
269 exif_data[offset+5] = 0;
270 exif_data[offset+6] = 0;
271 exif_data[offset+7] = 0;
272 exif_data[offset+8] = (unsigned char)set_flag;
273 exif_data[offset+9] = 0;
274 exif_data[offset+10] = 0;
275 exif_data[offset+11] = 0;
276 }
277 fseek(myfile, (4 + 2 + 6 + 2) + offset, SEEK_SET);
278 fwrite(exif_data + 2 + offset, 1, 10, myfile);
279 } else {
280 /* Get the Orientation value */
281 if (is_motorola) {
282 if (exif_data[offset+8] != 0) return 0;
283 set_flag = exif_data[offset+9];
284 } else {
285 if (exif_data[offset+9] != 0) return 0;
286 set_flag = exif_data[offset+8];
287 }
288 if (set_flag > 8) return 0;
289 }
290
291 /* Write out Orientation value */
292 if (n_flag)
293 printf("%c", '0' + set_flag);
294 else
295 printf("%c\n", '0' + set_flag);
296
297 /* All done. */
298 return 0;
299 }