2 * Copyright (c) 2000-2015 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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:
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.
30 * Value 0th Row 0th Column
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
45 * Here is another description given by Adam M. Costello:
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):
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
60 #ifdef _USE_ROTATE_BG_GE
65 #include <Elementary.h>
68 #include "ge-data-type.h"
70 #define GE_EXIF_BUF_LEN_MAX 65536L
71 #define GE_EXIF_BUF_TIME_LEN_MAX 20
72 #define GE_EXIF_DEFAULT_YEAR 1900
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
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
95 #define GE_EXI_TMP_JPEG_FILE "/opt/usr/apps/org.tizen.gallery/data/.gallery_tmp_write_exif.jpg"
97 /* Read one byte, testing for EOF */
98 static int __ge_exif_read_1_byte(FILE *fd)
102 /* Return next input byte, or EOF if no more */
105 ge_dbgE("Premature EOF in JPEG file!");
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)
119 /* Return next input byte, or EOF if no more */
122 ge_dbgE("Premature EOF in JPEG file!");
126 /* Return next input byte, or EOF if no more */
129 ge_dbgE("Premature EOF in JPEG file!");
134 *len = (((unsigned int)c1) << 8) + ((unsigned int)c2);
139 static int __ge_exif_rw_jfif(FILE *fd, char *file_path,
140 unsigned int *orientation)
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, };
147 unsigned int length = 0;
149 bool is_motorola = false; /* Flag for byte order */
150 unsigned int offset = 0;
152 /*unsigned char version = 0x00; */
154 if (__ge_exif_read_2_bytes(fd, &length) < 0)
156 ge_dbg("length: %d", length);
158 for (i = 0; i < 5; i++) {
159 tmp_exif = __ge_exif_read_1_byte(fd);
162 tmp[i] = (unsigned char)tmp_exif;
166 if (tmp[0] != 0x4A || tmp[1] != 0x46 || tmp[2] != 0x49 ||
167 tmp[3] != 0x46 || tmp[4] != 0x00) {
168 ge_dbgE("Not met Jfif!");
172 for (i = 0; i < 2; i++) {
173 tmp_exif = __ge_exif_read_1_byte(fd);
176 tmp[i] = (unsigned char)tmp_exif;
179 /* Check JFIF version */
180 if (tmp[0] == 0x01 && tmp[1] == GE_EXIF_JFIF_00) {
182 } else if (tmp[0] == 0x01 && tmp[1] == GE_EXIF_JFIF_01) {
184 } else if (tmp[0] == 0x01 && tmp[1] == GE_EXIF_JFIF_02) {
187 ge_dbgE("Unknow Jfif version[%d.%d]!", tmp[0], tmp[1]);
192 /*version = tmp[1]; */
195 bool b_tag_ff = false;
197 tmp_exif = __ge_exif_read_1_byte(fd);
201 tmp[0] = (unsigned char)tmp_exif;
203 ge_dbg("- %02X", tmp[0]);
206 if (tmp[0] == GE_EXIF_TAG) {
214 if (tmp[0] == GE_EXIF_APP1) {
215 ge_dbgW("Exif in APP1!");
219 ge_dbgW("No Exif in APP1!");
223 /* Normal orientation = 0degree = 1 */
231 tmp_exif = __ge_exif_read_1_byte(fd);
235 tmp[0] = (unsigned char)tmp_exif;
239 for (i = 0; i < 5; i++) {
240 tmp_exif = __ge_exif_read_1_byte(fd);
244 tmp[i] = (unsigned char)tmp_exif;
245 ge_dbg("- %02X", tmp[i]);
247 if (tmp[0] == 0x78 && tmp[1] == 0x69 && tmp[2] == 0x66 &&
248 tmp[3] == 0x00 && tmp[4] == 0x00) {
249 ge_dbgW("Met Exif!");
252 ge_dbgW("Not met Exif!");
258 for (i = 0; i < 4; i++) {
259 tmp_exif = __ge_exif_read_1_byte(fd);
262 tmp[i] = (unsigned char)tmp_exif;
265 /* Check byte order and Tag Mark , "II(0x4949)" or "MM(0x4d4d)" */
266 if (tmp[0] == 0x49 && tmp[1] == 0x49 && tmp[2] == 0x2A &&
270 } else if (tmp[0] == 0x4D && tmp[1] == 0x4D && tmp[2] == 0x00 &&
278 for (i = 0; i < 4; i++) {
279 tmp_exif = __ge_exif_read_1_byte(fd);
283 tmp[i] = (unsigned char)tmp_exif;
284 ge_dbg("- %02X", tmp[i]);
287 /* Get first IFD offset (offset to IFD0) , MM-08000000, II-00000008 */
289 if (tmp[0] != 0 && tmp[1] != 0)
295 if (tmp[3] != 0 && tmp[2] != 0)
301 ge_dbg("offset: %d", offset);
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);
311 tmp[i] = (unsigned char)tmp_exif;
322 ge_dbg("tags_cnt: %d", tags_cnt);
324 ge_dbgE("tags_cnt == 0 - 2");
328 /* Search for Orientation Tag in IFD0 */
329 unsigned int tag_num = 0;
331 /* Every directory entry size is 12 */
332 for (i = 0; i < 12; i++) {
333 tmp_exif = __ge_exif_read_1_byte(fd);
337 tmp[i] = (unsigned char)tmp_exif;
349 /* found Orientation Tag */
350 if (tag_num == 0x0112) {
351 ge_dbgW("Found orientation tag!");
354 if (--tags_cnt == 0) {
355 ge_dbgW("tags_cnt == 0, no found orientation tag!");
356 /* Normal orientation = 0degree = 1 */
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 */
368 ge_dbgE("tmp[8] != 0");
371 *orientation = (unsigned int)tmp[9];
374 ge_dbgE("tmp[9] != 0");
377 *orientation = (unsigned int)tmp[8];
379 if (*orientation > 8) {
380 ge_dbgE("*orient > 8");
383 ge_dbg("Read: %d", *orientation);
393 static int __ge_exif_rw_orient(char *file_path, unsigned int *orient)
395 GE_CHECK_VAL(file_path, -1);
396 unsigned int length = 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;
403 unsigned char exif_data[GE_EXIF_BUF_LEN_MAX] = { 0, };
407 if ((fd = fopen(file_path, "rb")) == NULL) {
408 ge_sdbgE("Can't open %s!", file_path);
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);
419 exif_data[i] = (unsigned char)tmp_exif;
422 if (exif_data[0] == GE_EXIF_TAG && exif_data[1] == GE_EXIF_SOI) {
425 ge_dbgE("Not a JPEG file!");
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);
437 ge_dbgE("Not a Exif in APP1 or Jiff in APP2[%d]!", exif_data[3]);
441 /* Get the marker parameter length count */
442 if (__ge_exif_read_2_bytes(fd, &length) < 0)
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 */
448 ge_dbgE("length < 8");
453 /* Length of an IFD entry */
455 ge_dbgE("length < 12");
459 /* Read Exif head, check for "Exif" */
460 for (i = 0; i < 6; i++) {
461 tmp_exif = __ge_exif_read_1_byte(fd);
465 exif_data[i] = (unsigned char)tmp_exif;
466 ge_dbg("- %02X", exif_data[i]);
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!");
477 for (i = 0; i < length; i++) {
478 tmp_exif = __ge_exif_read_1_byte(fd);
481 exif_data[i] = (unsigned char)tmp_exif;
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) {
489 } else if (exif_data[0] == 0x4D && exif_data[1] == 0x4D &&
490 exif_data[2] == 0x00 && exif_data[3] == 0x2A) {
497 /* Get first IFD offset (offset to IFD0) , MM-00000008, II-08000000 */
499 if (exif_data[4] != 0 && exif_data[5] != 0)
501 offset = exif_data[6];
503 offset += exif_data[7];
505 if (exif_data[7] != 0 && exif_data[6] != 0)
507 offset = exif_data[5];
509 offset += exif_data[4];
511 /* check end of data segment */
512 if (offset > length - 2) {
513 ge_dbgE("offset > length - 2");
517 /* IFD: Image File Directory */
518 /* Get the number of directory entries contained in this IFD, - EEEE */
520 tags_cnt = exif_data[offset];
522 tags_cnt += exif_data[offset+1];
524 tags_cnt = exif_data[offset+1];
526 tags_cnt += exif_data[offset];
529 ge_dbgE("tags_cnt == 0 - 2");
534 /* check end of data segment */
535 if (offset > length - 12) {
536 ge_dbgE("offset > length - 12");
540 /* Search for Orientation Tag in IFD0 */
544 tag_num = exif_data[offset];
546 tag_num += exif_data[offset+1];
548 tag_num = exif_data[offset+1];
550 tag_num += exif_data[offset];
552 /* found Orientation Tag */
553 if (tag_num == 0x0112) {
554 ge_dbgW("Found orientation tag!");
557 if (--tags_cnt == 0) {
558 ge_dbgW("tags_cnt == 0, no found orientation tag!");
559 /* Normal orientation = 0degree = 1 */
565 /* Every directory entry size is 12 */
569 /* Get the Orientation value */
571 if (exif_data[offset+8] != 0) {
572 ge_dbgE("exif_data[offset+8] != 0");
575 *orient = (unsigned int)exif_data[offset+9];
577 if (exif_data[offset+9] != 0) {
578 ge_dbgE("exif_data[offset+9] != 0");
581 *orient = (unsigned int)exif_data[offset+8];
584 ge_dbgE("*orient > 8");
587 ge_dbg("Read: %d", *orient);
598 int _ge_exif_get_orientation(char *file_path, unsigned int *orientation)
600 GE_CHECK_VAL(orientation, -1);
601 GE_CHECK_VAL(file_path, -1);
602 ge_sdbg("file_path: %s", file_path);
604 return __ge_exif_rw_orient(file_path, orientation);