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