1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "exif_utils.h"
17 #include <cassert>
18 #include <cstdio>
19 #include <cstdint>
20 #include <cmath>
21 #include <cstring>
22 #include <iostream>
23 #include <camera.h>
24 #include "securec.h"
25
26 namespace OHOS::Camera {
27 static const unsigned int IMAGE_DATA_OFFSET = 20;
28
29 // Raw exif header data
30 static const unsigned char EXIF_HEADER[] = {0xff, 0xd8, 0xff, 0xe1};
31
32 static const unsigned int EXIF_HEADER_LENGTH = sizeof(EXIF_HEADER);
33
34 constexpr uint32_t DEGREE_INDEX = 0; // Index
35 constexpr uint32_t MINUTE_INDEX = 1; // Index
36 constexpr uint32_t SECOND_INDEX = 2; // Index
37
38 #define FILE_BYTE_ORDER EXIF_BYTE_ORDER_INTEL
39
CreateTag(ExifData * exif,ExifIfd ifd,ExifTag tag,size_t len,ExifFormat format)40 static ExifEntry *CreateTag(ExifData *exif, ExifIfd ifd, ExifTag tag, size_t len, ExifFormat format)
41 {
42 void *buf = nullptr;
43 ExifEntry *entry = nullptr;
44
45 ExifMem *mem = exif_mem_new_default();
46 assert(mem != NULL);
47
48 entry = exif_entry_new_mem(mem);
49 assert(entry != nullptr);
50
51 buf = exif_mem_alloc(mem, len);
52 assert(buf != nullptr);
53
54 if (!entry) {
55 return nullptr;
56 }
57 entry->data = static_cast<unsigned char*>(buf);
58 entry->size = len;
59 entry->tag = tag;
60 entry->components = len;
61 entry->format = format;
62
63 exif_content_add_entry(exif->ifd[ifd], entry);
64
65 exif_mem_unref(mem);
66 exif_entry_unref(entry);
67
68 return entry;
69 }
70
GetGpsRef(LatOrLong latOrLongType,double number,char * gpsRef,int length)71 uint32_t ExifUtils::GetGpsRef(LatOrLong latOrLongType, double number, char *gpsRef, int length)
72 {
73 char north[2] = "N";
74 char south[2] = "S";
75 char east[2] = "E";
76 char west[2] = "W";
77
78 if (gpsRef == nullptr) {
79 CAMERA_LOGE("%{public}s gpsRef is null.", __FUNCTION__);
80 return RC_ERROR;
81 }
82
83 if (latOrLongType == LATITUDE_TYPE) {
84 if (number > 0) {
85 if (strncpy_s(gpsRef, length, north, strlen(north)) != 0) {
86 CAMERA_LOGE("%{public}s exif strncpy_s failed.", __FUNCTION__);
87 return RC_ERROR;
88 }
89 } else {
90 if (strncpy_s(gpsRef, length, south, strlen(south)) != 0) {
91 CAMERA_LOGE("%{public}s exif strncpy_s failed.", __FUNCTION__);
92 return RC_ERROR;
93 }
94 }
95 } else {
96 if (number > 0) {
97 if (strncpy_s(gpsRef, length, east, strlen(east)) != 0) {
98 CAMERA_LOGE("%{public}s exif strncpy_s failed.", __FUNCTION__);
99 return RC_ERROR;
100 }
101 } else {
102 if (strncpy_s(gpsRef, length, west, strlen(west)) != 0) {
103 CAMERA_LOGE("%{public}s exif strncpy_s failed.", __FUNCTION__);
104 return RC_ERROR;
105 }
106 }
107 }
108
109 return RC_OK;
110 }
111
AddLatOrLongInfo(ExifData * exif,double number,LatOrLong latOrLongType)112 uint32_t ExifUtils::AddLatOrLongInfo(ExifData *exif,
113 double number, LatOrLong latOrLongType)
114 {
115 ExifEntry *entry = nullptr;
116 char gpsRef[2] = {0}; // Index
117 ExifRational gpsRational[3]; // Index
118 int32_t degree = 0;
119 int32_t minute = 0;
120 int32_t second = 0;
121
122 if (GetGpsRef(latOrLongType, number, gpsRef, sizeof(gpsRef)) != RC_OK) {
123 CAMERA_LOGE("%{public}s exif GetGpsRef failed.", __FUNCTION__);
124 return RC_ERROR;
125 }
126
127 ConvertGpsDataToDms(number, °ree, &minute, &second);
128 gpsRational[DEGREE_INDEX].numerator = static_cast<uint32_t>(degree); // Index
129 gpsRational[DEGREE_INDEX].denominator = 1;
130 gpsRational[MINUTE_INDEX].numerator = static_cast<uint32_t>(minute); // Index
131 gpsRational[MINUTE_INDEX].denominator = 1;
132 gpsRational[SECOND_INDEX].numerator = static_cast<uint32_t>(second); // Index
133 gpsRational[SECOND_INDEX].denominator = 1;
134
135 // LATITUDE_TYPE/LONGITUDE_TYPE reference
136 if (latOrLongType == LATITUDE_TYPE) {
137 entry = CreateTag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF, sizeof(gpsRef), EXIF_FORMAT_ASCII);
138 } else {
139 entry = CreateTag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF, sizeof(gpsRef), EXIF_FORMAT_ASCII);
140 }
141 if (entry == nullptr) {
142 CAMERA_LOGE("%{public}s CreateTag failed.", __FUNCTION__);
143 return RC_ERROR;
144 }
145 if (memcpy_s(entry->data, entry->size, gpsRef, sizeof(gpsRef)) != 0) {
146 CAMERA_LOGE("%{public}s exif memcpy_s failed.", __FUNCTION__);
147 return RC_ERROR;
148 }
149 // LATITUDE_TYPE/LONGITUDE_TYPE value
150 constexpr uint32_t gpsDmsCount = 3;
151 if (latOrLongType == LATITUDE_TYPE) {
152 entry = CreateTag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE,
153 gpsDmsCount * exif_format_get_size(EXIF_FORMAT_RATIONAL),
154 EXIF_FORMAT_RATIONAL);
155 } else {
156 entry = CreateTag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE,
157 gpsDmsCount * exif_format_get_size(EXIF_FORMAT_RATIONAL),
158 EXIF_FORMAT_RATIONAL);
159 }
160 exif_set_rational(entry->data, FILE_BYTE_ORDER, gpsRational[0]);
161 exif_set_rational(entry->data + 8, FILE_BYTE_ORDER, gpsRational[1]); // 8bit
162 exif_set_rational(entry->data + 16, FILE_BYTE_ORDER, gpsRational[2]); // 16bit
163 return RC_OK;
164 }
165
AddAltitudeInfo(ExifData * exif,double altitude)166 uint32_t ExifUtils::AddAltitudeInfo(ExifData *exif, double altitude)
167 {
168 unsigned char seaLevelFlag = 0;
169 ExifEntry *entry = nullptr;
170 ExifRational gpsAltitudeRational;
171 exif_rational altitudeRational;
172
173 if (altitude > 0) {
174 seaLevelFlag = 0;
175 } else {
176 altitude = abs(altitude);
177 seaLevelFlag = 1;
178 }
179 ConvertAltitudeToRational(altitude, altitudeRational);
180 gpsAltitudeRational.numerator = static_cast<uint32_t>(altitudeRational.numerator);
181 gpsAltitudeRational.denominator = static_cast<uint32_t>(altitudeRational.denominator);
182 // Altitude reference
183 entry = CreateTag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_ALTITUDE_REF, sizeof(seaLevelFlag), EXIF_FORMAT_BYTE);
184 exif_set_short(entry->data, FILE_BYTE_ORDER, seaLevelFlag);
185
186 // Altitude value
187 entry = CreateTag(exif, EXIF_IFD_GPS, EXIF_TAG_GPS_ALTITUDE, exif_format_get_size(EXIF_FORMAT_RATIONAL),
188 EXIF_FORMAT_RATIONAL);
189 exif_set_rational(entry->data, FILE_BYTE_ORDER, gpsAltitudeRational);
190 return RC_OK;
191 }
192
IsJpegPicture(unsigned char * dataBuffer,int32_t dataBufferSize,void * address)193 uint32_t ExifUtils::IsJpegPicture(unsigned char *dataBuffer, int32_t dataBufferSize, void *address)
194 {
195 if (address == nullptr) {
196 CAMERA_LOGE("%{public}s address pointer is null", __FUNCTION__);
197 return RC_ERROR;
198 }
199 if (memcpy_s(dataBuffer, dataBufferSize, address, dataBufferSize) != 0) {
200 CAMERA_LOGE("%{public}s exif memcpy_s failed.", __FUNCTION__);
201 return RC_ERROR;
202 }
203
204 if (!(dataBuffer[0] == 0xFF && dataBuffer[1] == 0xD8)) {
205 CAMERA_LOGE("%{public}s not jpeg file,won't add exif for it.", __FUNCTION__);
206 return RC_ERROR;
207 }
208
209 if ((dataBuffer[6] == 'E' && dataBuffer[7] == 'x' && dataBuffer[8] == 'i' && dataBuffer[9] == 'f')) { // Index
210 CAMERA_LOGE("%{public}s already add exif, won't overwrite exif info.", __FUNCTION__);
211 return RC_ERROR;
212 }
213 return RC_OK;
214 }
215
PackageJpeg(unsigned char * tempBuffer,int32_t totalTempBufferSize,unsigned char * exifData,unsigned int exifDataLength,data_info sourceData)216 uint32_t ExifUtils::PackageJpeg(unsigned char *tempBuffer, int32_t totalTempBufferSize, unsigned char *exifData,
217 unsigned int exifDataLength, data_info sourceData)
218 {
219 unsigned char orderValue = 0;
220 unsigned char value = 0;
221 constexpr uint32_t exifBlockLength = 2;
222 orderValue = (exifDataLength + exifBlockLength) >> 8; // 8bit
223 value = (exifDataLength + exifBlockLength) & 0xff;
224 if (memcpy_s(tempBuffer, totalTempBufferSize, EXIF_HEADER, EXIF_HEADER_LENGTH) != 0) {
225 CAMERA_LOGE("%{public}s exif memcpy_s failed.", __FUNCTION__);
226 return RC_ERROR;
227 }
228 if (memcpy_s(tempBuffer + EXIF_HEADER_LENGTH, totalTempBufferSize, &orderValue,
229 sizeof(orderValue)) != 0) {
230 CAMERA_LOGE("%{public}s exif memcpy_s failed.", __FUNCTION__);
231 return RC_ERROR;
232 }
233 if (memcpy_s(tempBuffer + EXIF_HEADER_LENGTH + sizeof(orderValue), totalTempBufferSize, &value,
234 sizeof(value)) != 0) {
235 CAMERA_LOGE("%{public}s exif memcpy_s failed.", __FUNCTION__);
236 return RC_ERROR;
237 }
238 if (memcpy_s(tempBuffer + EXIF_HEADER_LENGTH + sizeof(orderValue) + sizeof(value), totalTempBufferSize,
239 exifData, exifDataLength) != 0) {
240 CAMERA_LOGE("%{public}s exif memcpy_s failed.", __FUNCTION__);
241 return RC_ERROR;
242 }
243 if (memcpy_s(tempBuffer + EXIF_HEADER_LENGTH + sizeof(orderValue) + sizeof(value) + exifDataLength,
244 totalTempBufferSize,
245 sourceData.dataBuffer + IMAGE_DATA_OFFSET,
246 sourceData.dataBufferSize - IMAGE_DATA_OFFSET) != 0) {
247 CAMERA_LOGE("%{public}s exif memcpy_s failed.", __FUNCTION__);
248 return RC_ERROR;
249 }
250 return RC_OK;
251 }
252
SetExifData(exif_data info,ExifData * exif,unsigned char ** exifData,unsigned int * exifDataLength)253 uint32_t ExifUtils::SetExifData(exif_data info, ExifData *exif,
254 unsigned char **exifData, unsigned int *exifDataLength)
255 {
256 CHECK_IF_PTR_NULL_RETURN_VALUE(exif, RC_ERROR);
257
258 exif_data_set_option(exif, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
259 exif_data_set_data_type(exif, EXIF_DATA_TYPE_COMPRESSED);
260 exif_data_set_byte_order(exif, FILE_BYTE_ORDER);
261 if (AddLatOrLongInfo(exif, info.latitude, LATITUDE_TYPE) != RC_OK) {
262 return RC_ERROR;
263 }
264 if (AddLatOrLongInfo(exif, info.longitude, LONGITUDE_TYPE) != RC_OK) {
265 return RC_ERROR;
266 }
267 if (AddAltitudeInfo(exif, info.altitude) != RC_OK) {
268 return RC_ERROR;
269 }
270 exif_data_save_data(exif, exifData, exifDataLength);
271
272 return RC_OK;
273 }
274
FreeResource(unsigned char * dataBuffer,unsigned char * tempBuffer,ExifData * exif,unsigned char * exifData)275 void ExifUtils::FreeResource(unsigned char *dataBuffer, unsigned char *tempBuffer,
276 ExifData *exif, unsigned char *exifData)
277 {
278 if (dataBuffer != nullptr) {
279 free(dataBuffer);
280 }
281 if (tempBuffer != nullptr) {
282 free(tempBuffer);
283 }
284 free(exifData);
285 exif_data_unref(exif);
286 }
287
AddCustomExifInfo(exif_data info,void * address,int32_t & outPutSize)288 uint32_t ExifUtils::AddCustomExifInfo(exif_data info, void *address, int32_t &outPutSize)
289 {
290 uint32_t ret = RC_ERROR;
291 unsigned char *exifData = nullptr;
292 unsigned int exifDataLength = 0;
293 ExifData *exif = nullptr;
294 unsigned char *dataBuffer = nullptr;
295 unsigned char *tempBuffer = nullptr;
296 int32_t totalTempBufferSize = 0;
297 int32_t dataBufferSize = info.frame_size;
298 constexpr uint32_t exifBlockLength = 2;
299
300 exif = exif_data_new();
301 if (!exif) {
302 CAMERA_LOGE("%{public}s exif new failed.", __FUNCTION__);
303 return ret;
304 }
305
306 if (SetExifData(info, exif, &exifData, &exifDataLength) != RC_OK) {
307 CAMERA_LOGE("%{public}s exif SetExifData failed.", __FUNCTION__);
308 return ret;
309 }
310
311 dataBuffer = static_cast<unsigned char *>(malloc(dataBufferSize));
312 if (!dataBuffer) {
313 CAMERA_LOGE("%{public}s Allocate data buf failed.", __FUNCTION__);
314 return ret;
315 }
316 data_info sourceData;
317 sourceData.dataBuffer = dataBuffer;
318 sourceData.dataBufferSize = dataBufferSize;
319
320 // Check buffer whether is valid
321 if (IsJpegPicture(dataBuffer, dataBufferSize, address) == RC_ERROR) {
322 goto error;
323 }
324 totalTempBufferSize = static_cast<int32_t>(EXIF_HEADER_LENGTH + exifBlockLength + exifDataLength +
325 (static_cast<uint32_t>(dataBufferSize) - IMAGE_DATA_OFFSET));
326 tempBuffer = static_cast<unsigned char *>(malloc(totalTempBufferSize));
327 if (!tempBuffer) {
328 CAMERA_LOGE("%{public}s Allocate temp buf failed.", __FUNCTION__);
329 goto error;
330 }
331 ret = PackageJpeg(tempBuffer, totalTempBufferSize, exifData, exifDataLength, sourceData);
332 outPutSize = totalTempBufferSize;
333 if (memcpy_s(address, totalTempBufferSize, tempBuffer, totalTempBufferSize) != 0) {
334 CAMERA_LOGE("%{public}s exif memcpy_s failed.", __FUNCTION__);
335 goto error;
336 }
337
338 error:
339 FreeResource(dataBuffer, tempBuffer, exif, exifData);
340
341 return ret;
342 }
343
ConvertGpsDataToDms(double number,int32_t * degrees,int32_t * minutes,int32_t * seconds)344 void ExifUtils::ConvertGpsDataToDms(double number, int32_t *degrees, int32_t *minutes, int32_t *seconds)
345 {
346 number = abs(number);
347 double approximateNumber = 0.0;
348 constexpr uint32_t timePeriod = 60;
349 constexpr uint32_t roundingValue = 5;
350 constexpr uint32_t precision = 10;
351 int32_t hour = static_cast<int32_t>(number);
352 int32_t minute = static_cast<int32_t>((number - hour) * timePeriod);
353 int32_t second = static_cast<int32_t>(((number - hour) * timePeriod - minute) * timePeriod);
354
355 approximateNumber = ((number - hour) * timePeriod - minute) * timePeriod - second;
356 if (static_cast<int32_t>(approximateNumber * precision) >= roundingValue) {
357 second = second + 1;
358 }
359 if (second == timePeriod) {
360 second = 0;
361 minute = minute + 1;
362 }
363 if (minute == timePeriod) {
364 minute = 0;
365 hour = hour + 1;
366 }
367 *degrees = hour;
368 *minutes = minute;
369 *seconds = second;
370
371 return;
372 }
373
ConvertAltitudeToRational(double altitude,exif_rational & outPutAltitude)374 void ExifUtils::ConvertAltitudeToRational(double altitude, exif_rational &outPutAltitude)
375 {
376 long long numerator = 0;
377 long long denominator = 1;
378 bool isSeparator = false;
379 uint32_t count = 0;
380 std::string strData = "";
381 strData = std::to_string(altitude);
382 CAMERA_LOGI("%{public}s strData = %{public}s", __FUNCTION__, strData.c_str());
383
384 count = strData.length();
385 CAMERA_LOGI("%{public}s count = %{public}d", __FUNCTION__, count);
386 constexpr uint32_t digitPosition = 10;
387 for (uint32_t i = 0; i < count; i++) {
388 char character = strData[i];
389 if (character == '.') {
390 isSeparator = true;
391 } else {
392 numerator = numerator * digitPosition + (character - '0');
393 CAMERA_LOGI("%{public}s numerator = %{public}lld", __FUNCTION__, numerator);
394 if (isSeparator) {
395 denominator *= digitPosition;
396 CAMERA_LOGI("%{public}s denominator = %{public}lld", __FUNCTION__, denominator);
397 }
398 }
399 }
400 constexpr uint32_t commonDivisor = 2;
401 constexpr uint32_t resetValue = 1;
402 for (int i = commonDivisor; static_cast<long long>(i) < numerator; i++) {
403 if ((numerator % i == 0) && (denominator % i == 0)) {
404 numerator /= i;
405 denominator /= i;
406 i = resetValue;
407 }
408 }
409
410 outPutAltitude.numerator = numerator;
411 outPutAltitude.denominator = denominator;
412 CAMERA_LOGI("%{public}s outPutAltitude.numerator = %{public}d and outPutAltitude.denominator = %{public}d",
413 __FUNCTION__, outPutAltitude.numerator, outPutAltitude.denominator);
414 }
415 } // namespace OHOS::Camera
416