tizen 2.4 release
[apps/home/attach-panel-gallery.git] / src / util / ge-exif.c
1 /*
2 * Copyright (c) 2000-2015 Samsung Electronics Co., Ltd All Rights Reserved
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 /**
19  * The Exif specification defines an Orientation Tag to indicate the orientation of the
20  * camera relative to the captured scene. This can be used by the camera either to
21  * indicate the orientation automatically by an orientation sensor,
22  * or to allow the user to indicate the orientation manually by a menu switch,
23  * without actually transforming the image data itself.
24  * Here is an explanation given by TsuruZoh Tachibanaya in
25  * his description of the Exif file format:
26  *
27  * The orientation of the camera relative to the scene, when the image was captured.
28  * The relation of the '0th row' and '0th column' to visual position is shown as below.
29  *
30  * Value         0th Row                0th Column
31  *   1    top             left side
32  *   2    top             right side
33  *   3    bottom                  right side
34  *   4    bottom                  left side
35  *   5    left side          top
36  *   6    right side        top
37  *   7    right side        bottom
38  *   8    left side          bottom
39  *
40  * Read this table as follows (thanks to Peter Nielsen for clarifying this - see also below):
41  * Entry #6 in the table says that the 0th row in the stored image is the right side of
42  * the captured scene, and the 0th column in the stored image is the top side of
43  * the captured scene.
44  *
45  * Here is another description given by Adam M. Costello:
46  *
47  * For convenience, here is what the letter F would look like if it were tagged correctly
48  * and displayed by a program that ignores the orientation tag
49  * (thus showing the stored image):
50  *
51  *       1             2         3      4            5                 6                   7                  8
52  *
53  *  888888  888888       88    88      8888888888  88                             88  8888888888
54  *  88               88        88    88      88  88          88  88                  88  88          88  88
55  *  8888        8888     8888   8888   88                8888888888  8888888888               88
56  *  88               88        88    88
57  *  88               88  888888   888888
58 */
59
60 #ifdef _USE_ROTATE_BG_GE
61
62 #include <stdlib.h>
63 #include <string.h>
64 #include <time.h>
65 #include <Elementary.h>
66 #include "ge-exif.h"
67 #include "ge-debug.h"
68 #include "ge-data-type.h"
69
70 #define GE_EXIF_BUF_LEN_MAX 65536L
71 #define GE_EXIF_BUF_TIME_LEN_MAX 20
72 #define GE_EXIF_DEFAULT_YEAR 1900
73
74 #define GE_EXIF_SOI 0xD8
75 #define GE_EXIF_TAG 0xFF
76 #define GE_EXIF_APP0 0xE0
77 #define GE_EXIF_APP1 0xE1
78 #define GE_EXIF_JFIF_00 0x00
79 #define GE_EXIF_JFIF_01 0x01
80 #define GE_EXIF_JFIF_02 0x02
81
82 #define GE_EXIF_IFD_DATA_FORMAT_UNSIGNED_BYTE 1
83 #define GE_EXIF_IFD_DATA_FORMAT_ASCII_STRINGS 1
84 #define GE_EXIF_IFD_DATA_FORMAT_UNSIGNED_SHORT 2
85 #define GE_EXIF_IFD_DATA_FORMAT_UNSIGNED_LONG 4
86 #define GE_EXIF_IFD_DATA_FORMAT_UNSIGNED_RATIONAL 8
87 #define GE_EXIF_IFD_DATA_FORMAT_SIGNED_BYTE 1
88 #define GE_EXIF_IFD_DATA_FORMAT_UNDEFINED 1
89 #define GE_EXIF_IFD_DATA_FORMAT_SIGNED_SHORT 2
90 #define GE_EXIF_IFD_DATA_FORMAT_SIGNED_LONG 4
91 #define GE_EXIF_IFD_DATA_FORMAT_SIGNED_RATIONAL 8
92 #define GE_EXIF_IFD_DATA_FORMAT_SIGNED_FLOAT 4
93 #define GE_EXIF_IFD_DATA_FORMAT_DOUBLE_FLOAT 8
94
95 #define GE_EXI_TMP_JPEG_FILE "/opt/usr/apps/org.tizen.gallery/data/.gallery_tmp_write_exif.jpg"
96
97 /* Read one byte, testing for EOF */
98 static int __ge_exif_read_1_byte(FILE *fd)
99 {
100         int c = 0;
101
102         /* Return next input byte, or EOF if no more */
103         c = getc(fd);
104         if (c == EOF) {
105                 ge_dbgE("Premature EOF in JPEG file!");
106                 return -1;
107         }
108
109         return c;
110 }
111
112 /* Read 2 bytes, convert to unsigned int */
113 /* All 2-byte quantities in JPEG markers are MSB first */
114 static int __ge_exif_read_2_bytes(FILE *fd, unsigned int *len)
115 {
116         int c1 = 0;
117         int c2 = 0;
118
119         /* Return next input byte, or EOF if no more */
120         c1 = getc(fd);
121         if (c1 == EOF) {
122                 ge_dbgE("Premature EOF in JPEG file!");
123                 return -1;
124         }
125
126         /* Return next input byte, or EOF if no more */
127         c2 = getc(fd);
128         if (c2 == EOF) {
129                 ge_dbgE("Premature EOF in JPEG file!");
130                 return -1;
131         }
132
133         if (len)
134                 *len = (((unsigned int)c1) << 8) + ((unsigned int)c2);
135
136         return 0;
137 }
138
139 static int __ge_exif_rw_jfif(FILE *fd, char *file_path,
140                              unsigned int *orientation)
141 {
142         GE_CHECK_VAL(fd, -1);
143         GE_CHECK_VAL(file_path, -1);
144         GE_CHECK_VAL(orientation, -1);
145         unsigned char tmp[GE_EXIF_BUF_LEN_MAX] = { 0, };
146         int i = 0;
147         unsigned int length = 0;
148         int tmp_exif = -1;
149         bool is_motorola = false; /* Flag for byte order */
150         unsigned int offset = 0;
151         int ret = -1;
152         /*unsigned char version = 0x00; */
153
154         if (__ge_exif_read_2_bytes(fd, &length) < 0)
155                 goto GE_EXIF_FAILED;
156         ge_dbg("length: %d", length);
157
158         for (i = 0; i < 5; i++) {
159                 tmp_exif = __ge_exif_read_1_byte(fd);
160                 if (tmp_exif < 0)
161                         goto GE_EXIF_FAILED;
162                 tmp[i] = (unsigned char)tmp_exif;
163         }
164
165         /* JFIF0 */
166         if (tmp[0] != 0x4A || tmp[1] != 0x46 || tmp[2] != 0x49 ||
167             tmp[3] != 0x46 || tmp[4] != 0x00) {
168                 ge_dbgE("Not met Jfif!");
169                 goto GE_EXIF_FAILED;
170         }
171
172         for (i = 0; i < 2; i++) {
173                 tmp_exif = __ge_exif_read_1_byte(fd);
174                 if (tmp_exif < 0)
175                         goto GE_EXIF_FAILED;
176                 tmp[i] = (unsigned char)tmp_exif;
177         }
178
179         /* Check JFIF version */
180         if (tmp[0] == 0x01 && tmp[1] == GE_EXIF_JFIF_00) {
181                 ge_dbg("Jfif 1.00");
182         } else if (tmp[0] == 0x01 && tmp[1] == GE_EXIF_JFIF_01) {
183                 ge_dbg("Jfif 1.01");
184         } else if (tmp[0] == 0x01 && tmp[1] == GE_EXIF_JFIF_02) {
185                 ge_dbg("Jfif 1.02");
186         } else {
187                 ge_dbgE("Unknow Jfif version[%d.%d]!", tmp[0], tmp[1]);
188                 goto GE_EXIF_FAILED;
189         }
190
191         /* Save version */
192         /*version = tmp[1]; */
193
194         /* Find APP1 */
195         bool b_tag_ff = false;
196         while(1) {
197                 tmp_exif = __ge_exif_read_1_byte(fd);
198                 if (tmp_exif < 0)
199                         goto GE_EXIF_FAILED;
200
201                 tmp[0] = (unsigned char)tmp_exif;
202
203                 ge_dbg("- %02X", tmp[0]);
204                 if (!b_tag_ff) {
205                         /* Get first tag */
206                         if (tmp[0] == GE_EXIF_TAG) {
207                                 ge_dbgW("0xFF!");
208                                 b_tag_ff = true;
209                         }
210                         continue;
211                 }
212
213                 /* Get APP1 */
214                 if (tmp[0] == GE_EXIF_APP1) {
215                         ge_dbgW("Exif in APP1!");
216                         break;
217                 }
218
219                 ge_dbgW("No Exif in APP1!");
220
221                 /* Close file */
222                 fclose(fd);
223                 /* Normal orientation = 0degree = 1 */
224                 *orientation = 1;
225                 return 0;
226
227         }
228
229         /* Find Exif */
230         while(1) {
231                 tmp_exif = __ge_exif_read_1_byte(fd);
232                 if (tmp_exif < 0)
233                         goto GE_EXIF_FAILED;
234
235                 tmp[0] = (unsigned char)tmp_exif;
236                 if (tmp[0] != 0x45)
237                         continue;
238
239                 for (i = 0; i < 5; i++) {
240                         tmp_exif = __ge_exif_read_1_byte(fd);
241                         if (tmp_exif < 0)
242                                 goto GE_EXIF_FAILED;
243
244                         tmp[i] = (unsigned char)tmp_exif;
245                         ge_dbg("- %02X", tmp[i]);
246                 }
247                 if (tmp[0] == 0x78 && tmp[1] == 0x69 && tmp[2] == 0x66 &&
248                     tmp[3] == 0x00 && tmp[4] == 0x00) {
249                         ge_dbgW("Met Exif!");
250                         break;
251                 } else {
252                         ge_dbgW("Not met Exif!");
253                         goto GE_EXIF_FAILED;
254                 }
255         }
256
257         /* Read Exif body */
258         for (i = 0; i < 4; i++) {
259                 tmp_exif = __ge_exif_read_1_byte(fd);
260                 if (tmp_exif < 0)
261                         goto GE_EXIF_FAILED;
262                 tmp[i] = (unsigned char)tmp_exif;
263         }
264
265         /* Check byte order and Tag Mark , "II(0x4949)" or "MM(0x4d4d)" */
266         if (tmp[0] == 0x49 && tmp[1] == 0x49 && tmp[2] == 0x2A &&
267             tmp[3] == 0x00) {
268                 ge_dbg("Intel");
269                 is_motorola = false;
270         } else if (tmp[0] == 0x4D && tmp[1] == 0x4D && tmp[2] == 0x00 &&
271                    tmp[3] == 0x2A) {
272                 ge_dbg("Motorola");
273                 is_motorola = true;
274         } else {
275                 goto GE_EXIF_FAILED;
276         }
277
278         for (i = 0; i < 4; i++) {
279                 tmp_exif = __ge_exif_read_1_byte(fd);
280                 if (tmp_exif < 0)
281                         goto GE_EXIF_FAILED;
282
283                 tmp[i] = (unsigned char)tmp_exif;
284                 ge_dbg("- %02X", tmp[i]);
285         }
286
287         /* Get first IFD offset (offset to IFD0) , MM-08000000, II-00000008 */
288         if (is_motorola) {
289                 if (tmp[0] != 0 && tmp[1] != 0)
290                         goto GE_EXIF_FAILED;
291                 offset = tmp[2];
292                 offset <<= 8;
293                 offset += tmp[3];
294         } else {
295                 if (tmp[3] != 0 && tmp[2] != 0)
296                         goto GE_EXIF_FAILED;
297                 offset = tmp[1];
298                 offset <<= 8;
299                 offset += tmp[0];
300         }
301         ge_dbg("offset: %d", offset);
302
303         /* IFD: Image File Directory */
304         /* Get the number of directory entries contained in this IFD, - 2 bytes, EE */
305         unsigned int tags_cnt = 0;
306         for (i = 0; i < 2; i++) {
307                 tmp_exif = __ge_exif_read_1_byte(fd);
308                 if (tmp_exif < 0)
309                         goto GE_EXIF_FAILED;
310
311                 tmp[i] = (unsigned char)tmp_exif;
312         }
313         if (is_motorola) {
314                 tags_cnt = tmp[0];
315                 tags_cnt <<= 8;
316                 tags_cnt += tmp[1];
317         } else {
318                 tags_cnt = tmp[1];
319                 tags_cnt <<= 8;
320                 tags_cnt += tmp[0];
321         }
322         ge_dbg("tags_cnt: %d", tags_cnt);
323         if (tags_cnt == 0) {
324                 ge_dbgE("tags_cnt == 0 - 2");
325                 goto GE_EXIF_FAILED;
326         }
327
328         /* Search for Orientation Tag in IFD0 */
329         unsigned int tag_num = 0;
330         while (1) {
331                 /* Every directory entry size is 12 */
332                 for (i = 0; i < 12; i++) {
333                         tmp_exif = __ge_exif_read_1_byte(fd);
334                         if (tmp_exif < 0)
335                                 goto GE_EXIF_FAILED;
336
337                         tmp[i] = (unsigned char)tmp_exif;
338                 }
339                 /* Get Tag number */
340                 if (is_motorola) {
341                         tag_num = tmp[0];
342                         tag_num <<= 8;
343                         tag_num += tmp[1];
344                 } else {
345                         tag_num = tmp[1];
346                         tag_num <<= 8;
347                         tag_num += tmp[0];
348                 }
349                 /* found Orientation Tag */
350                 if (tag_num == 0x0112) {
351                         ge_dbgW("Found orientation tag!");
352                         break;
353                 }
354                 if (--tags_cnt == 0) {
355                         ge_dbgW("tags_cnt == 0, no found orientation tag!");
356                         /* Normal orientation = 0degree = 1 */
357                         *orientation = 1;
358                         ret = 0;
359                         goto GE_EXIF_FAILED;
360                 }
361         }
362
363         /* |TT|ff|NNNN|DDDD|  ---  TT - 2 bytes, tag NO. ;ff - 2 bytes, data format
364              NNNN - 4 bytes, entry count;  DDDD - 4 bytes Data value */
365         /* Get the Orientation value */
366         if (is_motorola) {
367                 if (tmp[8] != 0) {
368                         ge_dbgE("tmp[8] != 0");
369                         goto GE_EXIF_FAILED;
370                 }
371                 *orientation = (unsigned int)tmp[9];
372         } else {
373                 if (tmp[9] != 0) {
374                         ge_dbgE("tmp[9] != 0");
375                         goto GE_EXIF_FAILED;
376                 }
377                 *orientation = (unsigned int)tmp[8];
378         }
379         if (*orientation > 8) {
380                 ge_dbgE("*orient > 8");
381                 goto GE_EXIF_FAILED;
382         }
383         ge_dbg("Read: %d", *orientation);
384         ret = 0;
385
386  GE_EXIF_FAILED:
387
388         fclose(fd);
389         ge_dbg("All done");
390         return ret;
391 }
392
393 static int __ge_exif_rw_orient(char *file_path, unsigned int *orient)
394 {
395         GE_CHECK_VAL(file_path, -1);
396         unsigned int length = 0;
397         unsigned int i = 0;
398         bool is_motorola = false; /* Flag for byte order */
399         unsigned int offset = 0;
400         unsigned int tags_cnt = 0;
401         unsigned int tag_num = 0;
402         int tmp_exif = -1;
403         unsigned char exif_data[GE_EXIF_BUF_LEN_MAX] = { 0, };
404         FILE *fd = NULL;
405         int ret = -1;
406
407         if ((fd = fopen(file_path, "rb")) == NULL) {
408                 ge_sdbgE("Can't open %s!", file_path);
409                 return -1;
410         }
411
412
413         /* Read File head, check for JPEG SOI + Exif APP1 */
414         for (i = 0; i < 4; i++) {
415                 tmp_exif = __ge_exif_read_1_byte(fd);
416                 if (tmp_exif < 0)
417                         goto GE_EXIF_FAILED;
418
419                 exif_data[i] = (unsigned char)tmp_exif;
420         }
421
422         if (exif_data[0] == GE_EXIF_TAG && exif_data[1] == GE_EXIF_SOI) {
423                 ge_dbg("JPEG file");
424         } else {
425                 ge_dbgE("Not a JPEG file!");
426                 goto GE_EXIF_FAILED;
427         }
428
429         if (exif_data[2] == GE_EXIF_TAG && exif_data[3] == GE_EXIF_APP1) {
430                 ge_dbgW("Exif in APP1!");
431         } else if (exif_data[2] == GE_EXIF_TAG &&
432                    exif_data[3] == GE_EXIF_APP0) {
433                 ge_dbgW("Jfif in APP0!");
434                 int ret = __ge_exif_rw_jfif(fd, file_path, orient);
435                 return ret;
436         } else {
437                 ge_dbgE("Not a Exif in APP1 or Jiff in APP2[%d]!", exif_data[3]);
438                 goto GE_EXIF_FAILED;
439         }
440
441         /* Get the marker parameter length count */
442         if (__ge_exif_read_2_bytes(fd, &length) < 0)
443                 goto GE_EXIF_FAILED;
444         ge_dbg("length: %d", length);
445         /* Length includes itself, so must be at least 2
446             Following Exif data length must be at least 6 */
447         if (length < 8) {
448                 ge_dbgE("length < 8");
449                 goto GE_EXIF_FAILED;
450         }
451         length -= 8;
452
453          /* Length of an IFD entry */
454         if (length < 12) {
455                 ge_dbgE("length < 12");
456                 goto GE_EXIF_FAILED;
457         }
458
459         /* Read Exif head, check for "Exif" */
460         for (i = 0; i < 6; i++) {
461                 tmp_exif = __ge_exif_read_1_byte(fd);
462                 if (tmp_exif < 0)
463                         goto GE_EXIF_FAILED;
464
465                 exif_data[i] = (unsigned char)tmp_exif;
466                 ge_dbg("- %02X", exif_data[i]);
467         }
468
469         if (exif_data[0] != 0x45 || exif_data[1] != 0x78 ||
470             exif_data[2] != 0x69 || exif_data[3] != 0x66 ||
471             exif_data[4] != 0x00 || exif_data[5] != 0x00) {
472                 ge_dbgE("Not met Exif!");
473                 goto GE_EXIF_FAILED;
474         }
475
476         /* Read Exif body */
477         for (i = 0; i < length; i++) {
478                 tmp_exif = __ge_exif_read_1_byte(fd);
479                 if (tmp_exif < 0)
480                         goto GE_EXIF_FAILED;
481                 exif_data[i] = (unsigned char)tmp_exif;
482         }
483
484         /* Check byte order and Tag Mark , "II(0x4949)" or "MM(0x4d4d)" */
485         if (exif_data[0] == 0x49 && exif_data[1] == 0x49 &&
486             exif_data[2] == 0x2A && exif_data[3] == 0x00) {
487                 ge_dbg("Intel");
488                 is_motorola = false;
489         } else if (exif_data[0] == 0x4D && exif_data[1] == 0x4D &&
490                  exif_data[2] == 0x00 && exif_data[3] == 0x2A) {
491                 ge_dbg("Motorola");
492                 is_motorola = true;
493         } else {
494                 goto GE_EXIF_FAILED;
495         }
496
497         /* Get first IFD offset (offset to IFD0) , MM-00000008, II-08000000 */
498         if (is_motorola) {
499                 if (exif_data[4] != 0 && exif_data[5] != 0)
500                         goto GE_EXIF_FAILED;
501                 offset = exif_data[6];
502                 offset <<= 8;
503                 offset += exif_data[7];
504         } else {
505                 if (exif_data[7] != 0 && exif_data[6] != 0)
506                         goto GE_EXIF_FAILED;
507                 offset = exif_data[5];
508                 offset <<= 8;
509                 offset += exif_data[4];
510         }
511         /* check end of data segment */
512         if (offset > length - 2) {
513                 ge_dbgE("offset > length - 2");
514                 goto GE_EXIF_FAILED;
515         }
516
517         /* IFD: Image File Directory */
518         /* Get the number of directory entries contained in this IFD, - EEEE */
519         if (is_motorola) {
520                 tags_cnt = exif_data[offset];
521                 tags_cnt <<= 8;
522                 tags_cnt += exif_data[offset+1];
523         } else {
524                 tags_cnt = exif_data[offset+1];
525                 tags_cnt <<= 8;
526                 tags_cnt += exif_data[offset];
527         }
528         if (tags_cnt == 0) {
529                 ge_dbgE("tags_cnt == 0 - 2");
530                 goto GE_EXIF_FAILED;
531         }
532         offset += 2;
533
534         /* check end of data segment */
535         if (offset > length - 12) {
536                 ge_dbgE("offset > length - 12");
537                 goto GE_EXIF_FAILED;
538         }
539
540         /* Search for Orientation Tag in IFD0 */
541         while (1) {
542                 /* Get Tag number */
543                 if (is_motorola) {
544                         tag_num = exif_data[offset];
545                         tag_num <<= 8;
546                         tag_num += exif_data[offset+1];
547                 } else {
548                         tag_num = exif_data[offset+1];
549                         tag_num <<= 8;
550                         tag_num += exif_data[offset];
551                 }
552                 /* found Orientation Tag */
553                 if (tag_num == 0x0112) {
554                         ge_dbgW("Found orientation tag!");
555                         break;
556                 }
557                 if (--tags_cnt == 0) {
558                         ge_dbgW("tags_cnt == 0, no found orientation tag!");
559                         /* Normal orientation = 0degree = 1 */
560                         *orient = 1;
561                         ret = 0;
562                         goto GE_EXIF_FAILED;
563                 }
564
565                 /* Every directory entry size is 12 */
566                 offset += 12;
567         }
568
569         /* Get the Orientation value */
570         if (is_motorola) {
571                 if (exif_data[offset+8] != 0) {
572                         ge_dbgE("exif_data[offset+8] != 0");
573                         goto GE_EXIF_FAILED;
574                 }
575                 *orient = (unsigned int)exif_data[offset+9];
576         } else {
577                 if (exif_data[offset+9] != 0) {
578                         ge_dbgE("exif_data[offset+9] != 0");
579                         goto GE_EXIF_FAILED;
580                 }
581                 *orient = (unsigned int)exif_data[offset+8];
582         }
583         if (*orient > 8) {
584                 ge_dbgE("*orient > 8");
585                 goto GE_EXIF_FAILED;
586         }
587         ge_dbg("Read: %d", *orient);
588
589         ret = 0;
590
591  GE_EXIF_FAILED:
592
593         fclose(fd);
594         ge_dbg("All done");
595         return ret;
596 }
597
598 int _ge_exif_get_orientation(char *file_path, unsigned int *orientation)
599 {
600         GE_CHECK_VAL(orientation, -1);
601         GE_CHECK_VAL(file_path, -1);
602         ge_sdbg("file_path: %s", file_path);
603
604         return __ge_exif_rw_orient(file_path, orientation);
605 }
606
607 #endif
608