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.
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
13 * Value | 0th Row | 0th Column
14 * ------+-------------+-----------
16 * 2 | top | rigth side
17 * 3 | bottom | rigth side
18 * 4 | bottom | left side
20 * 6 | right side | top
21 * 7 | right side | bottom
22 * 8 | left side | bottom
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
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
41 static FILE * myfile
; /* My JPEG file */
43 static unsigned char exif_data
[65536L];
45 /* Return next input byte, or EOF if no more */
46 #define NEXTBYTE() getc(myfile)
48 /* Error exit handler */
49 #define ERREXIT(msg) (exit(0))
51 /* Read one byte, testing for EOF */
59 ERREXIT("Premature EOF in JPEG file");
63 /* Read 2 bytes, convert to unsigned int */
64 /* All 2-byte quantities in JPEG markers are MSB first */
72 ERREXIT("Premature EOF in JPEG file");
75 ERREXIT("Premature EOF in JPEG file");
76 return (((unsigned int) c1
) << 8) + ((unsigned int) c2
);
79 static const char * progname
; /* program name for error messages */
83 /* complain about bad command line */
85 fprintf(out
, "jpegexiforient reads or writes the Exif Orientation Tag ");
86 fprintf(out
, "in a JPEG Exif file.\n");
88 fprintf(out
, "Usage: %s [switches] jpegfile\n", progname
);
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");
102 main (int argc
, char **argv
)
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
;
110 if (progname
== NULL
|| progname
[0] == 0)
111 progname
= "jpegexiforient"; /* in case C library doesn't provide it */
113 if (argc
< 2) { usage(stderr
); return 1; }
115 n_flag
= 0; set_flag
= 0;
118 while (argv
[i
][0] == '-') {
119 switch (argv
[i
][1]) {
121 switch (argv
[i
][2]) {
122 case 'h': usage(stdout
); return 0;
123 case 'v': fprintf(stdout
,"jpegexiforient\n"); return 0;
136 set_flag
= argv
[i
][1] - '0';
139 usage(stderr
); return 1;
141 if (++i
>= argc
) { usage(stderr
); return 1; }
145 if ((myfile
= fopen(argv
[i
], "rb+")) == NULL
) {
146 fprintf(stderr
, "%s: can't open %s\n", progname
, argv
[i
]);
150 if ((myfile
= fopen(argv
[i
], "rb")) == NULL
) {
151 fprintf(stderr
, "%s: can't open %s\n", progname
, argv
[i
]);
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)
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 */
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 ||
183 for (i
= 0; i
< length
; i
++)
184 exif_data
[i
] = (unsigned char) read_1_byte();
186 if (length
< 12) return 0; /* Length of an IFD entry */
188 /* Discover byte order */
189 if (exif_data
[0] == 0x49 && exif_data
[1] == 0x49)
191 else if (exif_data
[0] == 0x4D && exif_data
[1] == 0x4D)
198 if (exif_data
[2] != 0) return 0;
199 if (exif_data
[3] != 0x2A) return 0;
201 if (exif_data
[3] != 0) return 0;
202 if (exif_data
[2] != 0x2A) return 0;
205 /* Get first IFD offset (offset to IFD0) */
207 if (exif_data
[4] != 0) return 0;
208 if (exif_data
[5] != 0) return 0;
209 offset
= exif_data
[6];
211 offset
+= exif_data
[7];
213 if (exif_data
[7] != 0) return 0;
214 if (exif_data
[6] != 0) return 0;
215 offset
= exif_data
[5];
217 offset
+= exif_data
[4];
219 if (offset
> length
- 2) return 0; /* check end of data segment */
221 /* Get the number of directory entries contained in this IFD */
223 number_of_tags
= exif_data
[offset
];
224 number_of_tags
<<= 8;
225 number_of_tags
+= exif_data
[offset
+1];
227 number_of_tags
= exif_data
[offset
+1];
228 number_of_tags
<<= 8;
229 number_of_tags
+= exif_data
[offset
];
231 if (number_of_tags
== 0) return 0;
234 /* Search for Orientation Tag in IFD0 */
236 if (offset
> length
- 12) return 0; /* check end of data segment */
239 tagnum
= exif_data
[offset
];
241 tagnum
+= exif_data
[offset
+1];
243 tagnum
= exif_data
[offset
+1];
245 tagnum
+= exif_data
[offset
];
247 if (tagnum
== 0x0112) break; /* found Orientation Tag */
248 if (--number_of_tags
== 0) return 0;
253 /* Set the Orientation value */
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;
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;
277 fseek(myfile
, (4 + 2 + 6 + 2) + offset
, SEEK_SET
);
278 fwrite(exif_data
+ 2 + offset
, 1, 10, myfile
);
280 /* Get the Orientation value */
282 if (exif_data
[offset
+8] != 0) return 0;
283 set_flag
= exif_data
[offset
+9];
285 if (exif_data
[offset
+9] != 0) return 0;
286 set_flag
= exif_data
[offset
+8];
288 if (set_flag
> 8) return 0;
291 /* Write out Orientation value */
293 printf("%c", '0' + set_flag
);
295 printf("%c\n", '0' + set_flag
);