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 26namespace OHOS::Camera { 27static const unsigned int IMAGE_DATA_OFFSET = 20; 28 29// Raw exif header data 30static const unsigned char EXIF_HEADER[] = {0xff, 0xd8, 0xff, 0xe1}; 31 32static const unsigned int EXIF_HEADER_LENGTH = sizeof(EXIF_HEADER); 33 34#define FILE_BYTE_ORDER EXIF_BYTE_ORDER_INTEL 35 36static 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 64uint32_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 105uint32_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 155uint32_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 182uint32_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 201uint32_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 238uint32_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 260void 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 273uint32_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 323error: 324 FreeResource(dataBuffer, tempBuffer, exif, exifData); 325 326 return ret; 327} 328 329void 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 359void 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