2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "exif/exif_information.h"
22 #include "common/assert.h"
23 #include "common/converter.h"
24 #include "common/logger.h"
25 #include "common/platform_result.h"
27 #include "exif/exif_tag_saver.h"
28 #include "exif/exif_util.h"
29 #include "exif/jpeg_file.h"
34 using common::ErrorCode;
35 using common::PlatformResult;
37 const std::size_t EXIF_UNDEFINED_TYPE_LENGTH = 8;
38 const std::string EXIF_UNDEFINED_TYPE_ASCII =
39 std::string("ASCII\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH);
40 const std::string EXIF_UNDEFINED_TYPE_JIS =
41 std::string("JIS\0\0\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH);
42 const std::string EXIF_UNDEFINED_TYPE_UNICODE =
43 std::string("UNICODE\0", EXIF_UNDEFINED_TYPE_LENGTH);
44 const std::string EXIF_UNDEFINED_TYPE_UNDEFINED =
45 std::string("\0\0\0\0\0\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH);
48 constexpr unsigned int str2int(const char* str, int h = 0) {
49 return !str[h] ? 5381 : (str2int(str, h + 1) * 33) ^ str[h];
52 IsoSpeedRatingsVector jsonArray2vector(const picojson::value& a) {
54 if (!a.is<picojson::array>()) {
55 return IsoSpeedRatingsVector();
58 IsoSpeedRatingsVector result;
60 picojson::array v = a.get<picojson::array>();
62 for (picojson::array::iterator it = v.begin(); it != v.end(); ++it) {
63 if ((*it).is<double>()) result.push_back(static_cast<long long int>((*it).get<double>()));
70 ExifInformation::ExifInformation() {
72 for (int attr = 0; attr < EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES; attr++) {
73 unset(static_cast<ExifInformationAttribute>(attr));
77 ExifInformation::ExifInformation(const picojson::value& args) {
79 for (int attr = 0; attr < EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES; attr++) {
80 unset(static_cast<ExifInformationAttribute>(attr));
83 for (AttributeMap::const_iterator it = ExifInformationAttributeMap.begin();
84 it != ExifInformationAttributeMap.end(); ++it) {
85 std::string attributeName = it->second;
86 picojson::value v = args.get(attributeName);
87 if (!common::IsNull(v)) {
88 set(attributeName, v);
93 ExifInformation::~ExifInformation() {
97 const std::string& ExifInformation::getUri() {
101 void ExifInformation::setUri(const std::string& uri) {
102 m_is_set[EXIF_INFORMATION_ATTRIBUTE_URI] = true;
104 LoggerD("URI: %s", uri.c_str());
107 unsigned long ExifInformation::getWidth() const {
111 void ExifInformation::setWidth(unsigned long width) {
112 m_is_set[EXIF_INFORMATION_ATTRIBUTE_WIDTH] = true;
116 unsigned long ExifInformation::getHeight() const {
120 void ExifInformation::setHeight(unsigned long height) {
121 m_is_set[EXIF_INFORMATION_ATTRIBUTE_HEIGHT] = true;
125 const std::string& ExifInformation::getDeviceMaker() {
126 return m_device_maker;
129 void ExifInformation::setDeviceMaker(const std::string& device_maker) {
130 m_is_set[EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER] = true;
131 m_device_maker = device_maker;
134 const std::string& ExifInformation::getDeviceModel() {
135 return m_device_model;
138 void ExifInformation::setDeviceModel(const std::string& device_model) {
139 m_is_set[EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL] = true;
140 m_device_model = device_model;
143 time_t ExifInformation::getOriginalTime() const {
144 return m_original_time;
147 void ExifInformation::setOriginalTime(time_t original_time) {
148 m_is_set[EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME] = true;
149 m_original_time = original_time;
152 const std::string& ExifInformation::getOrientationString() {
153 return ExifUtil::orientationToString(m_orientation);
156 ImageOrientation ExifInformation::getOrientation() {
157 return m_orientation;
160 void ExifInformation::setOrientation(const std::string& orientation) {
162 setOrientation(ExifUtil::stringToOrientation(orientation));
165 void ExifInformation::setOrientation(ImageOrientation orientation) {
166 m_is_set[EXIF_INFORMATION_ATTRIBUTE_ORIENTATION] = true;
167 m_orientation = orientation;
170 const Rational& ExifInformation::getFNumber() const {
174 void ExifInformation::setFNumber(Rational f_number) {
175 if (!f_number.isValid()) {
176 LoggerW("Trying to set invalid F-Number: %s", f_number.toString().c_str());
180 m_is_set[EXIF_INFORMATION_ATTRIBUTE_FNUMBER] = true;
181 m_f_number = f_number;
184 const std::vector<long long int>& ExifInformation::getIsoSpeedRatings() {
185 return m_iso_speed_ratings;
188 void ExifInformation::setIsoSpeedRatings(const std::vector<long long int>& iso_speed_ratings) {
189 m_is_set[EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS] = true;
190 m_iso_speed_ratings = iso_speed_ratings;
193 const Rational& ExifInformation::getExposureTime() {
194 return m_exposure_time;
197 void ExifInformation::setExposureTime(const Rational& exposure_time) {
198 if (!exposure_time.isValid() || 0 == exposure_time.nominator) {
199 LoggerW("Trying to set invalid exposure time: [%s]", exposure_time.toString().c_str());
203 m_is_set[EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME] = true;
204 m_exposure_time = exposure_time;
207 const std::string& ExifInformation::getExposureProgramString() {
209 return ExifUtil::exposureProgramToString(m_exposure_program);
212 ExposureProgram ExifInformation::getExposureProgram() {
213 return m_exposure_program;
216 void ExifInformation::setExposureProgram(const std::string& exposure_program) {
218 setExposureProgram(ExifUtil::stringToExposureProgram(exposure_program));
221 void ExifInformation::setExposureProgram(ExposureProgram exposure_program) {
222 m_is_set[EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM] = true;
223 m_exposure_program = exposure_program;
226 bool ExifInformation::getFlash() const {
230 void ExifInformation::setFlash(bool flash) {
231 m_is_set[EXIF_INFORMATION_ATTRIBUTE_FLASH] = true;
235 const Rational& ExifInformation::getFocalLength() const {
236 return m_focal_length;
239 void ExifInformation::setFocalLength(Rational focal_length) {
240 if (!focal_length.isValid()) {
241 LoggerW("Trying to set invalid focal length: %s", focal_length.toString().c_str());
245 m_is_set[EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH] = true;
246 m_focal_length = focal_length;
249 const std::string& ExifInformation::getWhiteBalanceModeString() {
250 return ExifUtil::whiteBalanceToString(m_white_balance);
253 WhiteBalanceMode ExifInformation::getWhiteBalanceMode() {
254 return m_white_balance;
257 void ExifInformation::setWhiteBalanceMode(const std::string& white_balance) {
259 setWhiteBalanceMode(ExifUtil::stringToWhiteBalance(white_balance));
262 void ExifInformation::setWhiteBalanceMode(WhiteBalanceMode white_balance) {
263 m_is_set[EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE] = true;
264 m_white_balance = white_balance;
267 ExifGPSLocation& ExifInformation::getGPSExifLocation() {
268 return m_gps_location;
271 void ExifInformation::setGPSLocation(ExifGPSLocation gps_location) {
272 m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_LOCATION] = true;
273 m_gps_location = gps_location;
276 void ExifInformation::unsetGPSLocation() {
277 m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_LOCATION] = false;
278 m_gps_location.unsetAll();
281 const Rational& ExifInformation::getGpsAltitude() const {
282 return m_gps_altitude;
285 void ExifInformation::setGpsAltitude(Rational gps_altitude) {
286 if (!gps_altitude.isValid()) {
287 LoggerW("Trying to set invalid gps altitude: %s", gps_altitude.toString().c_str());
291 m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE] = true;
292 m_gps_altitude = gps_altitude;
295 GpsAltitudeRef ExifInformation::getGpsAltitudeRef() const {
296 return m_gps_altitude_ref;
299 void ExifInformation::setGpsAltitudeRef(const GpsAltitudeRef ref) {
300 m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF] = true;
301 m_gps_altitude_ref = ref;
304 void ExifInformation::setGpsAltitudeWithRef(double gps_altitude) {
306 setGpsAltitude(Rational::createFromDouble(fabs(gps_altitude)));
308 if (gps_altitude >= 0.0) {
309 setGpsAltitudeRef(GPS_ALTITUDE_REF_ABOVE_SEA);
311 setGpsAltitudeRef(GPS_ALTITUDE_REF_BELOW_SEA);
315 double ExifInformation::getGpsAltitudeWithRef() const {
316 if (!m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF] ||
317 GPS_ALTITUDE_REF_ABOVE_SEA == m_gps_altitude_ref) {
318 return m_gps_altitude.toDouble();
320 return -1.0 * m_gps_altitude.toDouble();
324 const std::string& ExifInformation::getGpsProcessingMethod() const {
325 return m_gps_processing_method;
328 const std::string& ExifInformation::getGpsProcessingMethodType() const {
329 return m_gps_processing_method_type;
332 void ExifInformation::setGpsProcessingMethod(const std::string& type,
333 const std::string& processing_method) {
334 if (type != EXIF_UNDEFINED_TYPE_ASCII && type != EXIF_UNDEFINED_TYPE_JIS &&
335 type != EXIF_UNDEFINED_TYPE_UNICODE && type != EXIF_UNDEFINED_TYPE_UNDEFINED) {
336 LoggerW("Trying to set invalid GPSProcessingMethod type: [%s] len: %zu", type.c_str(),
341 m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD] = true;
342 m_gps_processing_method = processing_method;
343 m_gps_processing_method_type = type;
346 void ExifInformation::setGpsTime(time_t time) {
347 m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_TIME] = true;
351 time_t ExifInformation::getGpsTime() {
355 void ExifInformation::unsetGPStime() {
356 m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_TIME] = false;
360 const std::string& ExifInformation::getUserComment() {
361 return m_user_comment;
364 const std::string& ExifInformation::getUserCommentType() {
365 return m_user_comment_type;
368 void ExifInformation::setUserComment(const std::string& type, const std::string& user_comment) {
369 if (type != EXIF_UNDEFINED_TYPE_ASCII && type != EXIF_UNDEFINED_TYPE_JIS &&
370 type != EXIF_UNDEFINED_TYPE_UNICODE && type != EXIF_UNDEFINED_TYPE_UNDEFINED) {
371 LoggerW("Trying to set invalid user comment type: [%s] len: %zu", type.c_str(), type.length());
375 m_is_set[EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT] = true;
376 m_user_comment_type = type;
377 m_user_comment = user_comment;
380 bool ExifInformation::isSet(ExifInformationAttribute attribute) const {
381 return m_is_set[attribute];
384 void ExifInformation::unset(ExifInformationAttribute attribute) {
385 if (attribute >= EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES) {
389 m_is_set[attribute] = false;
391 case EXIF_INFORMATION_ATTRIBUTE_URI:
392 m_uri = std::string();
394 case EXIF_INFORMATION_ATTRIBUTE_WIDTH:
397 case EXIF_INFORMATION_ATTRIBUTE_HEIGHT:
400 case EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER:
401 m_device_maker = std::string();
403 case EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL:
404 m_device_model = std::string();
406 case EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME:
409 case EXIF_INFORMATION_ATTRIBUTE_ORIENTATION:
410 m_orientation = EXIF_ORIENTATION_NOT_VALID;
412 case EXIF_INFORMATION_ATTRIBUTE_FNUMBER:
413 m_f_number = Rational::createInvalid();
415 case EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS:
416 m_iso_speed_ratings = std::vector<long long int>();
418 case EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME:
419 m_exposure_time = Rational::createInvalid();
421 case EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM:
422 m_exposure_program = EXIF_EXPOSURE_PROGRAM_NOT_VALID;
424 case EXIF_INFORMATION_ATTRIBUTE_FLASH:
427 case EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH:
428 m_focal_length = Rational::createInvalid();
430 case EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE:
431 m_white_balance = EXIF_WHITE_BALANCE_MODE_NOT_VALID;
433 case EXIF_INFORMATION_ATTRIBUTE_GPS_LOCATION:
436 case EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE:
437 m_gps_altitude = Rational::createInvalid();
439 case EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF:
440 m_gps_altitude_ref = GPS_ALTITUDE_REF_ABOVE_SEA;
442 case EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD:
443 m_gps_processing_method = std::string();
444 m_gps_processing_method_type = EXIF_UNDEFINED_TYPE_ASCII;
446 case EXIF_INFORMATION_ATTRIBUTE_GPS_TIME:
449 case EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT:
450 m_user_comment = std::string();
451 m_user_comment_type = EXIF_UNDEFINED_TYPE_ASCII;
458 void ExifInformation::set(std::string attributeName, const picojson::value& v) {
459 ScopeLogger("%s", attributeName.c_str());
461 switch (str2int(attributeName.c_str())) {
462 case str2int(EI_URI): {
463 setUri(v.get<std::string>());
466 case str2int(EI_WIDTH): {
467 setWidth(static_cast<int>(v.get<double>()));
470 case str2int(EI_HEIGHT): {
471 setHeight(static_cast<int>(v.get<double>()));
474 case str2int(EI_DEVICE_MAKER): {
475 setDeviceMaker(v.get<std::string>());
478 case str2int(EI_DEVICE_MODEL): {
479 setDeviceModel(v.get<std::string>());
482 case str2int(EI_ORIGINAL_TIME): {
483 setOriginalTime(static_cast<unsigned long long>(v.get<double>()));
486 case str2int(EI_ORIENTATION): {
487 setOrientation(v.get<std::string>());
490 case str2int(EI_FNUMBER): {
491 setFNumber(Rational::createFromDouble(v.get<double>()));
494 case str2int(EI_ISO_SPEED_RATINGS): {
495 setIsoSpeedRatings(jsonArray2vector(v));
498 case str2int(EI_EXPOSURE_TIME): {
499 setExposureTime(Rational::createFromExposureTimeString(v.get<std::string>()));
502 case str2int(EI_EXPOSURE_PROGRAM): {
503 setExposureProgram(v.get<std::string>());
506 case str2int(EI_FLASH): {
507 setFlash(v.get<bool>());
510 case str2int(EI_FOCAL_LENGTH): {
511 setFocalLength(Rational::createFromDouble(v.get<double>()));
514 case str2int(EI_WHITE_BALANCE): {
515 setWhiteBalanceMode(v.get<std::string>());
518 case str2int(EI_GPS_LOCATION): {
520 ExifGPSLocation(v.get("longitude").get<double>(), v.get("latitude").get<double>()));
523 case str2int(EI_GPS_ALTITUDE): {
524 setGpsAltitudeWithRef(v.get<double>());
527 case str2int(EI_GPS_PROCESSING_METHOD): {
528 setGpsProcessingMethod(EXIF_UNDEFINED_TYPE_ASCII, v.get<std::string>());
531 case str2int(EI_GPS_TIME): {
532 setGpsTime(static_cast<time_t>(v.get<double>()));
535 case str2int(EI_USER_COMMENT): {
536 setUserComment(EXIF_UNDEFINED_TYPE_ASCII, v.get<std::string>());
544 PlatformResult ExifInformation::removeNulledAttributesFromExifData(ExifData* exif_data) {
547 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "exif_data is NULL");
550 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) {
551 LoggerD("Removing width");
552 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_IMAGE_WIDTH, exif_data);
554 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_HEIGHT)) {
555 LoggerD("Removing height");
556 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_IMAGE_LENGTH, exif_data);
558 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER)) {
559 LoggerD("Removing device maker");
560 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_MAKE, exif_data);
562 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ORIENTATION)) {
563 LoggerD("Removing orientation");
564 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_ORIENTATION, exif_data);
566 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) {
567 LoggerD("Removing exposure program");
568 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_EXPOSURE_PROGRAM, exif_data);
570 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) {
571 LoggerD("Removing iso speed ratings");
572 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_ISO_SPEED_RATINGS, exif_data);
574 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE)) {
575 LoggerD("Removing white balance");
576 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_WHITE_BALANCE, exif_data);
578 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL)) {
579 LoggerD("Removing device model");
580 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_MODEL, exif_data);
582 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME)) {
583 LoggerD("Removing original time");
584 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_DATE_TIME_ORIGINAL, exif_data);
586 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME)) {
587 LoggerD("Removing exposure time");
588 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_EXPOSURE_TIME, exif_data);
590 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FNUMBER)) {
591 LoggerD("Removing f-number");
592 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FNUMBER, exif_data);
594 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FLASH)) {
595 LoggerD("Removing flash");
596 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FLASH, exif_data);
598 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH)) {
599 LoggerD("Removing focal length");
600 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FOCAL_LENGTH, exif_data);
602 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_TIME)) {
603 LoggerD("Removing gps altitude");
604 ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP), exif_data);
606 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE)) {
607 LoggerD("Removing gps altitude");
608 ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE), exif_data);
610 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) {
611 LoggerD("Removing gps altitude ref");
612 ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF),
615 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) {
616 LoggerD("Removing gps processing method");
617 ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD),
620 if (!isSet(EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT)) {
621 LoggerD("Removing user comment");
622 ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_USER_COMMENT, exif_data);
624 if (!m_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE)) {
625 LoggerD("Removing latitude");
626 ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE), exif_data);
628 if (!m_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF)) {
629 LoggerD("Removing latitude ref");
630 ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF),
633 if (!m_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE)) {
634 LoggerD("Removing longitude");
635 ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE), exif_data);
637 if (!m_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF)) {
638 LoggerD("Removing longitude ref");
639 ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF),
642 return PlatformResult(ErrorCode::NO_ERROR);
645 PlatformResult ExifInformation::updateAttributesInExifData(ExifData* exif_data) {
648 common::PlatformResult ret(common::ErrorCode::NO_ERROR);
651 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "exif_data is NULL");
654 if (isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) {
655 LoggerD("Saving width: %lu", getWidth());
656 ret = ExifTagSaver::saveToExif(getWidth(), EXIF_TAG_IMAGE_WIDTH, exif_data);
661 if (isSet(EXIF_INFORMATION_ATTRIBUTE_HEIGHT)) {
662 LoggerD("Saving height: %lu", getHeight());
663 ret = ExifTagSaver::saveToExif(getHeight(), EXIF_TAG_IMAGE_LENGTH, exif_data);
668 if (isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER)) {
669 LoggerD("Saving device maker: %s", getDeviceMaker().c_str());
670 ret = ExifTagSaver::saveToExif(getDeviceMaker(), EXIF_TAG_MAKE, exif_data);
675 if (isSet(EXIF_INFORMATION_ATTRIBUTE_ORIENTATION)) {
676 LoggerD("Saving orientation: %d", static_cast<int>(getOrientation()));
677 ret = ExifTagSaver::saveToExif(static_cast<long int>(getOrientation()), EXIF_TAG_ORIENTATION,
683 if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) {
684 LoggerD("Saving exposure program: %d", static_cast<int>(getExposureProgram()));
685 ret = ExifTagSaver::saveToExif(getExposureProgram(), EXIF_TAG_EXPOSURE_PROGRAM, exif_data);
690 if (isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) {
691 std::vector<long long int> iso_ratings = getIsoSpeedRatings();
692 LoggerD("Saving iso speed ratings count: %zu", iso_ratings.size());
693 ret = ExifTagSaver::saveToExif(iso_ratings, EXIF_FORMAT_SHORT, EXIF_TAG_ISO_SPEED_RATINGS,
699 if (isSet(EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE)) {
700 LoggerD("Saving white balance: %d", static_cast<int>(getWhiteBalanceMode()));
701 ret = ExifTagSaver::saveToExif(getWhiteBalanceMode(), EXIF_TAG_WHITE_BALANCE, exif_data);
706 if (isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL)) {
707 LoggerD("Saving device model: %s", getDeviceModel().c_str());
708 ret = ExifTagSaver::saveToExif(getDeviceModel(), EXIF_TAG_MODEL, exif_data);
713 if (isSet(EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME)) {
714 const time_t o_time = getOriginalTime();
715 const std::string o_time_str = ExifUtil::timeTToExifDateTimeOriginal(o_time);
716 LoggerD("Saving original time time_t:%d, format:%s", static_cast<int>(o_time),
719 ret = ExifTagSaver::saveToExif(o_time_str, EXIF_TAG_DATE_TIME_ORIGINAL, exif_data);
724 if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME)) {
725 Rational exposure_time = getExposureTime();
726 if (exposure_time.isValid()) {
727 LoggerD("Saving exposure time: %s (%s)", exposure_time.toString().c_str(),
728 exposure_time.toExposureTimeString().c_str());
730 ret = ExifTagSaver::saveToExif(exposure_time, EXIF_TAG_EXPOSURE_TIME, exif_data);
736 if (isSet(EXIF_INFORMATION_ATTRIBUTE_FNUMBER)) {
737 auto f_number = getFNumber();
738 LoggerD("Saving f-number: %f (%s)", f_number.toDouble(), f_number.toString().c_str());
739 ret = ExifTagSaver::saveToExif(f_number, EXIF_TAG_FNUMBER, exif_data);
744 if (isSet(EXIF_INFORMATION_ATTRIBUTE_FLASH)) {
745 LoggerD("Saving flash: %s", getFlash() ? "ON" : "OFF");
746 ret = ExifTagSaver::saveToExif(getFlash(), EXIF_TAG_FLASH, exif_data);
751 if (isSet(EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH)) {
752 auto f_length = getFocalLength();
753 LoggerD("Saving focal length:%f (%s)", f_length.toDouble(), f_length.toString().c_str());
754 ret = ExifTagSaver::saveToExif(f_length, EXIF_TAG_FOCAL_LENGTH, exif_data);
759 if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_LOCATION)) {
760 LoggerD("Saving gps location");
761 ret = ExifTagSaver::saveGpsLocationToExif(m_gps_location, exif_data);
766 if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE)) {
767 LoggerD("Saving gps altitude:%f (%s)", m_gps_altitude.toDouble(),
768 m_gps_altitude.toString().c_str());
769 ret = ExifTagSaver::saveToExif(m_gps_altitude, static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE),
775 if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) {
778 // 1 = Sea level reference (negative value)
779 LoggerD("Saving gps altitude ref:%d (%s)", static_cast<int>(m_gps_altitude_ref),
780 (static_cast<int>(m_gps_altitude_ref) > 0) ? "below sea" : "above sea");
781 std::vector<long long int> value = {static_cast<long long int>(m_gps_altitude_ref)};
782 ret = ExifTagSaver::saveToExif(value, EXIF_FORMAT_BYTE,
783 static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF), exif_data);
788 if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) {
789 LoggerD("Saving gps processing method: [%s] type:%s", getGpsProcessingMethod().c_str(),
790 getGpsProcessingMethodType().c_str());
792 const std::string& joined = getGpsProcessingMethodType() + getGpsProcessingMethod();
793 LoggerD("joined: [%s]", joined.c_str());
795 ret = ExifTagSaver::saveToExif(joined, static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD),
796 exif_data, EXIF_FORMAT_UNDEFINED, false);
801 if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_TIME)) {
802 const time_t gps_time = getGpsTime();
803 const Rationals gps_time_vec = ExifUtil::timeTToExifGpsTimeStamp(gps_time);
804 const std::string& gps_date_str = ExifUtil::timeTToExifGpsDateStamp(gps_time);
805 LoggerD("Saving gps time stamp time_t: %d", static_cast<int>(gps_time));
807 ret = ExifTagSaver::saveToExif(gps_time_vec, static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP),
813 LoggerD("Saving gps date stamp: %s", gps_date_str.c_str());
815 ret = ExifTagSaver::saveToExif(gps_date_str, static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP),
816 exif_data, EXIF_FORMAT_ASCII, false);
821 if (isSet(EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT)) {
822 LoggerD("Saving user comment: %s (type:%s)", getUserComment().c_str(),
823 getUserCommentType().c_str());
825 const std::string& joined = getUserCommentType() + getUserComment();
826 LoggerD("joined: [%s]", joined.c_str());
828 ret = ExifTagSaver::saveToExif(joined, EXIF_TAG_USER_COMMENT, exif_data, EXIF_FORMAT_UNDEFINED,
838 PlatformResult ExifInformation::saveToFile(const std::string& file_path) {
839 ScopeLogger("Using JpegFile to read: [%s] and Exif if present", file_path.c_str());
841 JpegFilePtr jpg_file;
842 PlatformResult result = JpegFile::loadFile(file_path, &jpg_file);
843 if (!result) return result;
845 ExifData* exif_data = jpg_file->getExifData();
846 bool exif_data_is_new = false;
848 // Exif is not present in file - create new ExifData
850 LoggerD("Exif is not present in file: [%s] creating new", file_path.c_str());
852 exif_data = exif_data_new();
854 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Memory allocation failed",
855 ("Couldn't allocate new ExifData"));
858 exif_data_set_option(exif_data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
859 exif_data_set_data_type(exif_data, EXIF_DATA_TYPE_COMPRESSED);
860 exif_data_set_byte_order(exif_data, EXIF_BYTE_ORDER_MOTOROLA);
861 exif_data_is_new = true;
864 LoggerD("Exif data type: %d", exif_data_get_data_type(exif_data));
865 LoggerD("Exif byte order: %d", exif_data_get_byte_order(exif_data));
866 exif_data_set_option(exif_data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
868 // If we have created new ExifData there is nothing to remove
869 if (!exif_data_is_new) {
870 // Remove attributes that have been nulled
871 PlatformResult ret = removeNulledAttributesFromExifData(exif_data);
872 if (ret.error_code() != ErrorCode::NO_ERROR) {
873 exif_data_unref(exif_data);
874 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Could not remove nulled attribute");
877 result = updateAttributesInExifData(exif_data);
879 exif_data_unref(exif_data);
883 LoggerD("Using JpegFile to save new Exif in: [%s]", file_path.c_str());
884 if (exif_data_is_new) {
885 result = jpg_file->setNewExifData(exif_data);
888 exif_data_unref(exif_data);
894 return jpg_file->saveToFile(file_path);
898 } // namespace extension