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