• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &degree, &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