From 9d34a4fc74f7167046180e507285e4c917d26218 Mon Sep 17 00:00:00 2001 From: Rafal Lelusz Date: Tue, 20 Jan 2015 14:25:27 +0100 Subject: [PATCH] [Exif] Implement getExifInfo(). [Verification] Code compiles without errors. TCT pass rate 29/63. Change-Id: If33a3907a28dbcd9a68a81d1c9f2b21279d4119f Signed-off-by: Rafal Lelusz --- src/exif/exif.gyp | 2 + src/exif/exif_api.js | 221 +++++++++++---- src/exif/exif_information.cc | 482 -------------------------------- src/exif/exif_information.h | 5 - src/exif/exif_instance.cc | 67 +---- src/exif/exif_instance.h | 2 +- src/exif/exif_util.cc | 33 --- src/exif/exif_util.h | 4 - src/exif/get_exif_info.cc | 518 +++++++++++++++++++++++++++++++++++ src/exif/get_exif_info.h | 57 ++++ 10 files changed, 746 insertions(+), 645 deletions(-) create mode 100644 src/exif/get_exif_info.cc create mode 100644 src/exif/get_exif_info.h diff --git a/src/exif/exif.gyp b/src/exif/exif.gyp index 6346ac80..9cc39a59 100644 --- a/src/exif/exif.gyp +++ b/src/exif/exif.gyp @@ -28,6 +28,8 @@ 'rational.h', 'exif_gps_location.cc', 'exif_gps_location.h', + 'get_exif_info.cc', + 'get_exif_info.h', ], 'conditions': [ [ 'tizen == 1', { diff --git a/src/exif/exif_api.js b/src/exif/exif_api.js index e890c49b..df9687be 100644 --- a/src/exif/exif_api.js +++ b/src/exif/exif_api.js @@ -1,4 +1,4 @@ -// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved. +// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -82,6 +82,74 @@ function _getJsonFromExifInformation(exifInfo) { return json; } +function _calculateDegDecimal(degrees, minutes, seconds) { + return parseInt(degrees) + parseInt(minutes) / 60.0 + parseInt(seconds) / 3600.0; +} + +function _calculateExifInfo(exifInfoNative) { + // copy all properties that share name from + // exifInfoNative to exifInfo + var exifInfo = new tizen.ExifInformation(exifInfoNative); + + // copy all remaining properties that do not share name or need extra calculations + if (exifInfoNative.originalTimeSeconds) { + exifInfo.originalTime = new Date(exifInfoNative.originalTimeSeconds * 1000); + } + + if (parseInt(exifInfoNative.whiteBalanceValue) === 0) { // 0=AUTO + exifInfo.whiteBalance = WhiteBalanceMode.AUTO; + } else if (parseInt(exifInfoNative.whiteBalanceValue) === 1) { // 1=MANUAL + exifInfo.whiteBalance = WhiteBalanceMode.MANUAL; + } + + // gpsLocation + if (exifInfoNative.gpsLatitudeDegrees && + exifInfoNative.gpsLongitudeDegrees && + exifInfoNative.gpsLatitudeRef && + exifInfoNative.gpsLongitudeRef) { + exifInfo.gpsLocation = new tizen.SimpleCoordinates(); + exifInfo.gpsLocation.latitude = _calculateDegDecimal(exifInfoNative.gpsLatitudeDegrees, + exifInfoNative.gpsLatitudeMinutes, exifInfoNative.gpsLatitudeSeconds); + exifInfo.gpsLocation.longitude = _calculateDegDecimal(exifInfoNative.gpsLongitudeDegrees, + exifInfoNative.gpsLongitudeMinutes, exifInfoNative.gpsLongitudeSeconds); + + if (exifInfoNative.gpsLatitudeRef === 'SOUTH') { + exifInfo.gpsLocation.latitude = -exifInfo.gpsLocation.latitude; + } else if (exifInfoNative.gpsLatitudeRef !== 'NORTH') { + exifInfo.gpsLocation.latitude = null; // invalid gpsLatitudeRef + } + + if (exifInfoNative.gpsLongitudeRef === 'WEST') { + exifInfo.gpsLocation.longitude = -exifInfo.gpsLocation.longitude; + } else if (exifInfoNative.gpsLongitudeRef !== 'EAST') { + exifInfo.gpsLocation.longitude = null; // invalid gpsLongitudeRef + } + } + + // gpsAltitude + if (exifInfoNative.gpsAltitude && exifInfoNative.gpsAltitudeRef) { + if (parseInt(exifInfoNative.gpsAltitudeRef) === 0) { // 0=ABOVE SEA LEVEL + exifInfo.gpsAltitude = exifInfoNative.gpsAltitude; + } else if (parseInt(exifInfoNative.gpsAltitudeRef) === 1) { // 1=BELOW SEA LEVEL + exifInfo.gpsAltitude = -exifInfoNative.gpsAltitude; + } + } + + // gpsTime + if (exifInfoNative.gpsExifDate) { + var dateSplit = exifInfoNative.gpsExifDate.split(':'); + exifInfo.gpsTime = new Date( + dateSplit[0], // year + dateSplit[1], // month + dateSplit[2], // day + exifInfoNative.gpsExifTimeHours, + exifInfoNative.gpsExifTimeMinutes, + exifInfoNative.gpsExifTimeSeconds); + } + + return exifInfo; +} + ExifManager.prototype.getExifInfo = function() { var args = validator_.validateArgs(arguments, [ { @@ -112,7 +180,15 @@ ExifManager.prototype.getExifInfo = function() { if (native_.isFailure(result)) { native_.callIfPossible(args.errorCallback, native_.getErrorObject(result)); } else { - var exifInfo = native_.getResultObject(result); + + // call to c++ code. Fields that do not exist are undefined. + var exifInfoNative = native_.getResultObject(result); + + // calculate ExifInformation struct. All fields are initially null. + // Fields that do not exist in jpg EXIF must remain null. + var exifInfo = _calculateExifInfo(exifInfoNative); + + // make successCalback and pass exifInfo args.successCallback(exifInfo); } }; @@ -120,7 +196,6 @@ ExifManager.prototype.getExifInfo = function() { native_.call('Exif_getExifInfo', callArgs, callback); }; - ExifManager.prototype.saveExifInfo = function() { var args = validator_.validateArgs(arguments, [ { @@ -193,7 +268,6 @@ ExifManager.prototype.getThumbnail = function() { native_.call('Exif_getThumbnail', {'uri': args.uri}, callback); }; -// this function passes ExifInformation_exposureProgram_attribute test: tizen.ExifInformation = function() { validator_.isConstructorCall(this, tizen.ExifInformation); @@ -206,25 +280,40 @@ tizen.ExifInformation = function() { } ]); - var uri_ = null; - var width_ = null; - var height_ = null; - var deviceMaker_ = null; - var deviceModel_ = null; - var originalTime_ = null; - var orientation_ = null; - var fNumber_ = null; - var isoSpeedRatings_ = null; - var exposureTime_ = null; - var exposureProgram_ = null; - var flash_ = null; - var focalLength_ = null; - var whiteBalance_ = null; - var gpsLocation_ = null; - var gpsAltitude_ = null; - var gpsProcessingMethod_ = null; - var gpsTime_ = null; - var userComment_ = null; + var uri_ = null, + width_ = null, + height_ = null, + deviceMaker_ = null, + deviceModel_ = null, + originalTime_ = null, + orientation_ = null, + fNumber_ = null, + isoSpeedRatings_ = null, + exposureTime_ = null, + exposureProgram_ = null, + flash_ = null, + focalLength_ = null, + whiteBalance_ = null, + gpsLocation_ = null, + gpsAltitude_ = null, + gpsProcessingMethod_ = null, + gpsTime_ = null, + userComment_ = null; + + function _validateISOSpeedRatings(v) { + var valid = false; + if (type_.isArray(v)) { + for (var i = 0; i < v.length; i++) { + var data = v[i]; // todo: uncomment when array conversion is implemented. + //if (!type_.isNumber(data)) { + // return false; + //} + } + valid = true; + } + return valid; + } + var exifInitDict = args.ExifInitDict; if (exifInitDict) { @@ -240,7 +329,7 @@ tizen.ExifInformation = function() { return uri_; }, set: function(v) { - uri_ = v ? converter_.toString(v, true) : uri_; + uri_ = v ? converter_.toString(v) : uri_; }, enumerable: true }, @@ -249,7 +338,7 @@ tizen.ExifInformation = function() { return width_; }, set: function(v) { - width_ = v ? converter_.toLong(v, true) : width_; + width_ = (!type_.isUndefined(v)) ? converter_.toLong(v, true) : width_; }, enumerable: true }, @@ -258,7 +347,7 @@ tizen.ExifInformation = function() { return height_; }, set: function(v) { - height_ = v ? converter_.toLong(v, true) : height_; + height_ = (!type_.isUndefined(v)) ? converter_.toLong(v, true) : height_; }, enumerable: true }, @@ -266,8 +355,9 @@ tizen.ExifInformation = function() { get: function() { return deviceMaker_; }, - set: function(val) { - deviceMaker_ = val ? converter_.toString(val, true) : deviceMaker_; + set: function(v) { + deviceMaker_ = (!type_.isUndefined(v)) ? + converter_.toString(v, true) : deviceMaker_; }, enumerable: true }, @@ -275,8 +365,9 @@ tizen.ExifInformation = function() { get: function() { return deviceModel_; }, - set: function(val) { - deviceModel_ = val ? converter_.toString(val, true) : deviceModel_; + set: function(v) { + deviceModel_ = (!type_.isUndefined(v)) ? + converter_.toString(v, true) : deviceModel_; }, enumerable: true }, @@ -284,8 +375,10 @@ tizen.ExifInformation = function() { get: function() { return originalTime_; }, - set: function(val) { - originalTime_ = val instanceof Date ? val : originalTime_; + set: function(v) { + if (!type_.isUndefined(v)) { + if (v === null || v instanceof Date) originalTime_ = v; + } }, enumerable: true }, @@ -294,8 +387,8 @@ tizen.ExifInformation = function() { return orientation_; }, set: function(v) { - orientation_ = v ? converter_.toEnum(v, Object.keys(ImageContentOrientation), true) : - orientation_; + orientation_ = (!type_.isUndefined(v)) ? + converter_.toEnum(v, Object.keys(ImageContentOrientation), true) : orientation_; }, enumerable: true }, @@ -303,8 +396,8 @@ tizen.ExifInformation = function() { get: function() { return fNumber_; }, - set: function(val) { - fNumber_ = val ? converter_.toDouble(val, true) : fNumber_; + set: function(v) { + fNumber_ = (!type_.isUndefined(v)) ? converter_.toDouble(v, true) : fNumber_; }, enumerable: true }, @@ -312,8 +405,11 @@ tizen.ExifInformation = function() { get: function() { return isoSpeedRatings_; }, - set: function(val) { - isoSpeedRatings_ = type_.isArray(val) ? val : isoSpeedRatings_; + set: function(v) { + // todo: convert string array into unsigned short array + if (!type_.isUndefined(v)) { + if (v === null || _validateISOSpeedRatings(v)) isoSpeedRatings_ = v; + } }, enumerable: true }, @@ -321,8 +417,9 @@ tizen.ExifInformation = function() { get: function() { return exposureTime_; }, - set: function(val) { - exposureTime_ = val ? converter_.toString(val, true) : exposureTime_; + set: function(v) { + exposureTime_ = (!type_.isUndefined(v)) ? + converter_.toString(v, true) : exposureTime_; }, enumerable: true }, @@ -331,8 +428,8 @@ tizen.ExifInformation = function() { return exposureProgram_; }, set: function(v) { - exposureProgram_ = v ? converter_.toEnum(v, Object.keys(ExposureProgram), true) : - exposureProgram_; + exposureProgram_ = (!type_.isUndefined(v)) ? + converter_.toEnum(v, Object.keys(ExposureProgram), true) : exposureProgram_; }, enumerable: true }, @@ -340,8 +437,8 @@ tizen.ExifInformation = function() { get: function() { return flash_; }, - set: function(val) { - flash_ = converter_.toBoolean(val, true); + set: function(v) { + flash_ = (!type_.isUndefined(v)) ? converter_.toBoolean(v, true) : flash_; }, enumerable: true }, @@ -349,8 +446,9 @@ tizen.ExifInformation = function() { get: function() { return focalLength_; }, - set: function(val) { - focalLength_ = val ? converter_.toDouble(val, true) : focalLength_; + set: function(v) { + focalLength_ = (!type_.isUndefined(v)) ? + converter_.toDouble(v, true) : focalLength_; }, enumerable: true }, @@ -359,8 +457,8 @@ tizen.ExifInformation = function() { return whiteBalance_; }, set: function(v) { - whiteBalance_ = v ? converter_.toEnum(v, Object.keys(WhiteBalanceMode), true) : - whiteBalance_; + whiteBalance_ = (!type_.isUndefined(v)) ? + converter_.toEnum(v, Object.keys(WhiteBalanceMode), true) : whiteBalance_; }, enumerable: true }, @@ -368,8 +466,10 @@ tizen.ExifInformation = function() { get: function() { return gpsLocation_; }, - set: function(val) { - gpsLocation_ = val instanceof tizen.SimpleCoordinates ? val : gpsLocation_; + set: function(v) { + if (!type_.isUndefined(v)) { + if (v === null || v instanceof tizen.SimpleCoordinates) gpsLocation_ = v; + } }, enumerable: true }, @@ -377,8 +477,9 @@ tizen.ExifInformation = function() { get: function() { return gpsAltitude_; }, - set: function(val) { - gpsAltitude_ = val ? converter_.toDouble(val, true) : gpsAltitude_; + set: function(v) { + gpsAltitude_ = (!type_.isUndefined(v)) ? + converter_.toDouble(v, true) : gpsAltitude_; }, enumerable: true }, @@ -386,8 +487,9 @@ tizen.ExifInformation = function() { get: function() { return gpsProcessingMethod_; }, - set: function(val) { - gpsProcessingMethod_ = val ? converter_.toString(val, true) : gpsProcessingMethod_; + set: function(v) { + gpsProcessingMethod_ = (!type_.isUndefined(v)) ? + converter_.toString(v, true) : gpsProcessingMethod_; }, enumerable: true }, @@ -396,8 +498,10 @@ tizen.ExifInformation = function() { get: function() { return gpsTime_; }, - set: function(val) { - gpsTime_ = val instanceof tizen.TZDate ? val : gpsTime_; + set: function(v) { + if (!type_.isUndefined(v)) { + if (v === null || v instanceof Date) gpsTime_ = v; + } } }, userComment: { @@ -405,8 +509,9 @@ tizen.ExifInformation = function() { get: function() { return userComment_; }, - set: function(val) { - userComment_ = val ? converter_.toString(val, true) : userComment_; + set: function(v) { + userComment_ = (!type_.isUndefined(v)) ? + converter_.toString(v, true) : userComment_; } } }); diff --git a/src/exif/exif_information.cc b/src/exif/exif_information.cc index b1aba683..63c8f8fa 100644 --- a/src/exif/exif_information.cc +++ b/src/exif/exif_information.cc @@ -596,488 +596,6 @@ void ExifInformation::set(std::string attributeName, const picojson::value& v) { } } -bool getGCSPositionFromEntry(ExifEntry *entry, ExifData* exif_data, - GCSPosition& out_pos) { - // RATIONAL - 3 - if (EXIF_FORMAT_RATIONAL == entry->format && - entry->components >= 3 && - entry->data) { - const ExifByteOrder order = exif_data_get_byte_order(exif_data); - out_pos.degrees = Rational(exif_get_rational(entry->data, order)); - out_pos.minutes = Rational(exif_get_rational( - entry->data + ExifTypeInfo::RationalSize, order)); - out_pos.seconds = Rational(exif_get_rational( - entry->data + 2*ExifTypeInfo::RationalSize, order)); - return true; - } else { - return false; - } -} - -bool getRationalsFromEntry(ExifEntry *entry, ExifData* exif_data, - unsigned long required_count, - Rationals& out_rationals) { - if (EXIF_FORMAT_RATIONAL == entry->format && - entry->components >= required_count && - entry->data) { - const ExifByteOrder order = exif_data_get_byte_order(exif_data); - unsigned char* ptr = entry->data; - - for (unsigned long i = 0; i < required_count; ++i) { - out_rationals.push_back(Rational(exif_get_rational(ptr, order))); - ptr += ExifTypeInfo::RationalSize; - } - - return true; - } else { - return false; - } -} - -Rational getRationalFromEntry(ExifEntry *entry, ExifData* exif_data) { - if (EXIF_FORMAT_RATIONAL == entry->format && - entry->components >= 1 && - entry->data) { - const ExifByteOrder order = exif_data_get_byte_order(exif_data); - return Rational(exif_get_rational(entry->data, order)); - } else { - return Rational::createInvalid(); - } -} - -bool decomposeExifUndefined(ExifEntry* entry, std::string& type, - std::string& value) { - if (!entry || !entry->data) { - LoggerW("exif entry is NULL/empty"); - return false; - } - - if (entry->size < EXIF_UNDEFINED_TYPE_LENGTH) { - LoggerW("entry size is invalid %d < EXIF_UNDEFINED_TYPE_LENGTH", - entry->size); - return false; - } - - const char* ptr = reinterpret_cast(entry->data); - type = std::string(ptr, EXIF_UNDEFINED_TYPE_LENGTH); - ptr += EXIF_UNDEFINED_TYPE_LENGTH; - value = std::string(ptr, entry->size - EXIF_UNDEFINED_TYPE_LENGTH); - return true; -} - -void ExifInformation::processEntry(ExifEntry* entry, ExifData* exif_data) { - char buf[2000]; - exif_entry_get_value(entry, buf, sizeof(buf)); - ExifUtil::printExifEntryInfo(entry, exif_data); - - const ExifIfd cur_ifd = exif_entry_get_ifd(entry); - if (EXIF_IFD_INTEROPERABILITY == cur_ifd || EXIF_IFD_1 == cur_ifd) { - return; - } - - switch (static_cast(entry->tag)) { - case EXIF_TAG_IMAGE_WIDTH: { - // SHORT or LONG - 1 - exif_entry_get_value(entry, buf, sizeof(buf)); - LoggerD("Setting ExifInformation width to: [%s]", buf); - setWidth(atol(buf)); - break; - } - case EXIF_TAG_IMAGE_LENGTH: { - // SHORT or LONG - 1 - exif_entry_get_value(entry, buf, sizeof(buf)); - LoggerD("Setting ExifInformation height to: [%s]", buf); - setHeight(atol(buf)); - break; - } - case EXIF_TAG_MAKE: { - // ASCII - Any - exif_entry_get_value(entry, buf, sizeof(buf)); - LoggerD("Setting ExifInformation maker to: [%s]", buf); - setDeviceMaker(std::string(buf)); - break; - } - case EXIF_TAG_MODEL: { - // ASCII - Any - exif_entry_get_value(entry, buf, sizeof(buf)); - LoggerD("Setting ExifInformation model to: [%s]", buf); - setDeviceModel(std::string(buf)); - break; - } - case EXIF_TAG_DATE_TIME_ORIGINAL: { - // ASCII - 20 - exif_entry_get_value(entry, buf, sizeof(buf)); - const time_t time = ExifUtil::exifDateTimeOriginalToTimeT( - reinterpret_cast(entry->data)); - LoggerD("Setting ExifInformation time original to: [%s] time_t:%d", buf, - static_cast(time)); - setOriginalTime(time); - } - case EXIF_TAG_ORIENTATION: { - // SHORT - 1 - exif_entry_get_value(entry, buf, sizeof(buf)); - const ExifByteOrder order = exif_data_get_byte_order(exif_data); - const ExifShort orient(exif_get_short(entry->data, order)); - - if (orient < EXIF_ORIENTATION_NORMAL || - orient >= EXIF_ORIENTATION_NOT_VALID) { - LoggerW("Couldn't set ExifInformation - orientation" - " is not valid: %d (%s)", orient, buf); - } else { - LoggerD("Setting ExifInformation orientation to: %d [%s]", orient, buf); - setOrientation(static_cast(orient)); - } - break; - } - case EXIF_TAG_FNUMBER: - { - // RATIONAL - 1 - Rational fnumber = getRationalFromEntry(entry, exif_data); - if (fnumber.isValid()) { - LoggerD("Setting ExifInformation fnumber to: %f (%s)", - fnumber.toDouble(), - fnumber.toString().c_str()); - setFNumber(fnumber); - } else { - LoggerW("Couldn't set ExifInformation - fnumber is not valid: %s", - fnumber.toString().c_str()); - } - break; - } - case EXIF_TAG_ISO_SPEED_RATINGS: { - // SHORT - Any - if (EXIF_FORMAT_SHORT == entry->format && - entry->components > 0 && - entry->data) { - const ExifByteOrder order = exif_data_get_byte_order(exif_data); - unsigned char* read_ptr = entry->data; - const size_t size_per_member = - ExifUtil::getSizeOfExifFormatType(entry->format); - - for (unsigned long i = 0; i < entry->components; ++i) { - ExifShort iso_rating = exif_get_short(read_ptr, order); - - LoggerD("Appending ExifInformation speed ratings with: %d", - static_cast(iso_rating)); - - read_ptr += size_per_member; - } - } else { - LoggerE("iso speed ratings: format or components count is invalid!"); - throw common::TypeMismatchException("iso speed ratings: format or" - " components count is invalid!"); - } - break; - } - case EXIF_TAG_EXPOSURE_TIME: { - // RATIONAL - 1 - if (EXIF_FORMAT_RATIONAL == entry->format && - entry->components > 0 && - entry->data) { - const ExifByteOrder order = exif_data_get_byte_order(exif_data); - const Rational exp_time(exif_get_rational(entry->data, order)); - - if (exp_time.isValid()) { - LoggerD("Setting ExifInformation exposure time to: %s (%s)", - exp_time.toString().c_str(), - exp_time.toExposureTimeString().c_str()); - setExposureTime(exp_time); - } else { - LoggerD("Couldn't set ExifInformation" - " - exposure time is not valid: %s", - exp_time.toString().c_str()); - } - } else { - LoggerE("exposure time: format or components count is invalid!"); - throw common::TypeMismatchException("exposure time: format or" - " components count is invalid!"); - } - break; - } - case EXIF_TAG_EXPOSURE_PROGRAM: { - // SHORT - 1 - exif_entry_get_value(entry, buf, sizeof(buf)); - - const ExifByteOrder order = exif_data_get_byte_order(exif_data); - const ExifShort exp_program = exif_get_short(entry->data, order); - if (exp_program >= EXIF_EXPOSURE_PROGRAM_NOT_VALID) { - LoggerW("ExposureProgram: %d (%s) is not valid!", exp_program, buf); - } else { - LoggerD("Setting ExifInformation exposure program to: %d [%s]", - exp_program, buf); - setExposureProgram(static_cast(exp_program)); - } - break; - } - case EXIF_TAG_FLASH: { - // SHORT - 1 - exif_entry_get_value(entry, buf, sizeof(buf)); - - const ExifByteOrder order = exif_data_get_byte_order(exif_data); - const ExifShort flash = exif_get_short(entry->data, order); - - LoggerD("Setting ExifInformation flash to: [%s] flash=%d", buf, flash); - setFlash(flash != 0); - break; - } - case EXIF_TAG_FOCAL_LENGTH: { - // RATIONAL - 1 - Rational flength = getRationalFromEntry(entry, exif_data); - if (flength.isValid()) { - LoggerD("Setting ExifInformation focal length to: %f (%s)", - flength.toDouble(), flength.toString().c_str()); - setFocalLength(flength); - } else { - LoggerW("Couldn't set ExifInformation - focal length is not valid: %s", - flength.toString().c_str()); - } - break; - } - case EXIF_TAG_WHITE_BALANCE: { - // SHORT - 1 - exif_entry_get_value(entry, buf, sizeof(buf)); - LoggerD("Setting ExifInformation white balance to: [%s]", buf); - if (entry->data[0]) { - setWhiteBalanceMode(EXIF_WHITE_BALANCE_MODE_MANUAL); - } else { - setWhiteBalanceMode(EXIF_WHITE_BALANCE_MODE_AUTO); - } - break; - } - case EXIF_TAG_GPS_LONGITUDE: { - // RATIONAL - 3 - GCSPosition longitude; - if (getGCSPositionFromEntry(entry, exif_data, longitude)) { - m_gps_location.setLongitude(longitude); - LoggerD("Setting ExifInformation gps longitude to: %s; %s; %s valid:%d", - longitude.degrees.toString().c_str(), - longitude.minutes.toString().c_str(), - longitude.seconds.toString().c_str(), - longitude.isValid()); - } else { - exif_entry_get_value(entry, buf, sizeof(buf)); - LoggerW("Couldn't set longitude pos - data is not valid: [%s]", buf); - } - break; - } - case EXIF_TAG_GPS_LONGITUDE_REF: { - // ASCII - 2 - if (entry->size < 1) { - LoggerW("Longtitude ref entry do not contain enought data!"); - break; - } - - const char ref = static_cast(entry->data[0]); - if ('E' == ref || 'e' == ref) { // East - m_gps_location.setLongitudeRef(GPS_LOCATION_EAST); - LoggerD("Setting ExifInformation gps longitude REF to: EAST"); - } else if ('W' == ref || 'w' == ref) { // West - m_gps_location.setLongitudeRef(GPS_LOCATION_WEST); - LoggerD("Setting ExifInformation gps longitude REF to: WEST"); - } else { - LoggerW("Unknown longitude ref: %c (0x%x)", ref, static_cast(ref)); - } - break; - } - case EXIF_TAG_GPS_LATITUDE: { - // RATIONAL - 3 - exif_entry_get_value(entry, buf, sizeof(buf)); - LoggerD("Setting ExifInformation latitude to: [%s], tag->%s", - buf, exif_tag_get_name(entry->tag) ); - - GCSPosition latitude; - if (getGCSPositionFromEntry(entry, exif_data, latitude)) { - m_gps_location.setLatitude(latitude); - LoggerD("Setting ExifInformation gps latitude to: %s; %s; %s valid:%d", - latitude.degrees.toString().c_str(), - latitude.minutes.toString().c_str(), - latitude.seconds.toString().c_str(), - latitude.isValid()); - } else { - LoggerW("Couldn't set latitude pos - data is not valid!"); - } - break; - } - case EXIF_TAG_GPS_LATITUDE_REF: { - // ASCII - 2 - if (entry->size < 1) { - LoggerW("Latitude ref entry do not contain enought data!"); - break; - } - - const char ref = static_cast(entry->data[0]); - if ('N' == ref || 'n' == ref) { // North - m_gps_location.setLatitudeRef(GPS_LOCATION_NORTH); - LoggerD("Setting ExifInformation gps latitude REF to: NORTH"); - } else if ('S' == ref || 's' == ref) { // South - m_gps_location.setLatitudeRef(GPS_LOCATION_SOUTH); - LoggerD("Setting ExifInformation gps latitude REF to: SOUTH"); - } else { - LoggerW("Unknown latitude ref: %c (0x%x)", ref, static_cast(ref)); - } - break; - } - case EXIF_TAG_GPS_ALTITUDE: { - // RATIONAL - 1 - Rational gps_altitude = getRationalFromEntry(entry, exif_data); - if (gps_altitude.isValid()) { - LoggerD("Setting ExifInformation gps altitude to: %f (%s)", - gps_altitude.toDouble(), gps_altitude.toString().c_str()); - setGpsAltitude(gps_altitude); - } else { - LoggerW("Couldn't set ExifInformation - gps altitude is not valid: %s", - gps_altitude.toString().c_str()); - } - break; - } - case EXIF_TAG_GPS_ALTITUDE_REF: { - // BYTE - 1 - const ExifByte altitude_ref = static_cast(entry->data[0]); - if (static_cast(GPS_ALTITUDE_REF_ABOVE_SEA) == altitude_ref || - static_cast(GPS_ALTITUDE_REF_BELOW_SEA) == altitude_ref) { - setGpsAltitudeRef(static_cast(altitude_ref)); - LoggerD("Setting ExifInformation gps altitude ref to: %d (%s)", - static_cast(altitude_ref), - (altitude_ref > 0) ? "below sea" : "above sea"); - } else { - LoggerW("GPS altitude ref is invalid:%d should be 0 or 1!", - static_cast(altitude_ref)); - } - break; - } - case EXIF_TAG_GPS_PROCESSING_METHOD: { - // UNDEFINED - Any - std::string type, value; - if (decomposeExifUndefined(entry, type, value)) { - LoggerD("Extracted GPSProcessingMethod: [%s], len:%d, type:%s", - value.c_str(), value.length(), type.c_str()); - setGpsProcessingMethod(type, value); - - LoggerD("Setting ExifInformation processing method" - " to: [%s], len:%d, type:%s", - m_gps_processing_method.c_str(), - m_gps_processing_method.length(), - m_gps_processing_method_type.c_str()); - } else { - LoggerW("GPSProcessingMethod tag contains invalid values!"); - } - break; - } - case EXIF_TAG_GPS_DATE_STAMP: { - // ASCII - 11 - exif_entry_get_value(entry, buf, sizeof(buf)); - LoggerD("Setting ExifInformation gps date stamp to: [%s]", buf); - // m_exif_gps_time.setDate(buf); - break; - } - case EXIF_TAG_GPS_TIME_STAMP: { - // Rational - 3 - exif_entry_get_value(entry, buf, sizeof(buf)); - LoggerD("Setting ExifInformation gps time stamp to: [%s]", buf); - - Rationals time; - if (getRationalsFromEntry(entry, exif_data, 3, time)) { - // m_exif_gps_time.setTime(time); - } - break; - } - case EXIF_TAG_USER_COMMENT: { - // UNDEFINED - Any - std::string type, value; - if (decomposeExifUndefined(entry, type, value)) { - LoggerD("Extracted UserComment: [%s], len:%d, type:%s", - value.c_str(), value.length(), type.c_str()); - setUserComment(type, value); - - LoggerD("Setting ExifInformation user comment" - " to: [%s], len:%d, type:%s", - m_user_comment.c_str(), - m_user_comment.length(), - m_user_comment_type.c_str()); - } else { - LoggerW("UserComment tag contains invalid values!"); - } - - break; - } - default: { - LoggerD("Field of tag:%x.H [%s] is not supported, value: [%s]", - entry->tag, - exif_tag_get_name_in_ifd(entry->tag, cur_ifd), - exif_entry_get_value(entry, buf, sizeof(buf))); - } - } -} - -struct ExifInfoAndDataHolder { - ExifInformationPtr exif_info; - ExifData* exif_data; -}; - -void ExifInformation::contentForeachFunctionProxy(ExifEntry *entry, - void *user_data) { - ExifInfoAndDataHolder* holder = - static_cast(user_data); - if (!holder) { - LoggerE("holder is NULL"); - } - - if (!holder->exif_info) { - LoggerE("exif_info is NULL!"); - return; - } - - if (!holder->exif_data) { - LoggerE("exif_data is NULL!"); - return; - } - - try { - holder->exif_info->processEntry(entry, holder->exif_data); - } - /*catch(const BasePlatformException &err) { - LoggerE("processEntry thrown exception: %s : %s", err.getName().c_str(), - err.getMessage().c_str()); - }*/ - catch(...) { - LoggerE("Unsupported error while processing Exif entry."); - } -} - -void ExifInformation::dataForeachFunction(ExifContent *content, - void *user_data) { - exif_content_foreach_entry(content, contentForeachFunctionProxy, user_data); -} - - -ExifInformationPtr ExifInformation::loadFromURI(const std::string& uri) { - ExifInformationPtr exif_info(new ExifInformation()); - exif_info->setUri(uri); - - const std::string file_path = ExifUtil::convertUriToPath(uri); - ExifData* ed = exif_data_new_from_file(file_path.c_str()); - if (!ed) { - LoggerE("Error reading exif from file %s", file_path.c_str()); - // throw NotFoundException("Error reading exif from file"); - } - - LoggerD("exif_data_foreach_content START"); - - ExifInfoAndDataHolder holder; - holder.exif_info = exif_info; - holder.exif_data = ed; - exif_data_foreach_content(ed, dataForeachFunction, - static_cast(&holder)); - - LoggerD("exif_data_foreach_content END"); - - exif_data_unref(ed); - ed = NULL; - - return exif_info; -} - - void ExifInformation::removeNulledAttributesFromExifData(ExifData* exif_data) { LoggerD("Entered"); if (!exif_data) { diff --git a/src/exif/exif_information.h b/src/exif/exif_information.h index 62ca1dd1..4c95d96e 100644 --- a/src/exif/exif_information.h +++ b/src/exif/exif_information.h @@ -117,7 +117,6 @@ class ExifInformation { explicit ExifInformation(const picojson::value& args); ~ExifInformation(); - static ExifInformationPtr loadFromURI(const std::string& uri); void saveToFile(const std::string& file_path); const std::string& getUri(); @@ -210,10 +209,6 @@ class ExifInformation { void set(std::string attributeName, const picojson::value& args); private: - void processEntry(ExifEntry* entry, ExifData* exif_data); - static void contentForeachFunctionProxy(ExifEntry* entry, void* user_data); - static void dataForeachFunction(ExifContent* content, void* user_data); - void removeNulledAttributesFromExifData(ExifData* exif_data); void updateAttributesInExifData(ExifData* exif_data); diff --git a/src/exif/exif_instance.cc b/src/exif/exif_instance.cc index 9d5720ca..23650d30 100644 --- a/src/exif/exif_instance.cc +++ b/src/exif/exif_instance.cc @@ -19,6 +19,7 @@ #include "exif_util.h" #include "jpeg_file.h" #include "exif_information.h" +#include "get_exif_info.h" namespace extension { namespace exif { @@ -49,76 +50,18 @@ ExifInstance::~ExifInstance() { } void ExifInstance::getExifInfo(const picojson::value& args, picojson::object& out) { - LoggerD("ExifInstance::getExifInfo() in c++ A"); + LoggerD("enter"); const std::string& uri = args.get("uri").get(); const double callback_id = args.get("callbackId").get(); auto get = [=](const std::shared_ptr& response) -> void { try { - // uri = file:///opt/usr/media/Images/exif.jpg - // file_path = /opt/usr/media/Images/exif.jpg const std::string file_path = ExifUtil::convertUriToPath(uri); LoggerD("file_path = %s\n", file_path.c_str()); - LoggerD("ExifInformation::loadFromURI... %s", file_path.c_str()); - ExifInformationPtr exif_info = ExifInformation::loadFromURI(uri); - if (!exif_info) { - LoggerE("ExifInformation::loadFromURI failed for %s", - file_path.c_str()); - } - - unsigned long width = exif_info->getWidth(); - LoggerD("width = %d", width); - unsigned long height = exif_info->getHeight(); - LoggerD("height = %d", height); - const std::string& device_maker = exif_info->getDeviceMaker(); - LoggerD("device_maker = %s", device_maker.c_str()); - const std::string& device_model = exif_info->getDeviceModel(); - LoggerD("device_model = %s", device_model.c_str()); - const time_t original_time = exif_info->getOriginalTime(); - LoggerD("original_time = %s", asctime(localtime(&original_time))); - //... - - /* todo: all fields that need to be implemented: - DOMString uri; - unsigned long width; - unsigned long height; - DOMString deviceMaker; - DOMString deviceModel; - Date originalTime; - ImageContentOrientation orientation; - double fNumber; - unsigned short[] isoSpeedRatings; - DOMString exposureTime; - ExposureProgram exposureProgram; - boolean flash; - double focalLength; - WhiteBalanceMode whiteBalance; - SimpleCoordinates gpsLocation; - double gpsAltitude; - DOMString gpsProcessingMethod; - Date gpsTime; - DOMString userComment; -*/ - - JsonValue result = JsonValue(JsonObject()); - JsonObject& result_obj = result.get(); - std::ostringstream ss_width; - ss_width << width; - result_obj.insert(std::make_pair("width", ss_width.str().c_str())); - std::ostringstream ss_height; - ss_height << height; - result_obj.insert(std::make_pair("height", ss_height.str().c_str())); - result_obj.insert(std::make_pair("device_maker", device_maker.c_str())); - result_obj.insert(std::make_pair("device_model", device_model.c_str())); - // todo: convert to js type: Date - result_obj.insert(std::make_pair("original_time", - asctime(localtime(&original_time)))); - - // todo: implement remaining fields - - ReportSuccess(result, response->get()); + JsonValue result_direct = GetExifInfo::LoadFromURI(uri); + ReportSuccess(result_direct, response->get()); } catch (const common::PlatformException& e) { ReportError(e, response->get()); } @@ -136,7 +79,7 @@ void ExifInstance::getExifInfo(const picojson::value& args, get, get_response, std::shared_ptr(new JsonValue(JsonObject()))); - LoggerD("ExifInstance::getExifInfo() END (c++)"); + LoggerD("exit"); } void ExifInstance::saveExifInfo(const picojson::value& args, diff --git a/src/exif/exif_instance.h b/src/exif/exif_instance.h index 3bde59dc..1cf86a49 100644 --- a/src/exif/exif_instance.h +++ b/src/exif/exif_instance.h @@ -20,7 +20,7 @@ class ExifInstance : public common::ParsedInstance { void saveExifInfo(const picojson::value& args, picojson::object& out); void getThumbnail(const picojson::value& args, picojson::object& out); }; + } // namespace exif } // namespace extension - #endif // EXIF_EXIF_INSTANCE_H_ diff --git a/src/exif/exif_util.cc b/src/exif/exif_util.cc index ecc3b410..5dfb1009 100644 --- a/src/exif/exif_util.cc +++ b/src/exif/exif_util.cc @@ -219,38 +219,6 @@ bool ExifUtil::isValidAbsoluteURI(const std::string& uri) { return 0 == uri.find(URI_ABSOLUTE_PREFIX); } -void ExifUtil::getURIInfo(const std::string& uri, - // const Filesystem::NodeType expected_type, - const std::string& required_permission, - bool& out_exists, - // Filesystem::NodeType& out_type, - bool& out_permission_granted) { - const std::string absolute_path = ExifUtil::convertUriToPath(uri); - out_exists = false; - out_permission_granted = false; - - try { - // Filesystem::PathPtr path = Filesystem::Path::create(absolute_path); - // Filesystem::NodePtr node = Filesystem::Node::resolve(path); - // out_type = node->getType(); - // out_exists = true; - - // if (expected_type == out_type) { - // out_permission_granted = node->checkPermission(path, - // required_permission, - // expected_type); - // } - } - /* catch (const common::BasePlatformException &err) { - LoggerE("Couldn't resolve path: %s, got:%s (%s)", absolute_path.c_str(), - (err.getName()).c_str(), (err.getMessage()).c_str()); - } - */ - catch(...) { - LoggerE("Couldn't resolve path: %s", absolute_path.c_str()); - } -} - // Example: // in: uri = file:///opt/usr/media/Images/exif.jpg // out: path = /opt/usr/media/Images/exif.jpg @@ -323,7 +291,6 @@ const Rationals ExifUtil::timeTToExifGpsTimeStamp(time_t time) { return result; } - std::string ExifUtil::timeTToExifGpsDateStamp(time_t time) { int year, month, day, hour, min, sec; extractFromTimeT(time, year, month, day, hour, min, sec); diff --git a/src/exif/exif_util.h b/src/exif/exif_util.h index 7ccb0812..9e773723 100644 --- a/src/exif/exif_util.h +++ b/src/exif/exif_util.h @@ -119,10 +119,6 @@ class ExifUtil { static const std::string& exposureProgramToString(ExposureProgram value); static bool isValidAbsoluteURI(const std::string& uri); - static void getURIInfo(const std::string& uri, - const std::string& required_permission, - bool& out_exists, - bool& out_permission_granted); static std::string convertUriToPath(const std::string& str); static std::string ltrim(const std::string& s); diff --git a/src/exif/get_exif_info.cc b/src/exif/get_exif_info.cc new file mode 100644 index 00000000..e929d454 --- /dev/null +++ b/src/exif/get_exif_info.cc @@ -0,0 +1,518 @@ +// +// Tizen Web Device API +// Copyright (c) 2015 Samsung Electronics Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "get_exif_info.h" + +#include +#include +#include +#include + +#include "common/platform_exception.h" +#include "common/logger.h" + +#include "exif_util.h" + +namespace extension { +namespace exif { + +struct ExifDataHolder { + ExifData* exif_data; + JsonObject* result_obj_ptr; +}; + +Rational GetRationalFromEntry(ExifEntry *entry, ExifData* exif_data) { + if (EXIF_FORMAT_RATIONAL == entry->format + && entry->components >= 1 + && entry->data) { + const ExifByteOrder order = exif_data_get_byte_order(exif_data); + return Rational(exif_get_rational(entry->data, order)); + } else { + return Rational::createInvalid(); + } +} + +bool GetRationalsFromEntry(ExifEntry* entry, ExifData* exif_data, + unsigned long required_count, + Rationals& out_rationals) { + if (EXIF_FORMAT_RATIONAL == entry->format && + entry->components >= required_count && + entry->data) { + const ExifByteOrder order = exif_data_get_byte_order(exif_data); + unsigned char* ptr = entry->data; + + for (unsigned long i = 0; i < required_count; ++i) { + out_rationals.push_back(Rational(exif_get_rational(ptr, order))); + ptr += ExifTypeInfo::RationalSize; + } + + return true; + } else { + return false; + } +} + +bool GetGCSPositionFromEntry(ExifEntry* entry, ExifData* exif_data, + GCSPosition& out_pos) { + // RATIONAL - 3 + if (EXIF_FORMAT_RATIONAL == entry->format && + entry->components >= 3 && + entry->data) { + const ExifByteOrder order = exif_data_get_byte_order(exif_data); + out_pos.degrees = Rational(exif_get_rational(entry->data, order)); + out_pos.minutes = Rational(exif_get_rational( + entry->data + ExifTypeInfo::RationalSize, order)); + out_pos.seconds = Rational(exif_get_rational( + entry->data + 2*ExifTypeInfo::RationalSize, order)); + return true; + } else { + return false; + } +} + +bool DecomposeExifUndefined(ExifEntry* entry, std::string& type, std::string& value) { + if (!entry || !entry->data) { + LoggerW("exif entry is NULL/empty"); + return false; + } + + if (entry->size < EXIF_UNDEFINED_TYPE_LENGTH) { + LoggerW("entry size is invalid %d < EXIF_UNDEFINED_TYPE_LENGTH", entry->size); + return false; + } + + const char* ptr = reinterpret_cast(entry->data); + type = std::string(ptr, EXIF_UNDEFINED_TYPE_LENGTH); + ptr += EXIF_UNDEFINED_TYPE_LENGTH; + value = std::string(ptr, entry->size - EXIF_UNDEFINED_TYPE_LENGTH); + return true; +} + +void GetExifInfo::ProcessEntry(ExifEntry* entry, ExifData* exif_data, + JsonObject* result_obj) { + char buf[2000]; + exif_entry_get_value(entry, buf, sizeof(buf)); + ExifUtil::printExifEntryInfo(entry, exif_data); + + const ExifIfd cur_ifd = exif_entry_get_ifd(entry); + if (EXIF_IFD_INTEROPERABILITY == cur_ifd || EXIF_IFD_1 == cur_ifd) { + return; + } + + std::pair pair; + switch (static_cast(entry->tag)) { + case EXIF_TAG_IMAGE_WIDTH: { + exif_entry_get_value(entry, buf, sizeof(buf)); + LoggerD("Setting ExifInformation width to: [%s]", buf); + pair = std::make_pair("width", std::string(buf)); + result_obj->insert(pair); + break; + } + case EXIF_TAG_IMAGE_LENGTH: { + exif_entry_get_value(entry, buf, sizeof(buf)); + LoggerD("Setting ExifInformation height to: [%s]", buf); + pair = std::make_pair("height", std::string(buf)); + result_obj->insert(pair); + break; + } + case EXIF_TAG_MAKE: { + exif_entry_get_value(entry, buf, sizeof(buf)); + LoggerD("Setting ExifInformation maker to: [%s]", buf); + pair = std::make_pair("deviceMaker", std::string(buf)); + result_obj->insert(pair); + break; + } + case EXIF_TAG_MODEL: { + exif_entry_get_value(entry, buf, sizeof(buf)); + LoggerD("Setting ExifInformation model to: [%s]", buf); + pair = std::make_pair("deviceModel", std::string(buf)); + result_obj->insert(pair); + break; + } + case EXIF_TAG_DATE_TIME_ORIGINAL: { + // ASCII - 20 + exif_entry_get_value(entry, buf, sizeof(buf)); + const time_t time = ExifUtil::exifDateTimeOriginalToTimeT( + reinterpret_cast(entry->data)); + LoggerD("Setting ExifInformation time original to: [%s] time_t:%d", buf, + static_cast(time)); + // convert time_t (number of seconds) to string + pair = std::make_pair("originalTimeSeconds", + std::to_string(static_cast(time))); + result_obj->insert(pair); + break; + } + case EXIF_TAG_ORIENTATION: { + // SHORT - 1 + exif_entry_get_value(entry, buf, sizeof(buf)); + const ExifByteOrder order = exif_data_get_byte_order(exif_data); + const ExifShort orient(exif_get_short(entry->data, order)); + + std::string orientation = ExifUtil::orientationToString( + static_cast(orient)); + pair = std::make_pair("orientation", orientation); + result_obj->insert(pair); + + if (orient < EXIF_ORIENTATION_NORMAL || orient >= EXIF_ORIENTATION_NOT_VALID) { + LoggerW("Couldn't set ExifInformation - orientation is not valid: %d (%s)", + orient, buf); + } else { + LoggerD("Setting ExifInformation orientation to: %d [%s]", orient, buf); + } + break; + } + case EXIF_TAG_FNUMBER: + { + // RATIONAL - 1 + Rational fnumber = GetRationalFromEntry(entry, exif_data); + if (fnumber.isValid()) { + LoggerD("Setting ExifInformation fnumber to: %f (%s)", fnumber.toDouble(), + fnumber.toString().c_str()); + pair = std::make_pair("fNumber", std::to_string(fnumber.toDouble())); + result_obj->insert(pair); + } else { + LoggerW("Couldn't set ExifInformation - fnumber is not valid: %s", + fnumber.toString().c_str()); + } + break; + } + case EXIF_TAG_ISO_SPEED_RATINGS: { + // SHORT - Any + if (EXIF_FORMAT_SHORT == entry->format && + entry->components > 0 && + entry->data) { + const ExifByteOrder order = exif_data_get_byte_order(exif_data); + unsigned char* read_ptr = entry->data; + const size_t size_per_member = + ExifUtil::getSizeOfExifFormatType(entry->format); + + JsonArray array = picojson::array(); + for (unsigned long i = 0; i < entry->components; ++i) { + ExifShort iso_rating = exif_get_short(read_ptr, order); + array.push_back(picojson::value(std::to_string(iso_rating))); + + LoggerD("Appending ExifInformation speed ratings with: %d", + static_cast(iso_rating)); + + read_ptr += size_per_member; + } + std::pair pair_array; + pair_array = std::make_pair("isoSpeedRatings", array); + result_obj->insert(pair_array); + } else { + LoggerE("iso speed ratings: format or components count is invalid!"); + throw common::TypeMismatchException("iso speed ratings: format or" + " components count is invalid!"); + } + break; + } + case EXIF_TAG_EXPOSURE_TIME: { + // RATIONAL - 1 + if (EXIF_FORMAT_RATIONAL == entry->format && + entry->components > 0 && + entry->data) { + const ExifByteOrder order = exif_data_get_byte_order(exif_data); + const Rational exp_time(exif_get_rational(entry->data, order)); + + if (exp_time.isValid()) { + LoggerD("Setting ExifInformation exposure time to: %s (%s)", + exp_time.toString().c_str(), + exp_time.toExposureTimeString().c_str()); + pair = std::make_pair("exposureTime", std::to_string(exp_time.toDouble())); + result_obj->insert(pair); + } else { + LoggerD("Couldn't set ExifInformation - exposure time is not valid: %s", + exp_time.toString().c_str()); + } + } else { + LoggerE("exposure time: format or components count is invalid!"); + throw common::TypeMismatchException("exposure time: format or" + " components count is invalid!"); + } + break; + } + case EXIF_TAG_EXPOSURE_PROGRAM: { + // SHORT - 1 + exif_entry_get_value(entry, buf, sizeof(buf)); + + const ExifByteOrder order = exif_data_get_byte_order(exif_data); + const ExifShort exp_program = exif_get_short(entry->data, order); + if (exp_program >= EXIF_EXPOSURE_PROGRAM_NOT_VALID) { + LoggerW("ExposureProgram: %d (%s) is not valid!", exp_program, buf); + } else { + LoggerD("Setting ExifInformation exposure program to: %d [%s]", + exp_program, buf); + std::string exp_program_string = + ExifUtil::exposureProgramToString(static_cast(exp_program)); + pair = std::make_pair("exposureProgram", exp_program_string); + result_obj->insert(pair); + } + break; + } + case EXIF_TAG_FLASH: { + // SHORT - 1 + exif_entry_get_value(entry, buf, sizeof(buf)); + + const ExifByteOrder order = exif_data_get_byte_order(exif_data); + const ExifShort flash = exif_get_short(entry->data, order); + + LoggerD("Setting ExifInformation flash to: [%s] flash=%d", buf, flash); + pair = std::make_pair("flash", (flash != 0) ? std::string("true") : std::string("false")); + result_obj->insert(pair); + break; + } + case EXIF_TAG_FOCAL_LENGTH: { + // RATIONAL - 1 + Rational flength = GetRationalFromEntry(entry, exif_data); + if (flength.isValid()) { + LoggerD("Setting ExifInformation focal length to: %f (%s)", + flength.toDouble(), flength.toString().c_str()); + pair = std::make_pair("focalLength", std::to_string(flength.toDouble())); + result_obj->insert(pair); + } else { + LoggerW("Couldn't set ExifInformation - focal length is not valid: %s", + flength.toString().c_str()); + } + break; + } + case EXIF_TAG_WHITE_BALANCE: { + // SHORT - 1 + exif_entry_get_value(entry, buf, sizeof(buf)); + LoggerD("Setting ExifInformation white balance to: [%s]", buf); + pair = std::make_pair("whiteBalanceValue", + std::to_string(static_cast(entry->data[0]))); + result_obj->insert(pair); + break; + } + case EXIF_TAG_GPS_LONGITUDE: { + // RATIONAL - 3 + GCSPosition longitude; + if (GetGCSPositionFromEntry(entry, exif_data, longitude)) { + pair = std::make_pair("gpsLongitudeDegrees", std::to_string(longitude.degrees.toDouble())); + result_obj->insert(pair); + pair = std::make_pair("gpsLongitudeMinutes", std::to_string(longitude.minutes.toDouble())); + result_obj->insert(pair); + pair = std::make_pair("gpsLongitudeSeconds", std::to_string(longitude.seconds.toDouble())); + result_obj->insert(pair); + LoggerD("Setting ExifInformation gps longitude to: %s; %s; %s valid:%d", + longitude.degrees.toString().c_str(), + longitude.minutes.toString().c_str(), + longitude.seconds.toString().c_str(), + longitude.isValid()); + } else { + LoggerW("Couldn't set longitude pos - data is not valid."); + } + break; + } + case EXIF_TAG_GPS_LONGITUDE_REF: { + // ASCII - 2 + if (entry->size < 1) { + LoggerW("Longitude ref entry do not contain enough data!"); + break; + } + + const char ref = static_cast(entry->data[0]); + if ('E' == ref || 'e' == ref) { // East + pair = std::make_pair("gpsLongitudeRef", std::string("EAST")); + result_obj->insert(pair); + LoggerD("Setting ExifInformation gps longitude REF to: EAST"); + } else if ('W' == ref || 'w' == ref) { // West + pair = std::make_pair("gpsLongitudeRef", std::string("WEST")); + result_obj->insert(pair); + LoggerD("Setting ExifInformation gps longitude REF to: WEST"); + } else { + LoggerW("Unknown longitude ref: %c (0x%x)", ref, static_cast(ref)); + } + break; + } + case EXIF_TAG_GPS_LATITUDE: { + // RATIONAL - 3 + exif_entry_get_value(entry, buf, sizeof(buf)); + LoggerD("Setting ExifInformation latitude to: [%s], tag->%s", + buf, exif_tag_get_name(entry->tag) ); + + GCSPosition latitude; + if (GetGCSPositionFromEntry(entry, exif_data, latitude)) { + pair = std::make_pair("gpsLatitudeDegrees", std::to_string(latitude.degrees.toDouble())); + result_obj->insert(pair); + pair = std::make_pair("gpsLatitudeMinutes", std::to_string(latitude.minutes.toDouble())); + result_obj->insert(pair); + pair = std::make_pair("gpsLatitudeSeconds", std::to_string(latitude.seconds.toDouble())); + result_obj->insert(pair); + + LoggerD("Setting ExifInformation gps latitude to: %s; %s; %s valid:%d", + latitude.degrees.toString().c_str(), + latitude.minutes.toString().c_str(), + latitude.seconds.toString().c_str(), + latitude.isValid()); + } else { + LoggerW("Couldn't set latitude pos - data is not valid!"); + } + break; + } + case EXIF_TAG_GPS_LATITUDE_REF: { + // ASCII - 2 + if (entry->size < 1) { + LoggerW("Latitude ref entry do not contain enough data!"); + break; + } + + const char ref = static_cast(entry->data[0]); + if ('N' == ref || 'n' == ref) { // North + pair = std::make_pair("gpsLatitudeRef", std::string("NORTH")); + result_obj->insert(pair); + LoggerD("Setting ExifInformation gps latitude REF to: NORTH"); + } else if ('S' == ref || 's' == ref) { // South + pair = std::make_pair("gpsLatitudeRef", std::string("SOUTH")); + LoggerD("Setting ExifInformation gps latitude REF to: SOUTH"); + } else { + LoggerW("Unknown latitude ref: %c (0x%x)", ref, static_cast(ref)); + } + break; + } + case EXIF_TAG_GPS_ALTITUDE: { + // RATIONAL - 1 + Rational gps_altitude = GetRationalFromEntry(entry, exif_data); + if (gps_altitude.isValid()) { + LoggerD("Setting ExifInformation gps altitude to: %f (%s)", + gps_altitude.toDouble(), gps_altitude.toString().c_str()); + pair = std::make_pair("gpsAltitude", std::to_string(gps_altitude.toDouble())); + result_obj->insert(pair); + } else { + LoggerW("Couldn't set ExifInformation - gps altitude is not valid: %s", + gps_altitude.toString().c_str()); + } + break; + } + case EXIF_TAG_GPS_ALTITUDE_REF: { + // BYTE - 1 + const ExifByte altitude_ref = static_cast(entry->data[0]); + pair = std::make_pair("gpsAltitudeRef", std::to_string(static_cast(altitude_ref))); + LoggerD("Setting ExifInformation gps altitude ref to: %d (%s)", + static_cast(altitude_ref), + (altitude_ref > 0) ? "below sea level" : "above sea level"); + + break; + } + case EXIF_TAG_GPS_PROCESSING_METHOD: { + // UNDEFINED - Any + std::string type, value; + if (DecomposeExifUndefined(entry, type, value)) { + LoggerD("Extracted GPSProcessingMethod: [%s], len:%d, type:%s", + value.c_str(), value.length(), type.c_str()); + pair = std::make_pair("gpsProcessingMethod", value); + result_obj->insert(pair); + } else { + LoggerW("GPSProcessingMethod tag contains invalid values!"); + } + break; + } + case EXIF_TAG_GPS_DATE_STAMP: { + // ASCII - 11 + pair = std::make_pair("gpsExifDate", std::string(buf)); + result_obj->insert(pair); + LoggerD("Setting ExifInformation gps date stamp to %s", pair.second.c_str()); + break; + } + case EXIF_TAG_GPS_TIME_STAMP: { + // Rational - 3 + LoggerD("Setting ExifInformation gps time stamp to: [%s]", buf); + + Rationals time; + if (GetRationalsFromEntry(entry, exif_data, 3, time)) { + pair = std::make_pair("gpsExifTimeHours", std::to_string(time[0].toDouble())); + result_obj->insert(pair); + pair = std::make_pair("gpsExifTimeMinutes", std::to_string(time[1].toDouble())); + result_obj->insert(pair); + pair = std::make_pair("gpsExifTimeSeconds", std::to_string(time[2].toDouble())); + result_obj->insert(pair); + } + break; + } + case EXIF_TAG_USER_COMMENT: { + // UNDEFINED - Any + std::string type, value; + if (DecomposeExifUndefined(entry, type, value)) { + LoggerD("Extracted UserComment: [%s], len:%d, type:%s", + value.c_str(), value.length(), type.c_str()); + + pair = std::make_pair("userComment", value); + result_obj->insert(pair); + } else { + LoggerW("UserComment tag contains invalid values!"); + } + break; + } + } +} + +void GetExifInfo::ContentForeachFunctionProxy(ExifEntry *entry, void *user_data) { + ExifDataHolder* holder = static_cast(user_data); + if (!holder) { + LoggerE("holder is NULL"); + } + + if (!holder->exif_data) { + LoggerE("exif_data is NULL!"); + return; + } + + JsonObject* result_obj_ptr = holder->result_obj_ptr; + + try { + ProcessEntry(entry, holder->exif_data, result_obj_ptr); + } + catch(...) { + LoggerE("Unsupported error while processing Exif entry."); + } +} + +void GetExifInfo::DataForeachFunction(ExifContent *content, void *user_data) { + exif_content_foreach_entry(content, ContentForeachFunctionProxy, user_data); +} + +JsonValue GetExifInfo::LoadFromURI(const std::string& uri) { + const std::string file_path = ExifUtil::convertUriToPath(uri); + ExifData* ed = exif_data_new_from_file(file_path.c_str()); + if (!ed) { + LoggerE("Error reading exif from file %s", file_path.c_str()); + throw common::NotFoundException("Error reading exif from file"); + } + + LoggerD("loadFromURI_into_json exif_data_foreach_content START"); + + JsonValue result = JsonValue(JsonObject()); + JsonObject& result_obj = result.get(); + + ExifDataHolder holder; + holder.exif_data = ed; + holder.result_obj_ptr = &result_obj; + exif_data_foreach_content(ed, DataForeachFunction, static_cast(&holder)); + + LoggerD("loadFromURI_into_json exif_data_foreach_content END"); + + exif_data_unref(ed); + ed = NULL; + + // uri is not taken from jgp Exif, so we add it here + holder.result_obj_ptr->insert(std::make_pair("uri", uri)); + + return result; +} + +} // namespace exif +} // namespace extension diff --git a/src/exif/get_exif_info.h b/src/exif/get_exif_info.h new file mode 100644 index 00000000..47a2334c --- /dev/null +++ b/src/exif/get_exif_info.h @@ -0,0 +1,57 @@ +// +// Tizen Web Device API +// Copyright (c) 2015 Samsung Electronics Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef WEBAPI_PLUGINS_EXIF_GET_EXIF_INFO_H_ +#define WEBAPI_PLUGINS_EXIF_GET_EXIF_INFO_H_ + +#include +#include + +#include "exif_gps_location.h" + +#include "common/extension.h" +#include "common/picojson.h" + +typedef picojson::value JsonValue; +typedef picojson::object JsonObject; +typedef picojson::array JsonArray; +typedef std::string JsonString; + +namespace extension { +namespace exif { + +extern const size_t EXIF_UNDEFINED_TYPE_LENGTH; + +class GetExifInfo { + public: + static void ProcessEntry(ExifEntry* entry, ExifData* exif_data, + JsonObject* result_obj); + static JsonValue LoadFromURI(const std::string& uri); + + private: + GetExifInfo() { } // private ctor - class can not be created + + static void ContentForeachFunctionProxy(ExifEntry* entry, void* user_data); + static void DataForeachFunction(ExifContent* content, void* user_data); +}; + +typedef std::shared_ptr GetExifInfoPtr; + +} // namespace exif +} // namespace extension + +#endif // WEBAPI_PLUGINS_EXIF_GET_EXIF_INFO_H__ -- 2.34.1