1 /**
2 * Copyright 2020 Huawei Technologies Co., Ltd
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 #include "minddata/dataset/kernels/image/exif_utils.h"
18
19 #include <algorithm>
20 #include <cstdint>
21
22 #define UNKNOW_ORIENTATION 0
23
24 namespace mindspore {
25 namespace dataset {
26
27 template <typename T>
28 T parse_bytes(const uint8_t *buf, bool intel_align);
29
30 template <>
parse_bytes(const uint8_t * buf,bool intel_align)31 uint8_t parse_bytes(const uint8_t *buf, bool intel_align) {
32 return *buf;
33 }
34
35 template <>
parse_bytes(const uint8_t * buf,bool intel_align)36 uint16_t parse_bytes(const uint8_t *buf, bool intel_align) {
37 if (buf == nullptr) {
38 return 0;
39 }
40
41 uint16_t res = 0;
42 if (intel_align) {
43 res = (static_cast<uint16_t>(buf[1]) << 8) | buf[0];
44 } else {
45 res = (static_cast<uint16_t>(buf[0]) << 8) | buf[1];
46 }
47 return res;
48 }
49
50 template <>
parse_bytes(const uint8_t * buf,bool intel_align)51 uint32_t parse_bytes(const uint8_t *buf, bool intel_align) {
52 if (buf == nullptr) {
53 return 0;
54 }
55
56 uint32_t res = 0;
57 if (intel_align) {
58 res = (static_cast<uint32_t>(buf[3]) << 24) | (static_cast<uint32_t>(buf[2]) << 16) |
59 (static_cast<uint32_t>(buf[1]) << 8) | buf[0];
60 } else {
61 res = (static_cast<uint32_t>(buf[0]) << 24) | (static_cast<uint32_t>(buf[1]) << 16) |
62 (static_cast<uint32_t>(buf[2]) << 8) | buf[3];
63 }
64 return res;
65 }
66
parseExif(const uint8_t * buf,uint32_t len)67 int parseExif(const uint8_t *buf, uint32_t len) {
68 bool intel_align = true;
69 uint32_t offset = 0;
70 if (!buf || len < 6) {
71 return UNKNOW_ORIENTATION;
72 }
73
74 if (!std::equal(buf, buf + 6, "Exif\0\0")) {
75 return UNKNOW_ORIENTATION;
76 }
77 offset += 6;
78
79 if (offset + 8 > len) {
80 return UNKNOW_ORIENTATION;
81 }
82 if (buf[offset] == 'I' && buf[offset + 1] == 'I') {
83 intel_align = true;
84 } else if (buf[offset] == 'M' && buf[offset + 1] == 'M') {
85 intel_align = false;
86 } else {
87 return UNKNOW_ORIENTATION;
88 }
89
90 offset += 2;
91 if (parse_bytes<uint16_t>(buf + offset, intel_align) != 0x2a) {
92 return UNKNOW_ORIENTATION;
93 }
94 offset += 2;
95 uint32_t first_ifd_offset = parse_bytes<uint32_t>(buf + offset, intel_align);
96 offset += first_ifd_offset - 4;
97 if (offset >= len || offset + 2 > len) {
98 return UNKNOW_ORIENTATION;
99 }
100
101 int num_entries = parse_bytes<uint16_t>(buf + offset, intel_align);
102 if (offset + 6 + 12 * num_entries > len) {
103 return UNKNOW_ORIENTATION;
104 }
105 offset += 2;
106 while (num_entries > 0) {
107 uint16_t tag = parse_bytes<uint16_t>(buf + offset, intel_align);
108 if (tag == 0x112) {
109 uint16_t format = parse_bytes<uint16_t>(buf + offset + 2, intel_align);
110 uint32_t length = parse_bytes<uint32_t>(buf + offset + 4, intel_align);
111 if (format == 3 && length) {
112 uint16_t orient = parse_bytes<uint16_t>(buf + offset + 8, intel_align);
113 return static_cast<int>(orient);
114 }
115 }
116 offset += 12;
117 num_entries--;
118 }
119 return UNKNOW_ORIENTATION;
120 }
121
parseOrientation(const unsigned char * data,unsigned len)122 int ExifInfo::parseOrientation(const unsigned char *data, unsigned len) {
123 if (!data || len < 4) return UNKNOW_ORIENTATION;
124
125 if (data[0] != 0xFF || data[1] != 0xD8) return UNKNOW_ORIENTATION;
126
127 while (len > 2) {
128 if (data[len - 1] == 0xD9 && data[len - 2] == 0xFF) break;
129 len--;
130 }
131 if (len <= 2) return UNKNOW_ORIENTATION;
132
133 unsigned int offset = 0;
134 for (; offset < len - 1; offset++) {
135 if (data[offset] == 0xFF && data[offset + 1] == 0xE1) break;
136 }
137 if (offset + 4 > len) return UNKNOW_ORIENTATION;
138 offset += 2;
139 uint16_t section_length = parse_bytes<uint16_t>(data + offset, false);
140 if (offset + section_length > len || section_length < 16) return UNKNOW_ORIENTATION;
141 offset += 2;
142
143 return parseExif(data + offset, len - offset);
144 }
145 } // namespace dataset
146 } // namespace mindspore
147