From: Rafal Lelusz Date: Wed, 7 Jan 2015 13:08:06 +0000 (+0100) Subject: [Exif] Add libexif dependency, partial implementation of getExifInfo() X-Git-Tag: submit/tizen_tv/20150603.064601~1^2~673 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=68f5bca060eab652e37b5e9942c349642dab6e63;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [Exif] Add libexif dependency, partial implementation of getExifInfo() Change-Id: I9d4d8e95fdb8940cb1013f2bbd86359d226c441d Signed-off-by: Rafal Lelusz --- diff --git a/src/exif/ExifGPSLocation.cpp b/src/exif/ExifGPSLocation.cpp new file mode 100644 index 00000000..c5349077 --- /dev/null +++ b/src/exif/ExifGPSLocation.cpp @@ -0,0 +1,302 @@ +// +// Tizen Web Device API +// Copyright (c) 2014 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 "ExifGPSLocation.h" + +#include +#include + +#include "common/platform_exception.h" +#include "common/logger.h" + +namespace extension { +namespace exif { + +GCSPosition::GCSPosition() +{ +} + +GCSPosition::GCSPosition(Rational _degrees, Rational _minutes, Rational _seconds) : + degrees(_degrees), + minutes(_minutes), + seconds(_seconds) +{ +} + +bool GCSPosition::isValid() const +{ + if (!(degrees.isValid() && minutes.isValid() && seconds.isValid())) { + return false; + } + + if ((degrees.toDouble() > 180.0f) || + (minutes.toDouble() > 60.0f) || + (seconds.toDouble() > 60.0f)) { + return false; + } + + return toDouble() <= 180.0f; +} + +double GCSPosition::toDouble() const +{ + const double degrees_value = degrees.toDouble(); + const double minutes_value = minutes.toDouble(); + const double seconds_value = seconds.toDouble(); + return (degrees_value + (minutes_value/60.0) + (seconds_value/3600.0)); +} + +Rationals GCSPosition::toRationalsVector() const +{ + Rationals vec; + vec.push_back(degrees); + vec.push_back(minutes); + vec.push_back(seconds); + return vec; +} + +std::string GCSPosition::toDebugString() const +{ + std::stringstream ss; + ss << degrees.toString() << "d "; + ss << minutes.toString() << "m "; + ss << seconds.toString() << "s"; + return ss.str(); +} + +GCSPosition GCSPosition::createFromDouble(double value) +{ + LoggerD("Entered value:%f"); + if (value < 0) { + LoggerW("Trying to create GCSPosition with double < 0: %f", value); + return GCSPosition(); + } + + if (value > 180.0) { + LoggerW("Trying to create GCSPosition with double > 180.0: %f", value); + return GCSPosition(); + } + + const double d_degrees = floor(value); + double left = value - d_degrees; + + const double d_minutes = floor(left * 60.0); + left -= d_minutes / 60.0; + + const double d_seconds = left * 3600.0; + + LOGD("d_degrees:%f d_minutes:%f d_seconds:%f", d_degrees, d_minutes, d_seconds); + + GCSPosition pos; + pos.degrees = Rational(static_cast(d_degrees), 1); + pos.minutes = Rational(static_cast(d_minutes), 1); + pos.seconds = Rational::createFromDouble(d_seconds); + return pos; +} + +ExifGPSLocation::ExifGPSLocation() : + m_longitude_ref(GPS_LOCATION_WEST), + m_latitude_ref(GPS_LOCATION_NORTH) +{ + for(int i = 0; i < EXIF_GPS_LOCATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES; ++i) { + m_is_set[i] = false; + } + LoggerE("ExifGPSLocation::ExifGPSLocation()"); +} + +void ExifGPSLocation::setLongitude(const GCSPosition& longitude) +{ + if (!longitude.isValid()) { + LoggerW("longitude is not valid!"); + return; + } + + m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE] = true; + m_longitude = longitude; +} + +const GCSPosition& ExifGPSLocation::getLongitude() const +{ + return m_longitude; +} + +void ExifGPSLocation::setLongitudeRef(GPSLocationDirectionLongitude ref) +{ + m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF] = true; + m_longitude_ref = ref; +} + +GPSLocationDirectionLongitude ExifGPSLocation::getLongitudeRef() const +{ + return m_longitude_ref; +} + +void ExifGPSLocation::setLatitude(const GCSPosition& latitude) +{ + if (!latitude.isValid()) { + LOGW("latitude is not valid!"); + return; + } + + m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE] = true; + m_latitude = latitude; +} + +const GCSPosition& ExifGPSLocation::getLatitude() const +{ + return m_latitude; +} + +void ExifGPSLocation::setLatitudeRef(GPSLocationDirectionLatitude ref) +{ + m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF] = true; + m_latitude_ref = ref; +} + +GPSLocationDirectionLatitude ExifGPSLocation::getLatitudeRef() const +{ + return m_latitude_ref; +} + +bool ExifGPSLocation::isSet(ExifGPSLocationAttributes attribute) const +{ + return m_is_set[attribute]; +} + +void ExifGPSLocation::unset(ExifGPSLocationAttributes attribute) +{ + m_is_set[attribute] = false; +} + +void ExifGPSLocation::unsetAll() +{ + m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE] = false; + m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF] = false; + m_longitude = GCSPosition(); + + m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE] = false; + m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF] = false; + m_latitude = GCSPosition(); +} + +bool ExifGPSLocation::isComplete() const +{ + return m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE] && + m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF] && + m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE] && + m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF]; +} + + +bool ExifGPSLocation::isValid() const +{ + return isComplete() && m_latitude.isValid() && m_longitude.isValid(); +} +/* +Tizen::SimpleCoordinatesPtr ExifGPSLocation::getSimpleCoordinates() const +{ + if (!isComplete()) { + LoggerW("Some attributes are not set!"); + return Tizen::SimpleCoordinatesPtr(); + } + + if (!isValid()) { + LoggerW("Some attributes are not valid!"); + return Tizen::SimpleCoordinatesPtr(); + } + + const double cur_latitude = getLatitudeValue(); + const double cur_longitude = getLongitudeValue(); + + return Tizen::SimpleCoordinatesPtr( + new Tizen::SimpleCoordinates(cur_latitude, cur_longitude)); +}*/ + +double ExifGPSLocation::getLongitudeValue() const +{ + const double longitude_dir = (m_longitude_ref == GPS_LOCATION_WEST) ? -1.0f : 1.0f; + const double longitude = m_longitude.toDouble() * longitude_dir; + return longitude; +} + +double ExifGPSLocation::getLatitudeValue() const +{ + const double latitude_dir = (m_latitude_ref == GPS_LOCATION_SOUTH) ? -1.0f : 1.0f; + const double latitude = m_latitude.toDouble() * latitude_dir; + return latitude; +} +/* +bool ExifGPSLocation::set(Tizen::SimpleCoordinatesPtr scoords) +{ + LoggerD("Entered"); + if (!scoords) { + LOGW("Trying to set null SimpleCoordinates!"); + return false; + } + + const double longitude = scoords->getLongitude(); + const double latitude = scoords->getLatitude(); + bool updateLongitude = true; + bool updateLatitude = true; + + if(isComplete()) { + updateLatitude = getLatitudeValue() != latitude; + updateLongitude = getLongitudeValue() != longitude; + } + + LoggerD("latitude:%f longitude:%f", latitude, longitude); + + GCSPosition gcs_longitude = GCSPosition::createFromDouble(fabs(longitude)); + LOGD("gcs_longitude deg:%s min:%s sec:%s", gcs_longitude.degrees.toString().c_str(), + gcs_longitude.minutes.toString().c_str(), + gcs_longitude.seconds.toString().c_str()); + + GCSPosition gcs_latitude = GCSPosition::createFromDouble(fabs(latitude)); + LoggerD("gcs_latitude deg:%s min:%s sec:%s", gcs_latitude.degrees.toString().c_str(), + gcs_latitude.minutes.toString().c_str(), + gcs_latitude.seconds.toString().c_str()); + + if (!gcs_latitude.isValid() || !gcs_longitude.isValid()) { + return false; + } + + if(updateLongitude) { + setLongitude(gcs_longitude); + if (longitude >= 0.0) { + setLongitudeRef(GPS_LOCATION_EAST); + } + else { + setLongitudeRef(GPS_LOCATION_WEST); + } + } + + if(updateLatitude) { + setLatitude(gcs_latitude); + if (latitude >= 0.0) { + setLatitudeRef(GPS_LOCATION_NORTH); + } + else { + setLatitudeRef(GPS_LOCATION_SOUTH); + } + } + + return true; +} +*/ + +} // exif +} // extension diff --git a/src/exif/ExifGPSLocation.h b/src/exif/ExifGPSLocation.h new file mode 100644 index 00000000..4c5103c2 --- /dev/null +++ b/src/exif/ExifGPSLocation.h @@ -0,0 +1,149 @@ +// +// Tizen Web Device API +// Copyright (c) 2014 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 __TIZEN_EXIF_EXIF_GPS_LOCATION_H_ +#define __TIZEN_EXIF_EXIF_GPS_LOCATION_H_ + +#include +#include + +//#include + +#include "ExifUtil.h" +#include "Rational.h" + +namespace extension { +namespace exif { + +enum GPSLocationDirectionLongitude { + GPS_LOCATION_WEST, + GPS_LOCATION_EAST +}; + +enum GPSLocationDirectionLatitude { + GPS_LOCATION_NORTH, + GPS_LOCATION_SOUTH +}; + +enum ExifGPSLocationAttributes { + EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE = 0, + EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF, + EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE, + EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF, + EXIF_GPS_LOCATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES +}; + +/** + * This class represents Global Coordinate System using + * three Rational numbers (as stored in Exif) + */ +struct GCSPosition +{ + GCSPosition(); + GCSPosition(Rational degrees, Rational minutes, Rational seconds); + + /** + * Create GCSPosition from degrees represented as double value + */ + static GCSPosition createFromDouble(double value); + + /** + * Verify that all components are valid Rational numbers and + * each component is within valid range. Sum of degrees, + * minutes and seconds should not be bigger then 180.0 + */ + bool isValid() const; + + /** + * Return position in degrees + */ + double toDouble() const; + + /** + * Return vector of three rationals: degrees, minutes, seconds + */ + Rationals toRationalsVector() const; + + /** + * Return string for debugging purposes + */ + std::string toDebugString() const; + + Rational degrees; + Rational minutes; + Rational seconds; +}; + +class ExifGPSLocation +{ +public: + ExifGPSLocation(); + + void setLongitude(const GCSPosition& longitude); + const GCSPosition& getLongitude() const; + + void setLongitudeRef(GPSLocationDirectionLongitude ref); + GPSLocationDirectionLongitude getLongitudeRef() const; + + void setLatitude(const GCSPosition& latitude); + const GCSPosition& getLatitude() const; + + void setLatitudeRef(GPSLocationDirectionLatitude ref); + GPSLocationDirectionLatitude getLatitudeRef() const; + + bool isSet(ExifGPSLocationAttributes attribute) const; + void unset(ExifGPSLocationAttributes attribute); + void unsetAll(); + + /** + * Returns true only if all components are set. + */ + bool isComplete() const; + + /** + * Returns true only if all components are set and valid. + */ + bool isValid() const; + + /** + * Returns null pointer if any information is missing or incorrect + */ + //Tizen::SimpleCoordinatesPtr getSimpleCoordinates() const; + + /** + * Return true if scoords has been set + */ + //bool set(Tizen::SimpleCoordinatesPtr scoords); + +private: + + double getLongitudeValue() const; + double getLatitudeValue() const; + + GCSPosition m_longitude; + GPSLocationDirectionLongitude m_longitude_ref; + + GCSPosition m_latitude; + GPSLocationDirectionLatitude m_latitude_ref; + + bool m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES]; +}; + +} // exif +} // extension + +#endif // __TIZEN_EXIF_EXIF_GPS_LOCATION_H_ diff --git a/src/exif/ExifInformation.cpp b/src/exif/ExifInformation.cpp new file mode 100644 index 00000000..a5223e67 --- /dev/null +++ b/src/exif/ExifInformation.cpp @@ -0,0 +1,1340 @@ +// +// Tizen Web Device API +// Copyright (c) 2014 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 "ExifInformation.h" + +#include +#include + +#include "ExifTagSaver.h" +#include "ExifUtil.h" +#include "JpegFile.h" + +#include "common/platform_exception.h" +#include "common/logger.h" + +namespace extension { +namespace exif { + +const size_t EXIF_UNDEFINED_TYPE_LENGTH = 8; +const std::string EXIF_UNDEFINED_TYPE_ASCII = + std::string("ASCII\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH); +const std::string EXIF_UNDEFINED_TYPE_JIS = + std::string("JIS\0\0\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH); +const std::string EXIF_UNDEFINED_TYPE_UNICODE = + std::string("UNICODE\0", EXIF_UNDEFINED_TYPE_LENGTH); +const std::string EXIF_UNDEFINED_TYPE_UNDEFINED = + std::string("\0\0\0\0\0\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH); + +ExifInformation::ExifInformation() +{ + for (int attr = 0; attr < EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES; attr++) { + unset(static_cast(attr)); + } +} + +ExifInformation::~ExifInformation() { } + +const std::string& ExifInformation::getUri() +{ + LoggerD("Entered"); + return m_uri; +} + +void ExifInformation::setUri(const std::string& uri) +{ + LoggerD("Entered"); + m_is_set[EXIF_INFORMATION_ATTRIBUTE_URI] = true; + m_uri = uri; +} + +unsigned long ExifInformation::getWidth() const +{ + LoggerD("Entered"); + return m_width; +} + +void ExifInformation::setWidth(unsigned long width) +{ + LoggerD("Entered"); + m_is_set[EXIF_INFORMATION_ATTRIBUTE_WIDTH] = true; + m_width = width; +} + +unsigned long ExifInformation::getHeight() const +{ + LoggerD("Entered"); + return m_height; +} + +void ExifInformation::setHeight(unsigned long height) +{ + LoggerD("Entered"); + m_is_set[EXIF_INFORMATION_ATTRIBUTE_HEIGHT] = true; + m_height = height; +} + +const std::string& ExifInformation::getDeviceMaker() +{ + LoggerD("Entered"); + return m_device_maker; +} + +void ExifInformation::setDeviceMaker(const std::string& device_maker) +{ + LoggerD("Entered"); + m_is_set[EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER] = true; + m_device_maker = device_maker; +} + +const std::string& ExifInformation::getDeviceModel() +{ + LoggerD("Entered"); + return m_device_model; +} + +void ExifInformation::setDeviceModel(const std::string& device_model) +{ + LoggerD("Entered"); + m_is_set[EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL] = true; + m_device_model = device_model; +} + +time_t ExifInformation::getOriginalTime() const +{ + LoggerD("Entered"); + return m_original_time; +} + +void ExifInformation::setOriginalTime(time_t original_time) +{ + LoggerD("Entered"); + m_is_set[EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME] = true; + m_original_time = original_time; +} + +ImageOrientation ExifInformation::getOrientation() const +{ + LoggerD("Entered"); + return m_orientation; +} + +void ExifInformation::setOrientation(ImageOrientation orientation) +{ + LoggerD("Entered"); + if(EXIF_ORIENTATION_NOT_VALID == orientation) { + LOGW("Trying to set NOT VALID orientation"); + return; + } + + m_is_set[EXIF_INFORMATION_ATTRIBUTE_ORIENTATION] = true; + m_orientation = orientation; +} + +const Rational& ExifInformation::getFNumber() const +{ + LoggerD("Entered"); + return m_f_number; +} + +void ExifInformation::setFNumber(Rational f_number) +{ + LoggerD("Entered"); + if (!f_number.isValid()) { + LoggerW("Trying to set invalid F-Number: %s", f_number.toString().c_str()); + return; + } + + m_is_set[EXIF_INFORMATION_ATTRIBUTE_FNUMBER] = true; + m_f_number = f_number; +} +/* +Common::JSLongLongVector ExifInformation::getIsoSpeedRatings() +{ + LoggerD("Entered"); + return m_iso_speed_ratings; +}*/ +/* +void ExifInformation::setIsoSpeedRatings( + const std::vector& iso_speed_ratings) +{ + LoggerD("Entered"); + m_is_set[EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS] = true; + m_iso_speed_ratings = iso_speed_ratings; +}*/ + +void ExifInformation::appendIsoSpeedRatings(long long int iso_speed_rating) +{ + m_is_set[EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS] = true; + //m_iso_speed_ratings.push_back(iso_speed_rating); +} + +const Rational& ExifInformation::getExposureTime() +{ + LoggerD("Entered"); + return m_exposure_time; +} + +void ExifInformation::setExposureTime(const Rational& exposure_time) +{ + LoggerD("Entered"); + if (!exposure_time.isValid() || 0 == exposure_time.nominator) { + LoggerW("Trying to set invalid exposure time: [%s]", + exposure_time.toString().c_str()); + return; + } + + m_is_set[EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME] = true; + m_exposure_time = exposure_time; +} + +ExposureProgram ExifInformation::getExposureProgram() +{ + LoggerD("Entered"); + return m_exposure_program; +} + +void ExifInformation::setExposureProgram(ExposureProgram exposure_program) +{ + LoggerD("Entered"); + if (EXIF_EXPOSURE_PROGRAM_NOT_VALID == exposure_program) { + LOGW("Trying to set NOT VALID exposure program"); + return; + } + + m_is_set[EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM] = true; + m_exposure_program = exposure_program; +} + +bool ExifInformation::getFlash() const +{ + LoggerD("Entered"); + return m_flash; +} + +void ExifInformation::setFlash(bool flash) +{ + LoggerD("Entered"); + m_is_set[EXIF_INFORMATION_ATTRIBUTE_FLASH] = true; + m_flash = flash; +} + +const Rational& ExifInformation::getFocalLength() const +{ + LoggerD("Entered"); + return m_focal_length; +} + +void ExifInformation::setFocalLength(Rational focal_length) +{ + LoggerD("Entered"); + if(!focal_length.isValid()) { + LoggerW("Trying to set invalid focal length: %s", focal_length.toString().c_str()); + return; + } + + m_is_set[EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH] = true; + m_focal_length = focal_length; +} + +WhiteBalanceMode ExifInformation::getWhiteBalanceMode() const +{ + LoggerD("Entered"); + return m_white_balance; +} + +void ExifInformation::setWhiteBalanceMode(WhiteBalanceMode white_balance) +{ + LoggerD("Entered"); + if (EXIF_WHITE_BALANCE_MODE_NOT_VALID == white_balance) { + LOGW("Trying to set NOT VALID white balance mode"); + return; + } + + m_is_set[EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE] = true; + m_white_balance = white_balance; +} + +ExifGPSLocation& ExifInformation::getGPSExifLocation() +{ + return m_exif_gps_location; +} +/* +Tizen::SimpleCoordinatesPtr ExifInformation::getGPSLocation() +{ + if(m_gps_location) { + return m_gps_location; + } + + + Tizen::SimpleCoordinatesPtr nscoords = m_exif_gps_location.getSimpleCoordinates(); + if(!nscoords) { + return nscoords; + } + + m_gps_location = nscoords; + return m_gps_location; +}*/ +/* +void ExifInformation::setGPSLocation(Tizen::SimpleCoordinatesPtr gps_location) +{ + if(!gps_location) { + LoggerW("Trying to set NULL gps location!"); + return; + } + + m_gps_location = gps_location; +}*/ + +void ExifInformation::unsetGPSLocation() +{ + //m_gps_location = Tizen::SimpleCoordinatesPtr(); + m_exif_gps_location.unsetAll(); +} + +const Rational& ExifInformation::getGpsAltitude() const +{ + LoggerD("Entered"); + return m_gps_altitude; +} + +void ExifInformation::setGpsAltitude(Rational gps_altitude) +{ + LoggerD("Entered"); + if (!gps_altitude.isValid()) { + LoggerW("Trying to set invalid gps altitude: %s", gps_altitude.toString().c_str()); + return; + } + + m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE] = true; + m_gps_altitude = gps_altitude; +} + +GpsAltitudeRef ExifInformation::getGpsAltitudeRef() const +{ + LoggerD("Entered"); + return m_gps_altitude_ref; +} + +void ExifInformation::setGpsAltitudeRef(const GpsAltitudeRef ref) +{ + LoggerD("Entered"); + m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF] = true; + m_gps_altitude_ref = ref; +} + +void ExifInformation::setGpsAltitudeWithRef(double gps_altitude) +{ + LoggerD("Entered"); + setGpsAltitude(Rational::createFromDouble(fabs(gps_altitude))); + + if(gps_altitude >= 0.0) { + setGpsAltitudeRef(GPS_ALTITUDE_REF_ABOVE_SEA); + } else { + setGpsAltitudeRef(GPS_ALTITUDE_REF_BELOW_SEA); + } + +} + +double ExifInformation::getGpsAltitudeWithRef() const +{ + LoggerD("Entered"); + + if (!m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF] || + GPS_ALTITUDE_REF_ABOVE_SEA == m_gps_altitude_ref) { + return m_gps_altitude.toDouble(); + } else { + return -1.0 * m_gps_altitude.toDouble(); + } +} + +const std::string& ExifInformation::getGpsProcessingMethod() const +{ + LoggerD("Entered"); + return m_gps_processing_method; +} + +const std::string& ExifInformation::getGpsProcessingMethodType() const +{ + LoggerD("Entered"); + return m_gps_processing_method_type; +} + +void ExifInformation::setGpsProcessingMethod(const std::string& type, + const std::string& processing_method) +{ + LoggerD("Entered"); + if (type != EXIF_UNDEFINED_TYPE_ASCII && + type != EXIF_UNDEFINED_TYPE_JIS && + type != EXIF_UNDEFINED_TYPE_UNICODE && + type != EXIF_UNDEFINED_TYPE_UNDEFINED) { + LoggerW("Trying to set invalid GPSProcessingMethod type: [%s] len:%d", + type.c_str(), type.length()); + return; + } + + m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD] = true; + m_gps_processing_method = processing_method; + m_gps_processing_method_type = type; +} +/* +ExifGPSTime& ExifInformation::getExifGpsTime() +{ + return m_exif_gps_time; +}*/ +/* +const ExifGPSTime& ExifInformation::getExifGpsTime() const +{ + return m_exif_gps_time; +}*/ + +/* +Time::TZDatePtr ExifInformation::getGpsTime() +{ + if(m_gps_time) { + return m_gps_time; + } + + if(!m_exif_gps_time.isValid()) { + return Time::TZDatePtr(); + } + + + m_gps_time = m_exif_gps_time.getTZDate(); + return m_gps_time; +}*/ +/* +void ExifInformation::setGpsTime(Time::TZDatePtr new_time) +{ + if(!new_time) { + LoggerW("Trying to set null new_time!"); + return; + } + + m_gps_time = new_time; +}*/ + +void ExifInformation::unsetGPStime() +{ + //m_exif_gps_time.unsetAll(); + //m_gps_time = NULL; +} + + +const std::string& ExifInformation::getUserComment() +{ + LoggerD("Entered"); + return m_user_comment; +} + +const std::string& ExifInformation::getUserCommentType() +{ + LoggerD("Entered"); + return m_user_comment_type; +} + +void ExifInformation::setUserComment(const std::string& type, + const std::string& user_comment) +{ + LoggerD("Entered"); + if (type != EXIF_UNDEFINED_TYPE_ASCII && + type != EXIF_UNDEFINED_TYPE_JIS && + type != EXIF_UNDEFINED_TYPE_UNICODE && + type != EXIF_UNDEFINED_TYPE_UNDEFINED) { + LoggerW("Trying to set invalid user comment type: [%s] len:%d", + type.c_str(), type.length()); + return; + } + + m_is_set[EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT] = true; + m_user_comment_type = type; + m_user_comment = user_comment; +} + +bool ExifInformation::isSet(ExifInformationAttribute attribute) const +{ + LoggerD("Entered"); + return m_is_set[attribute]; +} + +void ExifInformation::unset(ExifInformationAttribute attribute) +{ + LoggerD("Entered"); + if (attribute >= EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES) { + return; + } + + m_is_set[attribute] = false; + switch (attribute) { + case EXIF_INFORMATION_ATTRIBUTE_URI: + m_uri = std::string(); + break; + case EXIF_INFORMATION_ATTRIBUTE_WIDTH: + m_width = 0; + break; + case EXIF_INFORMATION_ATTRIBUTE_HEIGHT: + m_height = 0; + break; + case EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER: + m_device_maker = std::string(); + break; + case EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL: + m_device_model = std::string(); + break; + case EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME: + m_original_time = 0; + break; + case EXIF_INFORMATION_ATTRIBUTE_ORIENTATION: + m_orientation = EXIF_ORIENTATION_NOT_VALID; + break; + case EXIF_INFORMATION_ATTRIBUTE_FNUMBER: + m_f_number = Rational::createInvalid(); + break; + case EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS: + //m_iso_speed_ratings = std::vector(); + break; + case EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME: + m_exposure_time = Rational::createInvalid(); + break; + case EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM: + m_exposure_program = EXIF_EXPOSURE_PROGRAM_NOT_VALID; + break; + case EXIF_INFORMATION_ATTRIBUTE_FLASH: + m_flash = false; + break; + case EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH: + m_focal_length = Rational::createInvalid(); + break; + case EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE: + m_white_balance = EXIF_WHITE_BALANCE_MODE_NOT_VALID; + break; + case EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE: + m_gps_altitude = Rational::createInvalid(); + break; + case EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF: + m_gps_altitude_ref = GPS_ALTITUDE_REF_ABOVE_SEA; + break; + case EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD: + m_gps_processing_method = std::string(); + m_gps_processing_method_type = EXIF_UNDEFINED_TYPE_ASCII; + break; + case EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT: + m_user_comment = std::string(); + m_user_comment_type = EXIF_UNDEFINED_TYPE_ASCII; + break; + default: + break; + } +} + +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, + (int)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()) { + LOGD("Setting ExifInformation fnumber to: %f (%s)", fnumber.toDouble(), + fnumber.toString().c_str()); + setFNumber(fnumber); + } + else { + LOGW("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); + appendIsoSpeedRatings(iso_rating); + + 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!"); + } + 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!"); + } + 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_exif_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_exif_gps_location.setLongitudeRef(GPS_LOCATION_EAST); + LoggerD("Setting ExifInformation gps longitude REF to: EAST"); + } + else if ('W' == ref || 'w' == ref) { //West + m_exif_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_exif_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_exif_gps_location.setLatitudeRef(GPS_LOCATION_NORTH); + LoggerD("Setting ExifInformation gps latitude REF to: NORTH"); + } + else if ('S' == ref || 's' == ref) { //South + m_exif_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()); + 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) +{ + LOGD("Entered"); + if(!exif_data) { + LoggerE("exif_data is NULL"); + throw common::UnknownException("Invalid Exif provided"); + } + + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) { + LoggerD("Removing width"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_IMAGE_WIDTH, exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_HEIGHT)) { + LoggerD("Removing height"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_IMAGE_LENGTH, exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER)) { + LoggerD("Removing device maker"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_MAKE, exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ORIENTATION)) { + LoggerD("Removing orientation"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_ORIENTATION, exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) { + LoggerD("Removing exposure program"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_EXPOSURE_PROGRAM, exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) { + LoggerD("Removing iso speed ratings"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_ISO_SPEED_RATINGS, exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE)) { + LoggerD("Removing white balance"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_WHITE_BALANCE, exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL)) { + LoggerD("Removing device model"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_MODEL, exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME)) { + LoggerD("Removing original time"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_DATE_TIME_ORIGINAL, exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME)) { + LoggerD("Removing exposure time"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_EXPOSURE_TIME, exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FNUMBER)) { + LoggerD("Removing f-number"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FNUMBER, exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FLASH)) { + LoggerD("Removing flash"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FLASH, exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH)) { + LoggerD("Removing focal length"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FOCAL_LENGTH, exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE)) { + LoggerD("Removing gps altitude"); + ExifTagSaver::removeExifEntryWithTag( + static_cast(EXIF_TAG_GPS_ALTITUDE), exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) { + LoggerD("Removing gps altitude ref"); + ExifTagSaver::removeExifEntryWithTag( + static_cast(EXIF_TAG_GPS_ALTITUDE_REF), exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) { + LoggerD("Removing gps processing method"); + ExifTagSaver::removeExifEntryWithTag( + static_cast(EXIF_TAG_GPS_PROCESSING_METHOD), exif_data); + } + if (!isSet(EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT)) { + LoggerD("Removing user comment"); + ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_USER_COMMENT, exif_data); + } + + if (!m_exif_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE)) { + LoggerD("Removing latitude"); + ExifTagSaver::removeExifEntryWithTag( + static_cast(EXIF_TAG_GPS_LATITUDE), exif_data); + } + if (!m_exif_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF)) { + LoggerD("Removing latitude ref"); + ExifTagSaver::removeExifEntryWithTag( + static_cast(EXIF_TAG_GPS_LATITUDE_REF), exif_data); + } + if (!m_exif_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE)) { + LoggerD("Removing longitude"); + ExifTagSaver::removeExifEntryWithTag( + static_cast(EXIF_TAG_GPS_LONGITUDE), exif_data); + } + if (!m_exif_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF)) { + LoggerD("Removing longitude ref"); + ExifTagSaver::removeExifEntryWithTag( + static_cast(EXIF_TAG_GPS_LONGITUDE_REF), exif_data); + } +/* + if (!m_exif_gps_time.isTimeSet()) { + LoggerD("Removing gps time"); + ExifTagSaver::removeExifEntryWithTag( + static_cast(EXIF_TAG_GPS_TIME_STAMP), exif_data); + } + if (!m_exif_gps_time.isDateSet()) { + LoggerD("Removing gps date"); + ExifTagSaver::removeExifEntryWithTag( + static_cast(EXIF_TAG_GPS_DATE_STAMP), exif_data); + }*/ +} + +void ExifInformation::updateAttributesInExifData(ExifData* exif_data) +{ + LOGD("Entered"); + if(!exif_data) { + LoggerE("exif_data is NULL"); + throw common::UnknownException("Invalid Exif provided"); + } + + if (isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) { + LoggerD("Saving width: %d", getWidth()); + ExifTagSaver::saveToExif(getWidth(), + EXIF_TAG_IMAGE_WIDTH, exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_HEIGHT)) { + LoggerD("Saving height: %d", getHeight()); + ExifTagSaver::saveToExif(getHeight(), + EXIF_TAG_IMAGE_LENGTH, exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER)) { + LoggerD("Saving device maker: %s", getDeviceMaker().c_str()); + ExifTagSaver::saveToExif(getDeviceMaker(), + EXIF_TAG_MAKE, exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_ORIENTATION)) { + LoggerD("Saving orientation: %d", static_cast(getOrientation())); + ExifTagSaver::saveToExif(static_cast(getOrientation()), + EXIF_TAG_ORIENTATION, exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) { + LoggerD("Saving exposure program: %d", static_cast(getExposureProgram())); + ExifTagSaver::saveToExif(getExposureProgram(), + EXIF_TAG_EXPOSURE_PROGRAM, exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) { + //std::vector iso_ratings = getIsoSpeedRatings(); + //LoggerD("Saving iso speed ratings count:%d", iso_ratings.size()); + //ExifTagSaver::saveToExif(iso_ratings, EXIF_FORMAT_SHORT, + // EXIF_TAG_ISO_SPEED_RATINGS, exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE)) { + LoggerD("Saving white balance: %d", static_cast(getWhiteBalanceMode())); + ExifTagSaver::saveToExif(getWhiteBalanceMode(), + EXIF_TAG_WHITE_BALANCE, exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL)) { + LoggerD("Saving device model: %s", getDeviceModel().c_str()); + ExifTagSaver::saveToExif(getDeviceModel(), + EXIF_TAG_MODEL, exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME)) { + const time_t o_time = getOriginalTime(); + const std::string o_time_str = ExifUtil::timeTToExifDateTimeOriginal(o_time); + LoggerD("Saving original time time_t:%d, format:%s", static_cast(o_time), + o_time_str.c_str()); + + ExifTagSaver::saveToExif(o_time_str, + EXIF_TAG_DATE_TIME_ORIGINAL, exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME)) { + Rational exposure_time = getExposureTime(); + if (exposure_time.isValid()) { + LoggerD("Saving exposure time: %s (%s)", + exposure_time.toString().c_str(), + exposure_time.toExposureTimeString().c_str()); + + ExifTagSaver::saveToExif(exposure_time, + EXIF_TAG_EXPOSURE_TIME, exif_data); + } + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_FNUMBER)) { + auto f_number = getFNumber(); + LoggerD("Saving f-number: %f (%s)", f_number.toDouble(), + f_number.toString().c_str()); + ExifTagSaver::saveToExif(f_number, + EXIF_TAG_FNUMBER, exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_FLASH)) { + LoggerD("Saving flash: %s", getFlash() ? "ON" : "OFF"); + ExifTagSaver::saveToExif(getFlash(), + EXIF_TAG_FLASH, exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH)) { + auto f_length = getFocalLength(); + LoggerD("Saving focal length:%f (%s)", f_length.toDouble(), + f_length.toString().c_str()); + ExifTagSaver::saveToExif(f_length, + EXIF_TAG_FOCAL_LENGTH, exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE)) { + LoggerD("Saving gps altitude:%f (%s)", m_gps_altitude.toDouble(), + m_gps_altitude.toString().c_str()); + ExifTagSaver::saveToExif(m_gps_altitude, + static_cast(EXIF_TAG_GPS_ALTITUDE), exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) { + //Exif spec: + //0 = Sea level + //1 = Sea level reference (negative value) + LoggerD("Saving gps altitude ref:%d (%s)", static_cast(m_gps_altitude_ref), + (m_gps_altitude_ref > 0) ? "below sea" : "above sea"); + ExifTagSaver::saveToExif(static_cast(m_gps_altitude_ref), + static_cast(EXIF_TAG_GPS_ALTITUDE_REF), exif_data); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) { + LoggerD("Saving gps processing method: [%s] type:%s", + getGpsProcessingMethod().c_str(), getGpsProcessingMethodType().c_str()); + + const std::string joined = getGpsProcessingMethodType() + getGpsProcessingMethod(); + LoggerD("joined: [%s]", joined.c_str()); + + ExifTagSaver::saveToExif(joined, + static_cast(EXIF_TAG_GPS_PROCESSING_METHOD), exif_data, false); + } + if (isSet(EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT)) { + LoggerD("Saving user comment: %s (type:%s)", getUserComment().c_str(), + getUserCommentType().c_str()); + + const std::string joined = getUserCommentType() + getUserComment(); + LoggerD("joined: [%s]", joined.c_str()); + + ExifTagSaver::saveToExif(joined, + EXIF_TAG_USER_COMMENT, exif_data, false); + } + + //if(m_gps_location) { + // m_exif_gps_location.set(m_gps_location); + // } + //ExifTagSaver::saveGpsLocationToExif(m_exif_gps_location, exif_data); + +/* if(m_gps_time) { + m_exif_gps_time.setDateAndTime(m_gps_time); + } + ExifTagSaver::saveGpsTimeToExif(m_exif_gps_time, exif_data);*/ +} + +void ExifInformation::saveToFile(const std::string& file_path) +{ + LoggerD("Entered"); + LoggerD("Using JpegFile to read: [%s] and Exif if present", file_path.c_str()); + + bool exif_data_is_new = false; + JpegFilePtr jpg_file = JpegFile::loadFile(file_path); + ExifData* exif_data = jpg_file->getExifData(); + + //Exif is not present in file - create new ExifData + if (!exif_data) { + LoggerD("Exif is not present in file: [%s] creating new", file_path.c_str()); + + exif_data = exif_data_new(); + exif_data_set_option(exif_data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); + exif_data_set_data_type(exif_data, EXIF_DATA_TYPE_COMPRESSED); + exif_data_set_byte_order(exif_data, EXIF_BYTE_ORDER_MOTOROLA); + exif_data_is_new = true; + } + + if (!exif_data) { + LoggerE("Couldn't allocate new ExifData"); + throw common::UnknownException("Memory allocation failed"); + } + + LoggerD("Exif data type: %d", exif_data_get_data_type(exif_data) ); + LoggerD("Exif byte order: %d", exif_data_get_byte_order(exif_data) ); + exif_data_set_option(exif_data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); + + try { + //If we have created new ExifData there is nothing to remove + if(!exif_data_is_new) { + //Remove attributes that have been nulled + removeNulledAttributesFromExifData(exif_data); + } + + updateAttributesInExifData(exif_data); + + LOGD("Using JpegFile to save new Exif in: [%s]", file_path.c_str()); + if(exif_data_is_new) { + jpg_file->setNewExifData(exif_data); + } + + jpg_file->saveToFile(file_path); + } + catch (...) { + exif_data_unref(exif_data); + exif_data = NULL; + throw; + } + + exif_data_unref(exif_data); + exif_data = NULL; +} + +} // exif +} // extension diff --git a/src/exif/ExifInformation.h b/src/exif/ExifInformation.h new file mode 100644 index 00000000..a1fa343e --- /dev/null +++ b/src/exif/ExifInformation.h @@ -0,0 +1,210 @@ +// +// Tizen Web Device API +// Copyright (c) 2014 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 __TIZEN_EXIF_EXIFINFORMATION_H_ +#define __TIZEN_EXIF_EXIFINFORMATION_H_ + +#include +#include + +//#include +//#include + +#include "ExifGPSLocation.h" +//#include "ExifGPSTime.h" + +namespace extension { +namespace exif { + +class ExifInformation; +typedef std::shared_ptr ExifInformationPtr; + +extern const size_t EXIF_UNDEFINED_TYPE_LENGTH; +extern const std::string EXIF_UNDEFINED_TYPE_ASCII; +extern const std::string EXIF_UNDEFINED_TYPE_JIS; +extern const std::string EXIF_UNDEFINED_TYPE_UNICODE; +extern const std::string EXIF_UNDEFINED_TYPE_UNDEFINED; + +enum ExifInformationAttribute{ + EXIF_INFORMATION_ATTRIBUTE_URI, + EXIF_INFORMATION_ATTRIBUTE_WIDTH, + EXIF_INFORMATION_ATTRIBUTE_HEIGHT, + EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER, + EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL, + EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME, + EXIF_INFORMATION_ATTRIBUTE_ORIENTATION, + EXIF_INFORMATION_ATTRIBUTE_FNUMBER, + EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS, + EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME, + EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM, + EXIF_INFORMATION_ATTRIBUTE_FLASH, + EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH, + EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE, + EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE, + EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF, + EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD, + EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT, + EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES +}; + +enum GpsAltitudeRef { + GPS_ALTITUDE_REF_ABOVE_SEA = 0, + GPS_ALTITUDE_REF_BELOW_SEA = 1 +}; + +class ExifInformation +{ +public: + ExifInformation(); + ~ExifInformation(); + + static ExifInformationPtr loadFromURI(const std::string& uri); + void saveToFile(const std::string& file_path); + + const std::string& getUri(); + void setUri(const std::string& uri); + + unsigned long getWidth() const; + void setWidth(unsigned long width); + + unsigned long getHeight() const; + void setHeight(unsigned long height); + + const std::string& getDeviceMaker(); + void setDeviceMaker(const std::string& device_maker); + + const std::string& getDeviceModel(); + void setDeviceModel(const std::string& device_model); + + time_t getOriginalTime() const; + void setOriginalTime(time_t original_time); + + ImageOrientation getOrientation() const; + void setOrientation(ImageOrientation orientation); + + const Rational& getFNumber() const; + void setFNumber(Rational f_number); + + //Common::JSLongLongVector getIsoSpeedRatings(); + //void setIsoSpeedRatings(const std::vector& iso_speed_ratings); + void appendIsoSpeedRatings(long long int iso_speed_rating); + + const Rational& getExposureTime(); + void setExposureTime(const Rational& exposure_time); + + ExposureProgram getExposureProgram(); + void setExposureProgram(ExposureProgram exposure_program ); + + bool getFlash() const; + void setFlash(bool flash); + + const Rational& getFocalLength() const; + void setFocalLength(Rational focal_length); + + WhiteBalanceMode getWhiteBalanceMode() const; + void setWhiteBalanceMode(WhiteBalanceMode white_balance); + + ExifGPSLocation& getGPSExifLocation(); + //Tizen::SimpleCoordinatesPtr getGPSLocation(); + //void setGPSLocation(Tizen::SimpleCoordinatesPtr gps_location); + void unsetGPSLocation(); + + const Rational& getGpsAltitude() const; + void setGpsAltitude(Rational gps_altitude); + + GpsAltitudeRef getGpsAltitudeRef() const; + void setGpsAltitudeRef(const GpsAltitudeRef ref); + + /** + * gps_altitude can be negative and positive: + * if gps_altitude < 0.0 GPS_ALTITUDE_REF_BELOW_SEA is set + * if gps_altitude >= 0.0 GPS_ALTITUDE_REF_ABOVE_SEA is set + */ + void setGpsAltitudeWithRef(double gps_altitude); + + /** + * Return gps altitude which can be negative (below sea level) and positive (above sea + * level) + */ + double getGpsAltitudeWithRef() const; + + const std::string& getGpsProcessingMethod() const; + const std::string& getGpsProcessingMethodType() const; + void setGpsProcessingMethod(const std::string& type, + const std::string& processing_method); + + //ExifGPSTime& getExifGpsTime(); + //const ExifGPSTime& getExifGpsTime() const; + //Time::TZDatePtr getGpsTime(); + //void setGpsTime(Time::TZDatePtr new_time); + void unsetGPStime(); + + const std::string& getUserComment(); + const std::string& getUserCommentType(); + void setUserComment(const std::string& type, + const std::string& user_comment); + + bool isSet(ExifInformationAttribute attribute) const; + void unset(ExifInformationAttribute attribute); + +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); + + std::string m_uri; + unsigned long m_width; + unsigned long m_height; + std::string m_device_maker; + std::string m_device_model; + + time_t m_original_time; + + ImageOrientation m_orientation; + Rational m_f_number; + //Common::JSLongLongVector m_iso_speed_ratings; + Rational m_exposure_time; + ExposureProgram m_exposure_program; + bool m_flash; + Rational m_focal_length; + WhiteBalanceMode m_white_balance; + + ExifGPSLocation m_exif_gps_location; + //Tizen::SimpleCoordinatesPtr m_gps_location; + + Rational m_gps_altitude; + GpsAltitudeRef m_gps_altitude_ref; + + std::string m_gps_processing_method; + std::string m_gps_processing_method_type; + + //ExifGPSTime m_exif_gps_time; + //Time::TZDatePtr m_gps_time; + + std::string m_user_comment; + std::string m_user_comment_type; + + bool m_is_set[EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES]; +}; + +} // exif +} // extension + +#endif // __TIZEN_EXIF_EXIFINFORMATION_H_ diff --git a/src/exif/ExifTagSaver.cpp b/src/exif/ExifTagSaver.cpp new file mode 100644 index 00000000..ae1baaa7 --- /dev/null +++ b/src/exif/ExifTagSaver.cpp @@ -0,0 +1,412 @@ +// +// Tizen Web Device API +// Copyright (c) 2014 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 "ExifTagSaver.h" + +#include +#include +#include + +#include "common/platform_exception.h" +#include "common/logger.h" + +#include "ExifUtil.h" + +namespace extension { +namespace exif { + +void ExifTagSaver::removeExifEntryWithTag(const ExifTag tag, ExifData* exif_data) +{ + LoggerD("Entered tag:%d (0x%x)", tag, tag); + ExifEntry* exif_entry = exif_data_get_entry(exif_data, tag); + if (!exif_entry) { + LoggerE("Exif entry with tag:%d (0x%x) is not present", tag, tag); + return; + } + + exif_content_remove_entry(exif_entry->parent, exif_entry); +} + +void ExifTagSaver::saveToExif(long int value, ExifTag tag, ExifData* exif_data) +{ + ExifEntry* entry = prepareEntry(exif_data, tag); + ExifByteOrder order = exif_data_get_byte_order(exif_data); + + switch (entry->format) { + case EXIF_FORMAT_BYTE: + entry->data[0] = static_cast(value); + break; + case EXIF_FORMAT_SHORT: + exif_set_short (entry->data, order, value); + break; + case EXIF_FORMAT_LONG: + exif_set_long (entry->data, order, value); + break; + case EXIF_FORMAT_SLONG: + exif_set_slong (entry->data, order, value); + break; + default: + LoggerE("Error: wrong format: %d \n", entry->format ); + } +} + +void ExifTagSaver::saveToExif(const std::string& value, ExifTag tag, ExifData* exif_data, + bool add_zero_character) +{ + ExifEntry* entry = prepareEntry(exif_data, tag); + if (!value.empty()) { + + if (entry->data) { + free(entry->data); + entry->data = NULL; + } + + size_t new_len = value.length(); + if (add_zero_character) { + ++new_len; + } + + entry->size = new_len; + entry->components = new_len; + + entry->data = static_cast(malloc(entry->size)); + memcpy(entry->data, value.c_str(), value.length()); + if (add_zero_character) { + entry->data[value.length()] = '\0'; + } + } +} + +void ExifTagSaver::saveToExif(const Rational& value, ExifTag tag, ExifData* exif_data) +{ + ExifEntry* entry = prepareEntry(exif_data, tag); + entry->format = EXIF_FORMAT_RATIONAL; + + if (ExifTypeInfo::RationalSize != entry->size) { + if (entry->data) { + free(entry->data); + entry->data = NULL; + } + + entry->size = ExifTypeInfo::RationalSize; + entry->data = static_cast(malloc(entry->size)); + memset(entry->data, 0, entry->size); + } + + entry->components = 1; + + ExifByteOrder order = exif_data_get_byte_order(exif_data); + ExifRational r; + r.numerator = value.nominator; + r.denominator = value.denominator; + exif_set_rational(entry->data, order, r); +} + +void ExifTagSaver::saveToExif(const Rationals& value, ExifTag tag, ExifData* exif_data) +{ + ExifEntry* entry = prepareEntry(exif_data, tag); + ExifByteOrder order = exif_data_get_byte_order(exif_data); + entry->format = EXIF_FORMAT_RATIONAL; + + const unsigned int required_size = ExifTypeInfo::RationalSize * value.size(); + if (required_size != entry->size) { + if (entry->data) { + free(entry->data); + entry->data = NULL; + } + + entry->size = required_size; + entry->data = static_cast(malloc(entry->size)); + memset(entry->data, 0, entry->size); + } + + entry->components = value.size(); + for (size_t i = 0; i < value.size(); ++i) + { + ExifRational r; + r.numerator = value[i].nominator; + r.denominator = value[i].denominator; + exif_set_rational(entry->data + i * ExifTypeInfo::RationalSize, order, r); + } +} + +void ExifTagSaver::saveToExif(std::vector& value, ExifFormat store_as, + ExifTag tag, ExifData* exif_data) +{ + ExifEntry* entry = prepareEntry(exif_data, tag); + const ExifByteOrder order = exif_data_get_byte_order(exif_data); + + const size_t size_per_member = ExifUtil::getSizeOfExifFormatType(store_as); + switch (store_as) { + case EXIF_FORMAT_BYTE: + case EXIF_FORMAT_SHORT: + case EXIF_FORMAT_SSHORT: + case EXIF_FORMAT_LONG: + case EXIF_FORMAT_SLONG: + break; + default: + LoggerE("output ExifFormat: %d is not supported!"); + return; + } + entry->format = store_as; + + const size_t num_elements = value.size(); + const unsigned int required_size = size_per_member * num_elements; + if (required_size != entry->size) { + if (entry->data) { + free(entry->data); + entry->data = NULL; + } + + entry->size = required_size; + entry->data = static_cast(malloc(entry->size)); + memset(entry->data, 0, entry->size); + } + entry->components = num_elements; + + + switch (store_as) { + case EXIF_FORMAT_BYTE: { + for(size_t i = 0; i < num_elements; ++i) { + entry->data[i] = static_cast(value[i]); + } + break; + } + + case EXIF_FORMAT_SHORT: { + for (size_t i = 0; i < num_elements; ++i) { + exif_set_short(entry->data + i * size_per_member, order, + static_cast(value[i])); + } + break; + } + + case EXIF_FORMAT_SSHORT: { + for (size_t i = 0; i < num_elements; ++i) { + exif_set_sshort(entry->data + i * size_per_member, order, + static_cast(value[i])); + } + break; + } + + case EXIF_FORMAT_LONG: { + for (size_t i = 0; i < num_elements; ++i) { + exif_set_long(entry->data + i * size_per_member, order, + static_cast(value[i])); + } + break; + } + + case EXIF_FORMAT_SLONG: { + for(size_t i = 0; i < num_elements; ++i) { + exif_set_slong(entry->data + i * size_per_member, order, + static_cast(value[i])); + } + break; + } + + default: + break; + } + + + LoggerD("entry after save:"); + ExifUtil::printExifEntryInfo(entry, exif_data); +} + +void ExifTagSaver::saveGpsLocationToExif(const ExifGPSLocation& gps_info, + ExifData* exif_data) +{ + if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE)) { + auto latitude = gps_info.getLatitude(); + LoggerD("Saving latitude: %s", latitude.toDebugString().c_str()); + saveToExif(latitude.toRationalsVector(), + static_cast(EXIF_TAG_GPS_LATITUDE), exif_data); + } + + if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF)) { + std::string lat_ref = + (gps_info.getLatitudeRef() == GPS_LOCATION_NORTH) ? "N" : "S"; + LoggerD("Saving latitude ref: %s", lat_ref.c_str()); + saveToExif(lat_ref, static_cast(EXIF_TAG_GPS_LATITUDE_REF), exif_data); + } + + if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE)) { + + auto longitude = gps_info.getLongitude(); + LoggerD("Saving longitude: %s", longitude.toDebugString().c_str()); + saveToExif(longitude.toRationalsVector(), + static_cast(EXIF_TAG_GPS_LONGITUDE), exif_data); + } + + if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF)) { + std::string long_ref = + (gps_info.getLongitudeRef() == GPS_LOCATION_WEST) ? "W" : "E"; + LoggerD("Saving longitude ref: %s", long_ref.c_str()); + saveToExif(long_ref, static_cast(EXIF_TAG_GPS_LONGITUDE_REF), exif_data); + } +} +/* +void ExifTagSaver::saveGpsTimeToExif(const ExifGPSTime& gps_time, + ExifData* exif_data) +{ + if (gps_time.isTimeSet()) { + const Rationals& time = gps_time.getTime(); + LoggerD("Saving gps time: [%s]h [%s]m [%s]d", + time[0].toString().c_str(), + time[1].toString().c_str(), + time[2].toString().c_str()); + + saveToExif(time, static_cast(EXIF_TAG_GPS_TIME_STAMP), exif_data); + } + + if (gps_time.isDateSet()) { + std::string date = gps_time.getDate(); + LoggerD("Saving gps date: [%s]", date.c_str()); + + saveToExif(date, static_cast(EXIF_TAG_GPS_DATE_STAMP), exif_data); + } +} +*/ +ExifEntry* ExifTagSaver::prepareEntry(ExifData* exif_data, ExifTag tag) +{ + LoggerD("Entered m_tag:%d", tag); + + ExifEntry* exif_entry = exif_data_get_entry(exif_data, tag); + if (!exif_entry) { + exif_entry = createNewTag(exif_data, deduceIfdSection(tag), + deduceDataFormat(tag), tag ); + } + + if (!exif_entry) { + LoggerE("Couldn't create new Exif tag"); + //throw UnknownException("Could not save Exif to file"); + } + + exif_entry_initialize(exif_entry, tag); + + return exif_entry; +} + +ExifEntry* ExifTagSaver::createNewTag(ExifData* exif_data, ExifIfd ifd, + ExifFormat format, ExifTag tag) +{ + LoggerD("Creating new tag: %d", tag); + + ExifEntry* new_entry = exif_entry_new(); + new_entry->tag = tag; + new_entry->format = format; + exif_content_add_entry(exif_data->ifd[ifd], new_entry); + exif_entry_initialize(new_entry, tag); + return new_entry; +} + +ExifIfd ExifTagSaver::deduceIfdSection(ExifTag tag) +{ + switch (static_cast(tag)) { + //Tags in IFD_0 Section + case EXIF_TAG_MAKE: + case EXIF_TAG_MODEL: + case EXIF_TAG_IMAGE_WIDTH: + case EXIF_TAG_IMAGE_LENGTH: + case EXIF_TAG_ORIENTATION: + return EXIF_IFD_0; + + //Tags in IFD_EXIF Section + case EXIF_TAG_USER_COMMENT: + case EXIF_TAG_DATE_TIME_ORIGINAL: + case EXIF_TAG_EXPOSURE_TIME: + case EXIF_TAG_FNUMBER: + case EXIF_TAG_EXPOSURE_PROGRAM: + case EXIF_TAG_ISO_SPEED_RATINGS: + case EXIF_TAG_WHITE_BALANCE: + case EXIF_TAG_FLASH: + case EXIF_TAG_FOCAL_LENGTH: + return EXIF_IFD_EXIF; + + //Tags in IFD_GPS Section + case EXIF_TAG_GPS_LATITUDE_REF: + case EXIF_TAG_GPS_LONGITUDE_REF: + case EXIF_TAG_GPS_LATITUDE: + case EXIF_TAG_GPS_LONGITUDE: + case EXIF_TAG_GPS_ALTITUDE: + case EXIF_TAG_GPS_ALTITUDE_REF: + case EXIF_TAG_GPS_TIME_STAMP: + case EXIF_TAG_GPS_PROCESSING_METHOD: + case EXIF_TAG_GPS_DATE_STAMP: + return EXIF_IFD_GPS; + + //Tags in other sections + default: + LoggerE("Unsupported tag: %d", tag); + //throw UnknownException("Unsupported tag"); + } +} + +ExifFormat ExifTagSaver::deduceDataFormat(ExifTag tag) +{ + switch (static_cast(tag)) { + //Tags with byte type: + case EXIF_TAG_GPS_ALTITUDE_REF: + return EXIF_FORMAT_BYTE; + + //Tags with long type: + case EXIF_TAG_IMAGE_WIDTH: + case EXIF_TAG_IMAGE_LENGTH: + return EXIF_FORMAT_LONG; + + //Tags with short type: + case EXIF_TAG_ORIENTATION: + case EXIF_TAG_EXPOSURE_PROGRAM: + case EXIF_TAG_WHITE_BALANCE: + case EXIF_TAG_FLASH: + return EXIF_FORMAT_SHORT; + + //Tags with ASCII type: + case EXIF_TAG_MAKE: + case EXIF_TAG_MODEL: + case EXIF_TAG_DATE_TIME_ORIGINAL: + case EXIF_TAG_GPS_LATITUDE_REF: + case EXIF_TAG_GPS_LONGITUDE_REF: + case EXIF_TAG_GPS_DATE_STAMP: + return EXIF_FORMAT_ASCII; + + //Tags with rational type: + case EXIF_TAG_EXPOSURE_TIME: + case EXIF_TAG_FNUMBER: + case EXIF_TAG_FOCAL_LENGTH: + case EXIF_TAG_GPS_LATITUDE: + case EXIF_TAG_GPS_LONGITUDE: + case EXIF_TAG_GPS_ALTITUDE: + case EXIF_TAG_GPS_TIME_STAMP: + case EXIF_TAG_ISO_SPEED_RATINGS: + return EXIF_FORMAT_RATIONAL; + + //Tags with undefined type: + case EXIF_TAG_USER_COMMENT: + case EXIF_TAG_GPS_PROCESSING_METHOD: + return EXIF_FORMAT_UNDEFINED; + + //Unsupported tags: + default: + LoggerE("Unsupported tag: %d", tag); + //throw UnknownException("Unsupported tag"); + } +} + +} // exif +} // extension diff --git a/src/exif/ExifTagSaver.h b/src/exif/ExifTagSaver.h new file mode 100644 index 00000000..fc07eafc --- /dev/null +++ b/src/exif/ExifTagSaver.h @@ -0,0 +1,62 @@ +// +// Tizen Web Device API +// Copyright (c) 2014 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. +// + +/** + * @file ExifTagSaver.h + */ + +#ifndef __TIZEN_EXIF_EXIF_TAG_SAVER_H__ +#define __TIZEN_EXIF_EXIF_TAG_SAVER_H__ + +#include +#include + +#include "ExifGPSLocation.h" +//#include "ExifGPSTime.h" + +namespace extension { +namespace exif { + +class ExifTagSaver +{ +public: + static void removeExifEntryWithTag(const ExifTag tag, ExifData* exif_data); + + static void saveToExif(long int value, ExifTag tag, ExifData* exif_data); + static void saveToExif(const std::string& value, ExifTag tag, ExifData* exif_data, + bool add_zero_character = true); + static void saveToExif(const Rational& value, ExifTag tag, ExifData* exif_data); + static void saveToExif(const Rationals& value, ExifTag tag, ExifData* exif_data); + static void saveToExif(std::vector& value, ExifFormat store_as, + ExifTag tag, ExifData* exif_data); + static void saveGpsLocationToExif(const ExifGPSLocation& gps_info, + ExifData* exif_data); + //static void saveGpsTimeToExif(const ExifGPSTime& gps_time, + //ExifData* exif_data); + +private: + static ExifEntry* prepareEntry(ExifData* exif_data, ExifTag tag); + static ExifIfd deduceIfdSection(ExifTag tag); + static ExifFormat deduceDataFormat(ExifTag tag); + static ExifEntry* createNewTag(ExifData* exif_data, ExifIfd ifd, + ExifFormat format, ExifTag tag); +}; + +} // exif +} // extension + +#endif // __TIZEN_EXIF_EXIF_TAG_SAVER_H__ diff --git a/src/exif/ExifUtil.cpp b/src/exif/ExifUtil.cpp new file mode 100644 index 00000000..7f86335b --- /dev/null +++ b/src/exif/ExifUtil.cpp @@ -0,0 +1,431 @@ +// +// Tizen Web Device API +// Copyright (c) 2014 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 "ExifUtil.h" + +#include +#include + +#include "common/platform_exception.h" +#include "common/logger.h" + +namespace extension { +namespace exif { + +namespace { +const std::string ORIENTATION_NORMAL = "NORMAL"; +const std::string ORIENTATION_FLIP_HORIZONTAL = "FLIP_HORIZONTAL"; +const std::string ORIENTATION_ROTATE_180 = "ROTATE_180"; +const std::string ORIENTATION_FLIP_VERTICAL = "FLIP_VERTICAL"; +const std::string ORIENTATION_TRANSPOSE = "TRANSPOSE"; +const std::string ORIENTATION_ROTATE_90 = "ROTATE_90"; +const std::string ORIENTATION_TRANSVERSE = "TRANSVERSE"; +const std::string ORIENTATION_ROTATE_270 = "ROTATE_270"; + +const std::string WHITE_BALANCE_MODE_AUTO = "AUTO"; +const std::string WHITE_BALANCE_MODE_MANUAL = "MANUAL"; + +const std::string EXPOSURE_PROGRAM_NOT_DEFINED = "NOT_DEFINED"; +const std::string EXPOSURE_PROGRAM_MANUAL = "MANUAL"; +const std::string EXPOSURE_PROGRAM_NORMAL = "NORMAL"; +const std::string EXPOSURE_PROGRAM_APERTURE_PRIORITY = "APERTURE_PRIORITY"; +const std::string EXPOSURE_PROGRAM_SHUTTER_PRIORITY = "SHUTTER_PRIORITY"; +const std::string EXPOSURE_PROGRAM_CREATIVE_PROGRAM = "CREATIVE_PROGRAM"; +const std::string EXPOSURE_PROGRAM_ACTION_PROGRAM = "ACTION_PROGRAM"; +const std::string EXPOSURE_PROGRAM_PORTRAIT_MODE = "PORTRAIT_MODE"; +const std::string EXPOSURE_PROGRAM_LANDSCAPE_MODE = "LANDSCAPE_MODE"; + +const std::string DUMMY = ""; // For unexpected input handling + +const std::string URI_PREFIX = "file://"; +const std::string URI_ABSOLUTE_PREFIX = "file:///"; +} + +const size_t ExifTypeInfo::ByteSize = 1; +const size_t ExifTypeInfo::ASCIISize = 1; +const size_t ExifTypeInfo::ShortSize = 2; +const size_t ExifTypeInfo::LongSize = 4; +const size_t ExifTypeInfo::RationalSize = 8; +const size_t ExifTypeInfo::UndefinedSize = 1; +const size_t ExifTypeInfo::SLongSize = 4; +const size_t ExifTypeInfo::SRationalSize = 8; + +const ExifByte ExifTypeInfo::ByteId = 1; +const ExifByte ExifTypeInfo::ASCIIId = 2; +const ExifByte ExifTypeInfo::ShortId = 3; +const ExifByte ExifTypeInfo::LongId = 4; +const ExifByte ExifTypeInfo::RationalId = 5; +const ExifByte ExifTypeInfo::UndefinedId = 7; +const ExifByte ExifTypeInfo::SLongId = 9; +const ExifByte ExifTypeInfo::SRationalId = 10; + +ExifUtil::ExifUtil() +{ +} + +ExifUtil::~ExifUtil() +{ +} + +ImageOrientation ExifUtil::stringToOrientation(const std::string& orientation) +{ + LoggerD("Entered"); + if (ORIENTATION_NORMAL == orientation) { + return ImageOrientation::EXIF_ORIENTATION_NORMAL; + } + if (ORIENTATION_FLIP_HORIZONTAL == orientation) { + return ImageOrientation::EXIF_ORIENTATION_FLIP_HORIZONTAL; + } + if (ORIENTATION_ROTATE_180 == orientation) { + return ImageOrientation::EXIF_ORIENTATION_ROTATE_180; + } + if (ORIENTATION_FLIP_VERTICAL == orientation) { + return ImageOrientation::EXIF_ORIENTATION_FLIP_VERTICAL; + } + if (ORIENTATION_TRANSPOSE == orientation) { + return ImageOrientation::EXIF_ORIENTATION_TRANSPOSE; + } + if (ORIENTATION_ROTATE_90 == orientation) { + return ImageOrientation::EXIF_ORIENTATION_ROTATE_90; + } + if (ORIENTATION_TRANSVERSE == orientation) { + return ImageOrientation::EXIF_ORIENTATION_TRANSVERSE; + } + if (ORIENTATION_ROTATE_270 == orientation) { + return ImageOrientation::EXIF_ORIENTATION_ROTATE_270; + } + return ImageOrientation::EXIF_ORIENTATION_NOT_VALID; +} + +const std::string& ExifUtil::orientationToString(ImageOrientation orientation) +{ + LoggerD("Entered"); + switch (orientation) { + case ImageOrientation::EXIF_ORIENTATION_NORMAL: + return ORIENTATION_NORMAL; + case ImageOrientation::EXIF_ORIENTATION_FLIP_HORIZONTAL: + return ORIENTATION_FLIP_HORIZONTAL; + case ImageOrientation::EXIF_ORIENTATION_ROTATE_180: + return ORIENTATION_ROTATE_180; + case ImageOrientation::EXIF_ORIENTATION_FLIP_VERTICAL: + return ORIENTATION_FLIP_VERTICAL; + case ImageOrientation::EXIF_ORIENTATION_TRANSPOSE: + return ORIENTATION_TRANSPOSE; + case ImageOrientation::EXIF_ORIENTATION_ROTATE_90: + return ORIENTATION_ROTATE_90; + case ImageOrientation::EXIF_ORIENTATION_TRANSVERSE: + return ORIENTATION_TRANSVERSE; + case ImageOrientation::EXIF_ORIENTATION_ROTATE_270: + return ORIENTATION_ROTATE_270; + default: + return DUMMY; + } +} + +WhiteBalanceMode ExifUtil::stringToWhiteBalance(const std::string& white_balance) +{ + LoggerD("Entered"); + if (WHITE_BALANCE_MODE_AUTO == white_balance) { + return WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_AUTO; + } + if (WHITE_BALANCE_MODE_MANUAL == white_balance) { + return WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_MANUAL; + } + return WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_NOT_VALID; +} + +const std::string& ExifUtil::whiteBalanceToString(WhiteBalanceMode value) +{ + LoggerD("Entered"); + switch (value) { + case WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_AUTO: + return WHITE_BALANCE_MODE_AUTO; + case WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_MANUAL: + return WHITE_BALANCE_MODE_MANUAL; + default: + return DUMMY; + } +} + +ExposureProgram ExifUtil::stringToExposureProgram( + const std::string& exposure_program) +{ + LoggerD("Entered"); + if (EXPOSURE_PROGRAM_NOT_DEFINED == exposure_program) { + return EXIF_EXPOSURE_PROGRAM_NOT_DEFINED; + } + if (EXPOSURE_PROGRAM_MANUAL == exposure_program) { + return EXIF_EXPOSURE_PROGRAM_MANUAL; + } + if (EXPOSURE_PROGRAM_NORMAL == exposure_program) { + return EXIF_EXPOSURE_PROGRAM_NORMAL; + } + if (EXPOSURE_PROGRAM_APERTURE_PRIORITY == exposure_program) { + return EXIF_EXPOSURE_PROGRAM_APERTURE_PRIORITY; + } + if (EXPOSURE_PROGRAM_SHUTTER_PRIORITY == exposure_program) { + return EXIF_EXPOSURE_PROGRAM_SHUTTER_PRIORITY; + } + if (EXPOSURE_PROGRAM_CREATIVE_PROGRAM == exposure_program) { + return EXIF_EXPOSURE_PROGRAM_CREATIVE_PROGRAM; + } + if (EXPOSURE_PROGRAM_ACTION_PROGRAM == exposure_program) { + return EXIF_EXPOSURE_PROGRAM_ACTION_PROGRAM; + } + if (EXPOSURE_PROGRAM_PORTRAIT_MODE == exposure_program) { + return EXIF_EXPOSURE_PROGRAM_PORTRAIT_MODE; + } + if (EXPOSURE_PROGRAM_LANDSCAPE_MODE == exposure_program) { + return EXIF_EXPOSURE_PROGRAM_LANDSCAPE_MODE; + } + return EXIF_EXPOSURE_PROGRAM_NOT_VALID; +} + +const std::string& ExifUtil::exposureProgramToString(ExposureProgram value) +{ + LoggerD("Entered"); + switch (value) { + case ExposureProgram::EXIF_EXPOSURE_PROGRAM_NOT_DEFINED: + return EXPOSURE_PROGRAM_NOT_DEFINED; + case ExposureProgram::EXIF_EXPOSURE_PROGRAM_MANUAL: + return EXPOSURE_PROGRAM_MANUAL; + case ExposureProgram::EXIF_EXPOSURE_PROGRAM_NORMAL: + return EXPOSURE_PROGRAM_NORMAL; + case ExposureProgram::EXIF_EXPOSURE_PROGRAM_APERTURE_PRIORITY: + return EXPOSURE_PROGRAM_APERTURE_PRIORITY; + case ExposureProgram::EXIF_EXPOSURE_PROGRAM_SHUTTER_PRIORITY: + return EXPOSURE_PROGRAM_SHUTTER_PRIORITY; + case ExposureProgram::EXIF_EXPOSURE_PROGRAM_CREATIVE_PROGRAM: + return EXPOSURE_PROGRAM_CREATIVE_PROGRAM; + case ExposureProgram::EXIF_EXPOSURE_PROGRAM_ACTION_PROGRAM: + return EXPOSURE_PROGRAM_ACTION_PROGRAM; + case ExposureProgram::EXIF_EXPOSURE_PROGRAM_PORTRAIT_MODE: + return EXPOSURE_PROGRAM_PORTRAIT_MODE; + case ExposureProgram::EXIF_EXPOSURE_PROGRAM_LANDSCAPE_MODE: + return EXPOSURE_PROGRAM_LANDSCAPE_MODE; + default: + return DUMMY; + } +} + +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 +std::string ExifUtil::convertUriToPath(const std::string& str) +{ + std::string path = ltrim(str); + std::string prefix = path.substr(0, URI_PREFIX.size()); + + if (prefix == URI_PREFIX) { + return path.substr(URI_PREFIX.size()); + } + else { + return path; + } +} + +std::string ExifUtil::ltrim(const std::string& s) +{ + std::string str = s; + std::string::iterator i; + for (i = str.begin(); i != str.end(); i++) { + if (!isspace(*i)) { + break; + } + } + if (i == str.end()) { + str.clear(); + } + else { + str.erase(str.begin(), i); + } + return str; +} + +time_t ExifUtil::exifDateTimeOriginalToTimeT(const char* string) +{ + int year, month, day, hour, min, sec; + if (sscanf(string, "%d:%d:%d %d:%d:%d", + &year, &month, &day, &hour, &min, &sec) >= 6) { + return convertToTimeT(year, month, day, hour, min, sec); + } + + return 0; +} + +std::string ExifUtil::timeTToExifDateTimeOriginal(time_t time) +{ + int year, month, day, hour, min, sec; + extractFromTimeT(time, year, month, day, hour, min, sec); + + std::ostringstream ss; + ss << std::setfill('0') << std::setw(4) << year << ':' ; + ss << std::setfill('0') << std::setw(2) << month << ':' ; + ss << std::setfill('0') << std::setw(2) << day << ' ' ; + + ss << std::setfill('0') << std::setw(2) << hour << ':' ; + ss << std::setfill('0') << std::setw(2) << min << ':' ; + ss << std::setfill('0') << std::setw(2) << sec; + return ss.str(); +} + +size_t ExifUtil::getSizeOfExifFormatType(ExifFormat format) +{ + size_t size_per_member = 0; + switch (format) { + case EXIF_FORMAT_BYTE: + size_per_member = 1; + break; + + case EXIF_FORMAT_SHORT: + case EXIF_FORMAT_SSHORT: + size_per_member = 2; + break; + + case EXIF_FORMAT_LONG: + case EXIF_FORMAT_SLONG: + size_per_member = 4; + break; + + case EXIF_FORMAT_RATIONAL: + case EXIF_FORMAT_SRATIONAL: + size_per_member = 8; + break; + + default: + LoggerE("output ExifFormat: %d is not supported!"); + return 0; + } + + return size_per_member; +} + +void ExifUtil::printExifEntryInfo(ExifEntry* entry, ExifData* exif_data) +{ + char buf[2000]; + std::stringstream ss; + + if (!entry) { + LoggerE("entry is null"); + return; + } + + if (!entry->data) { + LoggerE("entry data is null"); + return; + } + + unsigned char* read_buf_ptr = entry->data; + + size_t size_per_member = getSizeOfExifFormatType(entry->format); + if (0 == size_per_member) { + size_per_member = 1; //display as array of bytes + } + + for(unsigned long compi = 0; compi < entry->components; ++compi) { + + if (compi > 0) { + ss << " "; + } + + for(size_t i = 0; i < size_per_member; ++i) { + unsigned int value = read_buf_ptr[i]; + ss << std::hex << std::setw(2) << std::setfill('0') << value; + } + + read_buf_ptr += size_per_member; + } + + LoggerD("Entry{name:%s type:%s size:%d components:%d value:%s RAW DATA:[%s]}", + exif_tag_get_name(entry->tag), + exif_format_get_name(entry->format), + (int)entry->size, + (int)entry->components, + exif_entry_get_value(entry, buf, sizeof(buf)), + ss.str().c_str()); +} + +void ExifUtil::extractFromTimeT(const time_t time, + int& out_year, int& out_month, int& out_day, + int& out_hour, int& out_min, int& out_sec) +{ + struct tm* utc = gmtime(&time); + + out_year = utc->tm_year + 1900; + out_month = utc->tm_mon + 1; + out_day = utc->tm_mday; + out_hour = utc->tm_hour; + out_min = utc->tm_min; + out_sec = utc->tm_sec; +} + +time_t ExifUtil::convertToTimeT(int year, int month, int day, + int hour, int min, int sec) +{ + time_t tmp_time = 0; + struct tm* timeinfo = localtime(&tmp_time); + timeinfo->tm_year = year - 1900; + timeinfo->tm_mon = month - 1; + timeinfo->tm_mday = day; + + timeinfo->tm_hour = hour; + timeinfo->tm_min = min; + timeinfo->tm_sec = sec; + + //From mktime documentation: + //"The values of the members tm_wday and tm_yday of timeptr are ignored" + return timegm(timeinfo); +} + +} // exif +} // extension diff --git a/src/exif/ExifUtil.h b/src/exif/ExifUtil.h new file mode 100644 index 00000000..dfa01902 --- /dev/null +++ b/src/exif/ExifUtil.h @@ -0,0 +1,153 @@ +// +// Tizen Web Device API +// Copyright (c) 2014 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 __TIZEN_EXIF_EXIFUTIL_H_ +#define __TIZEN_EXIF_EXIFUTIL_H_ + +#include +#include +#include +#include +#include + +//#include +//#include +//#include + +//#include "Rational.h" + +namespace extension { +namespace exif { + +enum ImageOrientation { + EXIF_ORIENTATION_NORMAL = 1, + EXIF_ORIENTATION_FLIP_HORIZONTAL = 2, + EXIF_ORIENTATION_ROTATE_180 = 3, + EXIF_ORIENTATION_FLIP_VERTICAL = 4, + EXIF_ORIENTATION_TRANSPOSE = 5, + EXIF_ORIENTATION_ROTATE_90 = 6, + EXIF_ORIENTATION_TRANSVERSE = 7, + EXIF_ORIENTATION_ROTATE_270 = 8, + EXIF_ORIENTATION_NOT_VALID, +}; + +enum WhiteBalanceMode { + EXIF_WHITE_BALANCE_MODE_AUTO = 0, + EXIF_WHITE_BALANCE_MODE_MANUAL = 1, + EXIF_WHITE_BALANCE_MODE_NOT_VALID +}; + +enum ExposureProgram { + EXIF_EXPOSURE_PROGRAM_NOT_DEFINED = 0, + EXIF_EXPOSURE_PROGRAM_MANUAL = 1, + EXIF_EXPOSURE_PROGRAM_NORMAL = 2, + EXIF_EXPOSURE_PROGRAM_APERTURE_PRIORITY = 3, + EXIF_EXPOSURE_PROGRAM_SHUTTER_PRIORITY = 4, + EXIF_EXPOSURE_PROGRAM_CREATIVE_PROGRAM = 5, + EXIF_EXPOSURE_PROGRAM_ACTION_PROGRAM = 6, + EXIF_EXPOSURE_PROGRAM_PORTRAIT_MODE = 7, + EXIF_EXPOSURE_PROGRAM_LANDSCAPE_MODE = 8, + EXIF_EXPOSURE_PROGRAM_NOT_VALID +}; + +/** + * From Exif 2.2 specification: + * The following types are used in Exif: + * 1 = BYTE An 8-bit unsigned integer., + * 2 = ASCII An 8-bit byte containing one 7-bit ASCII code. The final byte is terminated + * with NULL., + * 3 = SHORT A 16-bit (2-byte) unsigned integer, + * 4 = LONG A 32-bit (4-byte) unsigned integer, + * 5 = RATIONAL Two LONGs. The first LONG is the numerator and the second LONG expresses + * the denominator., + * 7 = UNDEFINED An 8-bit byte that can take any value depending on the field definition, + * 9 = SLONG A 32-bit (4-byte) signed integer (2's complement notation), + * 10 = SRATIONAL Two SLONGs. The first SLONG is the numerator and the second SLONG is the + * denominator. + */ +struct ExifTypeInfo { + + /** + * Number of bytes used by each exif type + */ + static const size_t ByteSize; //1 byte + static const size_t ASCIISize; //1 byte (*N) + static const size_t ShortSize; //2 bytes + static const size_t LongSize; //4 bytes + static const size_t RationalSize; //8 bytes + static const size_t UndefinedSize; //1 byte (*N) + static const size_t SLongSize; //4 bytes + static const size_t SRationalSize; //8 bytes + + /** + * Id values used by Exif to identify type + */ + static const ExifByte ByteId; // 1 + static const ExifByte ASCIIId; // 2 + static const ExifByte ShortId; // 3 + static const ExifByte LongId; // 4 + static const ExifByte RationalId; // 5 + static const ExifByte UndefinedId; // 7 + static const ExifByte SLongId; // 9 + static const ExifByte SRationalId; //10 +}; + +class ExifUtil +{ +public: + ExifUtil(); + virtual ~ExifUtil(); + + static ImageOrientation stringToOrientation(const std::string& orientation); + static const std::string& orientationToString(ImageOrientation value); + + static WhiteBalanceMode stringToWhiteBalance(const std::string& white_balance); + static const std::string& whiteBalanceToString(WhiteBalanceMode value); + + static ExposureProgram stringToExposureProgram(const std::string& exposure_program); + static const std::string& exposureProgramToString(ExposureProgram value); + + static bool isValidAbsoluteURI(const std::string& uri); + static void 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); + + static std::string convertUriToPath(const std::string& str); + static std::string ltrim(const std::string& s); + + static time_t exifDateTimeOriginalToTimeT(const char* string); + static std::string timeTToExifDateTimeOriginal(time_t time); + + static size_t getSizeOfExifFormatType(ExifFormat format); + static void printExifEntryInfo(ExifEntry* entry, ExifData* exif_data); + + static void extractFromTimeT(const time_t time, + int& out_year, int& out_month, int& out_day, + int& out_hour, int& out_min, int& out_sec); + + static time_t convertToTimeT(int year, int month, int day, + int hour, int min, int sec); +}; + +} // exif +} // extension + +#endif // __TIZEN_EXIF_EXIFUTIL_H_ diff --git a/src/exif/JpegFile.cpp b/src/exif/JpegFile.cpp new file mode 100644 index 00000000..8542dffe --- /dev/null +++ b/src/exif/JpegFile.cpp @@ -0,0 +1,729 @@ +// +// Tizen Web Device API +// Copyright (c) 2014 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. +// + +// +// For details of JPEG file format see: +// http://www.media.mit.edu/pia/Research/deepview/exif.html + +#include "JpegFile.h" + +#include +#include +#include +#include + +#include "common/platform_exception.h" +#include "common/logger.h" + +namespace extension { +namespace exif { + +/** + * Size of maximal JPEG's section data length + * (since it is stored as unsigned short limit is 2^16 -1) + */ +const unsigned int MAX_JPEG_SECTION_DATA_SIZE = 65535; + +/** + * JPEG's section data length includes 2 bytes for length therefore we need to + * substract 2 from MAX_JPEG_SECTION_DATA_SIZE + */ +const unsigned int MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE = MAX_JPEG_SECTION_DATA_SIZE - 2; + +bool isJpegMarker(const int value) +{ + return value >= JPEG_MARKER_LOWEST_ID && value <= JPEG_MARKER_HIGHEST_ID; +} + +JpegMarker castToJpegMarker(const unsigned char byte) +{ + if (byte < JPEG_MARKER_LOWEST_ID || byte > JPEG_MARKER_HIGHEST_ID) { + return JPEG_MARKER_UNKNOWN; + } + + return static_cast(byte); +} + +long readUShortBE(unsigned char* src) +{ + return ((static_cast(src[0]) << 8) | static_cast(src[1])); +} + +void writeUShortBE(unsigned short value, unsigned char* buffer) +{ + buffer[0] = static_cast(value >> 8); + buffer[1] = static_cast(value); +} + +struct CArrayDeleter { + void operator()(void* buffer) { free(buffer); } +}; + +JpegFile::JpegFile() : + m_in_data(NULL), + m_in_data_size(0), + m_image_data(NULL), + m_image_size(0), + m_padding_data(NULL), + m_padding_data_size(0), + m_in_file(NULL), + m_out_file(NULL) +{ + +} + +JpegFile::~JpegFile() +{ + delete [] m_in_data; + m_in_data = NULL; + m_in_data_size = 0; + + m_padding_data = NULL; + m_padding_data_size = 0; + + for(SectionsVec::iterator it = m_sections.begin(); it != m_sections.end(); ++it) { + JpegFileSectionPtr cur = *it; + + if (cur->exif_data) { + exif_data_unref(cur->exif_data); + cur->exif_data = NULL; + } + + cur->data_ptr = NULL; + cur->size = 0; + cur->type = JPEG_MARKER_UNKNOWN; + } + + m_image_data = NULL; + m_image_size = 0; + + if (m_in_file) { + fclose(m_in_file); + m_in_file = NULL; + } + + if (m_out_file) { + fclose(m_out_file); + m_out_file = NULL; + } +} + +JpegFilePtr JpegFile::loadFile(const std::string& path) +{ + JpegFile* new_jpg = new (std::nothrow) JpegFile(); + if (!new_jpg) { + LoggerE("Couldn't allocate Jpegfile!"); + throw common::UnknownException("Memory allocation failed"); + } + + JpegFilePtr jpg_ptr(new_jpg); + jpg_ptr->load(path); + return jpg_ptr; +} + +void JpegFile::load(const std::string& path) +{ + LoggerD("Entered file:%s", path.c_str()); + + m_source_file_path = path; + + m_in_file = fopen(path.c_str(), "rb"); + if (!m_in_file) { + LoggerE("Couldn't open Jpeg file: [%s]", path.c_str()); + throw common::NotFoundException("Could not open JPG file"); + } + + fseek(m_in_file, 0, SEEK_END); + const size_t in_file_size = static_cast(ftell(m_in_file)); + fseek(m_in_file, 0, SEEK_SET); + LoggerD("JPEG file: [%s] size:%d", path.c_str(), in_file_size); + if (0 == in_file_size) { + LoggerE("Input file [%s] is empty!", path.c_str()); + throw common::UnknownException("JPEG file is invalid"); + } + + m_in_data = new (std::nothrow) unsigned char[in_file_size]; + if (!m_in_data) { + LoggerE("Couldn't allocate buffer with size: %d", in_file_size); + throw common::UnknownException("Memory allocation failed"); + } + + m_in_data_size = in_file_size; + + const size_t read_bytes = fread(m_in_data, 1, m_in_data_size, m_in_file); + if (read_bytes != m_in_data_size) { + LoggerE("Couldn't read all: %d bytes. Read only: %d bytes!", m_in_data_size, + read_bytes); + throw common::UnknownException("Could not read JPEG file"); + } + + if (fclose(m_in_file) == EOF) { + LoggerE("Couldn't close input file: %s!", path.c_str()); + } + m_in_file = NULL; + + generateListOfSections(); +} + +std::string JpegFile::getPartOfFile(const size_t offset, + const size_t num_bytes_before, + const size_t num_bytes_after) +{ + long long int start = static_cast(offset) - num_bytes_before; + if (start < 0) { + start = 0; + } + + long long int end = static_cast(offset) + num_bytes_after; + if (end >= m_in_data_size) { + end = m_in_data_size - 1; + } + + std::stringstream ss; + ss << std::setfill('0') << std::setw(2) << std::hex; + for(long long int i = start; i <= end; ++i) { + ss << static_cast(m_in_data[i]); + } + return ss.str(); +} + + +void JpegFile::generateListOfSections() +{ + LoggerD("Entered"); + + //JPEG starts with: + //FFD8 (2 bytes) - SOI Marker + // + //then: + //N sections - format of section: + //0xFF(1 byte) + Marker Number(1 byte) + Data size(2 bytes) + Data + // + //then: + //SOS 0xFF(1 byte) + Marker Number(1 byte) + Data size(2 bytes) + Data + // + //Image data + // + //FFD9 (2 bytes) - EOI Marker + // + //Warning: some images taken on Android contains some extra data at the end + //we will keep it in m_padding_data + + m_padding_data = NULL; + m_padding_data_size = 0; + + for(size_t offset = 0, iterration = 0; offset < m_in_data_size;++iterration) { + + LoggerD("offset:%d | Starting iteration: %d", offset, iterration); + const size_t search_len = 10; + size_t search_offset = 0; + for(search_offset = 0; search_offset < search_len; ++search_offset) { + //Skip bytes until first no 0xff + unsigned char& tmp_marker = m_in_data[offset + search_offset]; + if (tmp_marker != 0xff) { + break; + } + } + + if (search_len == search_offset) { + LoggerE("offset:%d | Couldn't find marker! RAW DATA:{%s}", offset, + getPartOfFile(offset, 0, 10).c_str()); + throw common::UnknownException("JPEG file is invalid"); + } + + const size_t section_offset = offset + search_offset - 1; + unsigned char* section_begin = m_in_data + section_offset; + + offset = section_offset; //Move to section begin + LoggerD("offset:%d | Moved to section begin", offset); + + if (!isJpegMarker(section_begin[1])) { + LoggerE("offset:%d | Is not valid marker: 0x%x RAW DATA:{%s}", offset, + section_begin[1], getPartOfFile(section_offset,0,4).c_str()); + throw common::UnknownException("JPEG file is invalid"); + } + + const JpegMarker cur_marker = castToJpegMarker(section_begin[1]); + LoggerD("offset:%d | Found valid marker: 0x%x RAW DATA:{%s}", offset, + cur_marker, + getPartOfFile(section_offset,0,4).c_str()); + + offset += 2; //Read 0xffxx marker tag - 2 bytes + + JpegFileSectionPtr section; + { + JpegFileSection* sec = new (std::nothrow) JpegFileSection(); + if (!sec) { + LoggerE("Couldn't allocate JpegFileSection"); + throw common::UnknownException("Memory allocation failed"); + } + + section = JpegFileSectionPtr(sec); + } + + section->type = cur_marker; + m_sections.push_back(section); + if (cur_marker == JPEG_MARKER_SOI || + cur_marker == JPEG_MARKER_EOI) { + LoggerD("offset:%d | Found: %s marker, moving to next marker at:%d", + section_offset, ((cur_marker == JPEG_MARKER_SOI) ? "SOI" : "EOI"), + offset); + + if (cur_marker == JPEG_MARKER_EOI && m_padding_data != NULL) { + LoggerW("Padding data have been found - do not try to parse end of file"); + break; + } + } + else { + //From JPEG/EXIF info: + // Please notice that "Data" contains Data size descriptor, if there is + // a Marker like this; + // + // FF C1 00 0C + // It means this Marker(0xFFC1) has 0x000C(equal 12)bytes of data. But the + // data size '12' includes "Data size" descriptor, it follows only 10 bytes of + // data after 0x000C. + // + + const long total_section_len = readUShortBE(section_begin + 2); //Include data + //size 2 bytes + + const long section_data_len = total_section_len - 2; //Exclude data + //size 2 bytes + + LoggerD("offset:%d tag:0x%x | Read total_section_len:%d (data len:%d)", + section_offset, cur_marker, total_section_len, section_data_len); + + offset += 2; //Read data size - 2 bytes + + if (total_section_len < 0) { + LoggerE("offset:%d tag:0x%x | Error: total_section_len is: %d < 0", offset, + cur_marker, total_section_len); + throw common::UnknownException("JPEG file is invalid"); + } + + if (section_offset + 2 + total_section_len > m_in_data_size) { + LoggerE("offset:%d tag:0x%x | Error: current section offset:%d" + " + 2 + total_section_len:%d = %d is greater then file size:%d", + offset, cur_marker, + section_offset, total_section_len, + section_offset + total_section_len, m_in_data_size); + throw common::UnknownException("JPEG file is invalid"); + } + + if (JPEG_MARKER_APP1 == cur_marker) { + //TODO: verify this + //-4 --> 0xFF(1 byte)+Marker Number(1 byte)+Data size(2 bytes)) + //const unsigned int exif_data_size = section_length - 4; + + const unsigned int exif_data_size = total_section_len + 2; + section->exif_data = exif_data_new_from_data (section_begin, + exif_data_size); + + LoggerD("offset:%d tag:0x%x | Loading exif from offset:%d" + " len:%d exif_data_new_from_data returned: %p", + offset, cur_marker, section_offset, exif_data_size, + section->exif_data); + + if (!section->exif_data) { + LoggerW("offset:%d tag:0x%x | Couldn't load Exif!", offset, cur_marker); + } + } + + //This just saves pointer not copying data + section->data_ptr = section_begin + 2 + 2; //2 bytes marker + 2 bytes data size + section->size = section_data_len; //Exclude data size + + if (JPEG_MARKER_SOS == cur_marker) { + //Calculate offset of first image data which is just after this SOS section + const size_t image_data_offset = section_offset + 2 + total_section_len; + + //Calculate size of image data from start to expected EOI at end of file. + // + //-2 (exclude ending EOI marker (2 bytes) + size_t image_size = m_in_data_size - image_data_offset - 2; + LoggerW("offset:%d tag:0x%x | Image data offset:%d Estimated image size:%d", + offset, cur_marker, image_data_offset, image_size); + + m_image_data = m_in_data + image_data_offset; + + size_t eoi_tag_index = 0; + bool found_eoi_tag = searchForTagInBuffer(m_in_data + image_data_offset, + m_in_data + m_in_data_size, JPEG_MARKER_EOI, eoi_tag_index); + if (!found_eoi_tag) { + LoggerE("Could not find EOI tag! Assume that there is no EOI and rest of " + "JPEG file contains image data stream: image_size+= 2"); + image_size += 2; //Skip expected EOI tag which is not present + } else { + LoggerD("EOI tag found at offset: %d from SOS data", eoi_tag_index); + + if(eoi_tag_index != image_size) { + LoggerW("Estimated image size:%d doesn't match EOI tag index:%d" + " delta:%d", image_size, eoi_tag_index, + image_size - eoi_tag_index); + + LoggerW("Setting image_size to EOI tag: %d", eoi_tag_index); + image_size = eoi_tag_index; + + m_padding_data = m_image_data + image_size + 2; //(skip EOI tag) + m_padding_data_size = (m_in_data + m_in_data_size) - m_padding_data; + LoggerW("Saving padding data from offset:%d with size:%d", + m_padding_data - m_in_data, m_padding_data_size); + } + } + + m_image_size = image_size; + + offset = image_data_offset + image_size; + LoggerD("offset:%d tag:0x%x | SOS Offset moved to next marker", offset, + cur_marker); + } + else { + offset += section_data_len; + LoggerD("offset:%d tag:0x%x | Offset moved to next marker", offset, cur_marker); + } + } + } +} + +bool JpegFile::searchForTagInBuffer(const unsigned char* buffer_start, + const unsigned char* buffer_end, + const JpegMarker marker, + size_t& out_index) +{ + LoggerD("Entered start:%p end:%p marker:0x%x", buffer_start, buffer_end, marker); + + if(!buffer_start) { + LoggerE("buffer_start is NULL"); + return false; + } + + if(!buffer_end) { + LoggerE("buffer_end is NULL"); + return false; + } + + if(buffer_end <= buffer_start) { + LoggerE("buffer_end: %p <= buffer_start: %p", buffer_end, buffer_start); + return false; + } + + LoggerD("Bytes to scan: %d", static_cast(buffer_end - buffer_start)); + const unsigned char marker_uchar = static_cast(marker); + + for(const unsigned char* ptr = buffer_start; ptr < buffer_end; ++ptr) { + + if((0xff == *ptr) && (ptr+1 < buffer_end)) { + if(marker_uchar == *(ptr+1)) { + out_index = static_cast(ptr - buffer_start); + return true; + } + } + } + + out_index = 0; + return false; +} + +void JpegFile::setNewExifData(ExifData* new_exif_data) +{ + if (!new_exif_data) { + LoggerE("Trying to set NULL exif_data!"); + throw common::UnknownException("Could not save Exif in JPEG file"); + } + + JpegFileSectionPtr exif = getExifSection(); + if (!exif) { + LoggerW("Could't find Exif section - creating new one"); + { + JpegFileSection* new_sec = new (std::nothrow) JpegFileSection(); + if (!new_sec) { + LoggerE("Couldn't allocate JpegFileSection"); + throw common::UnknownException("Memory allocation failed"); + } + new_sec->type = JPEG_MARKER_APP1; + + exif = JpegFileSectionPtr(new_sec); + } + + SectionsVec::iterator insert_it = m_sections.begin(); + bool soi_is_present = false; + + if (insert_it != m_sections.end()) { + if ((*insert_it)->type != JPEG_MARKER_SOI) { + LoggerW("First section is not SOI - Start Of Image!"); + } + else { + soi_is_present = true; + } + } + + if (!soi_is_present) { + LoggerW("SOI section is missing"); + throw common::UnknownException("JPEG file is invalid"); + } + + //Insert new Exif sections just after SOI + ++insert_it; + if (insert_it != m_sections.begin()) { + m_sections.insert(insert_it, exif); + } + else { + //This shouldn't happen since we at lest need SOS and EOI sections + m_sections.push_back(exif); + } + } + + //We don't want to save old data + exif->data_ptr = NULL; + exif->size = 0; + + exif_data_unref(exif->exif_data); + exif_data_ref (new_exif_data); + exif->exif_data = new_exif_data; +} + +ExifData* JpegFile::getExifData() +{ + JpegFileSectionPtr exif = getExifSection(); + if (!exif) { + return NULL; + } + + exif_data_ref(exif->exif_data); + return exif->exif_data; +} + +void JpegFile::saveToFile(const std::string& out_path) +{ + LoggerD("Entered out_path:%s", out_path.c_str()); + try { + saveToFilePriv(out_path); + } + catch (...) { + LoggerE("Exception occured during saveToFilePriv " + "original file: [%] new: [%s]", + m_source_file_path.c_str(), + out_path.c_str()); + + if (out_path == m_source_file_path) { + + LoggerD("Trying to recover broken JPEG file: [%s]", out_path.c_str()); + //We were writing to source file and since something went wrong let's + //restore old file - we have it in m_in_data + + FILE* outf = fopen(out_path.c_str(), "wb"); + if (!outf) { + LoggerE("Couldn't open output file: [%s] - JPEG file will not be restored!"); + } + else { + size_t bytes_wrote = fwrite(m_in_data, 1, m_in_data_size, outf); + if (bytes_wrote != m_in_data_size) { + LoggerE("Couldn't restore whole JPEG! " + "Only %d of %d bytes have been wrote!", + bytes_wrote, m_in_data_size); + } + if (EOF == fclose(outf)) { + LoggerE("Couldn't close restore output file: [%s]", out_path.c_str()); + } + } + } + + throw; + } +} + +void JpegFile::saveToFilePriv(const std::string& out_path) +{ + LoggerD("Entered out_path:%s", out_path.c_str()); + + m_out_file = fopen(out_path.c_str(), "wb"); + if (!m_out_file) { + LoggerE("Couldn't open output file: %s", out_path.c_str()); + throw common::UnknownException("Could not write JPEG file"); + } + + unsigned char tmp_buf[128]; + size_t offset = 0; + + int section_index = 0; + for(SectionsVec::iterator it = m_sections.begin(); + it != m_sections.end(); + ++it, ++ section_index) { + + JpegFileSectionPtr cur = *it; + const JpegMarker cur_marker = cur->type; + + LoggerD("offset:%d | Section: %d marker 0x%x", offset, section_index, cur_marker); + + size_t bytes_to_write = 0; + size_t bytes_wrote = 0; + + tmp_buf[0] = 0xff; + tmp_buf[1] = cur_marker; + bytes_to_write += 2; + + bool write_section_data = false; + + bool write_exif_data = false; + + std::unique_ptr exif_output_data; + unsigned int exif_output_size = 0; + + if (cur_marker != JPEG_MARKER_SOI && + cur_marker != JPEG_MARKER_EOI) { + + unsigned short section_size = 2; + if (JPEG_MARKER_APP1 && cur->exif_data) { + + unsigned char* tmp = NULL; + exif_data_save_data (cur->exif_data, &tmp, &exif_output_size); + if (!tmp || 0 == exif_output_size) { + LoggerE("Couldn't generate RAW Exif data!"); + throw common::UnknownException("Could not save Exif in JPEG file"); + } + + LoggerD("offset:%d | Generated Exif RAW Data length:%d", offset, + exif_output_size); + + exif_output_data.reset(tmp); + + if (exif_output_size > MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE) { + LoggerE("exif_output_size:%d is greater then maximum JPEG section" + "data block size: %d", exif_output_size, + MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE); + throw common::UnknownException("Exif data is to big to be saved in JPEG file"); + } + section_size += exif_output_size; + write_exif_data = true; + } + else { + section_size += cur->size; + write_section_data = true; + } + + writeUShortBE(section_size, tmp_buf + bytes_to_write); + bytes_to_write += 2; + } + + LoggerD("offset:%d | Writing section: marker:0x%x size:%d", offset, cur_marker, + cur->size); + + bytes_wrote = fwrite(tmp_buf, 1, bytes_to_write, m_out_file); + offset += bytes_wrote; + + if (bytes_wrote != bytes_to_write) { + LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write, + bytes_wrote); + throw common::UnknownException("Could not write JPEG file"); + } + + if (write_section_data && cur->size > 0) { + LoggerD("offset:%d | Writing data with length:%d", offset, cur->size); + + bytes_to_write = cur->size; + bytes_wrote = fwrite(cur->data_ptr, 1, bytes_to_write, m_out_file); + offset += bytes_wrote; + + if (bytes_wrote != bytes_to_write) { + LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write, + bytes_wrote); + throw common::UnknownException("Could not write JPEG file"); + } + } + + if (write_exif_data && exif_output_data && exif_output_size > 0) { + LoggerD("offset:%d | Writing new exif data with length:%d", offset, + exif_output_size); + + bytes_to_write = exif_output_size; + bytes_wrote = fwrite(exif_output_data.get(), 1, bytes_to_write, m_out_file); + offset += bytes_wrote; + + if (bytes_wrote != bytes_to_write) { + LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write, + bytes_wrote); + throw common::UnknownException("Could not write JPEG file"); + } + } + + if (JPEG_MARKER_SOS == cur_marker) { + LoggerD("offset:%d | Writing image data stream with lenght:%d", offset, + m_image_size); + + bytes_to_write = m_image_size; + bytes_wrote = fwrite(m_image_data, 1, bytes_to_write, m_out_file); + offset += bytes_wrote; + + if (bytes_wrote != bytes_to_write) { + LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write, + bytes_wrote); + throw common::UnknownException("Could not write JPEG file"); + } + } + } + + if (m_padding_data && m_padding_data_size > 0) { + LoggerD("Padding data exists and contains:%d bytes saving to JPEG file"); + const size_t bytes_wrote = fwrite(m_image_data, 1, m_padding_data_size, + m_out_file); + + if (bytes_wrote != m_padding_data_size) { + LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", m_padding_data_size, + bytes_wrote); + throw common::UnknownException("Could not write JPEG file"); + } + } + + if (fclose(m_out_file) == EOF) { + LoggerE("Couldn't close output file: %s", out_path.c_str()); + m_out_file = NULL; + } else { + m_out_file = NULL; + LoggerD("Closed output file: %s wrote:%d bytes: %d", out_path.c_str(), offset); + } +} + +JpegFileSectionPtr JpegFile::getExifSection() +{ + size_t num_exif_sections = 0; + JpegFileSectionPtr first_exif_section; + + for (SectionsVec::iterator it = m_sections.begin(); it != m_sections.end(); ++it) { + JpegFileSectionPtr cur = *it; + + if (JPEG_MARKER_APP1 == cur->type) { + if (!cur->exif_data) { + LoggerW("Warning: found APP1 section but exif_data is NULL (Not Exif?)"); + continue; + } + + ++num_exif_sections; + if (!first_exif_section) { + first_exif_section = cur; + } + else { + LoggerW("Warning: found %d APP1/Exif sections - only first is currently supported!"); + } + } + } + + return first_exif_section; +} + +} // namespace exif +} // namespace extension diff --git a/src/exif/JpegFile.h b/src/exif/JpegFile.h new file mode 100644 index 00000000..4eb2b1f2 --- /dev/null +++ b/src/exif/JpegFile.h @@ -0,0 +1,138 @@ +// +// Tizen Web Device API +// Copyright (c) 2014 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 __TIZEN_EXIF_JPEG_FILE_H_ +#define __TIZEN_EXIF_JPEG_FILE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace extension { +namespace exif { + +enum JpegMarker{ + JPEG_MARKER_UNKNOWN = 0x00, + JPEG_MARKER_LOWEST_ID = 0xc0, + JPEG_MARKER_SOI = 0xd8, //Start Of Image + JPEG_MARKER_EOI = 0xd9, //End Of Image + JPEG_MARKER_SOS = 0xda, //Start Of Stream + JPEG_MARKER_APP1 = 0xe1, //Application Data 1 - for Exif + JPEG_MARKER_HIGHEST_ID = 0xfe +}; + +struct JpegFileSection; +typedef std::shared_ptr JpegFileSectionPtr; + +struct JpegFileSection +{ + JpegFileSection() : + type(JPEG_MARKER_UNKNOWN), + data_ptr(NULL), + size(0), + exif_data(NULL) {}; + + JpegMarker type; + unsigned char* data_ptr; + unsigned short size; + + ExifData* exif_data; +}; + + +class JpegFile; +typedef std::shared_ptr JpegFilePtr; + +class JpegFile { +public: + static JpegFilePtr loadFile(const std::string& path); + ~JpegFile(); + + void setNewExifData(ExifData* new_exif_data); + + /** + * You are responsible to unreference returned data with: exif_data_unref(...) + * Example: + * ExifData* ed = jpeg.getExifData(); + * if(ed) { + * doSth(ed); + * exif_data_unref(ed); + * } + */ + ExifData* getExifData(); + + void saveToFile(const std::string& out_path); + +private: + JpegFile(); + void load(const std::string& path); + void generateListOfSections(); + + std::string getPartOfFile(const size_t offset, + const size_t num_bytes_before = 10, + const size_t num_bytes_after = 10); + + JpegFileSectionPtr getExifSection(); + void saveToFilePriv(const std::string& out_path); + + /** + * Search for first occurence of specific tag inside buffer. + * + * buffer_end is the first byte that should not be checked: + * [buffer_start ... buffer_end) + * + * For example EOI - search for first 'ffd9' in buffer + */ + static bool searchForTagInBuffer(const unsigned char* buffer_start, + const unsigned char* buffer_end, + const JpegMarker marker, + size_t& out_index); + + std::string m_source_file_path; + + unsigned char* m_in_data; + size_t m_in_data_size; + + unsigned char* m_image_data; + size_t m_image_size; + + /** + * This contains any bytes after EOI. + * Usually there should be no extra bytes after EOI unfortunately + * some cameras saves extra bytes (for example Android). + */ + unsigned char* m_padding_data; + size_t m_padding_data_size; + + FILE* m_in_file; + FILE* m_out_file; + + typedef std::vector SectionsVec; + SectionsVec m_sections; +}; + + +} // namespace exif +} // namespace extension + +#endif // __TIZEN_EXIF_JPEG_FILE_H_ diff --git a/src/exif/Rational.cpp b/src/exif/Rational.cpp new file mode 100644 index 00000000..bde7a097 --- /dev/null +++ b/src/exif/Rational.cpp @@ -0,0 +1,275 @@ +// +// Tizen Web Device API +// Copyright (c) 2014 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 "Rational.h" + +#include "math.h" + +#include "common/platform_exception.h" +#include "common/logger.h" + +#include + +namespace extension { +namespace exif { + +namespace { +const double DOUBLE_ERROR_REPRESENTATION = static_cast(0x7FFFFFFF); +} //anonymous namespace + +Rational::Rational() : + nominator(0), + denominator(0) +{ +} + +Rational::Rational(ExifLong nom, ExifLong denom) : + nominator(nom), + denominator(denom) +{ +} + +Rational::Rational(const ExifRational& exif_rational) : + nominator(exif_rational.numerator), + denominator(exif_rational.denominator) +{ +} + +Rational Rational::createFromDouble(const double value, const long precision) +{ + LoggerD("Entered value:%f precision:%d", value, precision); + if (value < 0.0) { + LoggerW("Trying to create negative Rational: %f!", value); + return Rational(); + } + + if (value < 0.000000001) { + LoggerD("Skipping calculation returning: Rational(0,1)"); + return Rational(0,1); + } + + long m[2][2]; + double x, startx; + long ai; + + startx = x = value; + + // initialize matrix + m[0][0] = m[1][1] = 1; + m[0][1] = m[1][0] = 0; + + //loop finding terms until daemon gets too big + do { + ai = static_cast(x); + if(m[1][0] * ai + m[1][1] > precision) { + break; + } + + long t = m[0][0] * ai + m[0][1]; + m[0][1] = m[0][0]; + m[0][0] = t; + + t = m[1][0] * ai + m[1][1]; + m[1][1] = m[1][0]; + m[1][0] = t; + + if (x == static_cast(ai)) { + break; // AF: division by zero + } + + x = 1 / (x - static_cast(ai)); + if (x > DOUBLE_ERROR_REPRESENTATION) { + break; // AF: representation failure + } + } while(1); + + // now remaining x is between 0 and 1/ai + // approx as either 0 or 1/m where m is max that will fit in precision + // first try zero + const double error0 = startx - ((double) m[0][0] / (double) m[1][0]); + const long numerator0 = m[0][0]; + const long denominator0 = m[1][0]; + + LoggerD("%ld/%ld, error = %e\n", numerator0, denominator0, error0); + + /* now try other possibility */ + ai = (precision - m[1][1]) / m[1][0]; + m[0][0] = m[0][0] * ai + m[0][1]; + m[1][0] = m[1][0] * ai + m[1][1]; + + double error1m = startx - + (static_cast(m[0][0]) / static_cast(m[1][0])); + LoggerD("%ld/%ld, error = %e\n", m[0][0], m[1][0], error1m ); + + long result_numerator = 0; + long result_denominator = 0; + + if (error0 < error1m ) { + result_numerator = numerator0; + result_denominator = denominator0; + } + else { + result_numerator = m[0][0]; + result_denominator = m[1][0]; + } + + if (result_numerator < 0) { + result_numerator *= -1; + } + if (result_denominator < 0) { + result_denominator *= -1; + } + + LoggerD("Rational(%d, %d) error0 < error1m:%d", result_numerator, result_denominator, + error0 < error1m); + + return Rational(numerator0, denominator0); +} + +Rational Rational::createInvalid() +{ + return Rational(0,0); +} + +bool Rational::isValid() const +{ + if (0 == denominator) { + return false; + } + else { + return true; + } +} + +double Rational::toDouble() const +{ + if (!isValid()) { + return NAN; + } + + return (double)nominator / (double)denominator; +} + +Rational Rational::createFromExposureTimeString(const std::string& exp_time) +{ + LoggerD("Entered"); + if (exp_time.length() == 0) { + return Rational::createInvalid(); //lets assume that empty string means 0, + //however exposure time = 0 is not valid value + } + + std::string integer_part; + std::string fraction_part; + + int first_space_at = -1; + int first_slash_at = -1; + + for(size_t i=0; i < exp_time.size(); ++i) { + + const char& cur = exp_time[i]; + if (first_space_at < 0 && ' ' == cur) { + first_space_at = i; + } + if (first_slash_at < 0 && '/' == cur) { + first_slash_at = i; + } + } + + if (first_slash_at > 0) { + if (first_space_at > 0) { + integer_part = exp_time.substr(0,first_space_at); + fraction_part = exp_time.substr(first_space_at+1, + exp_time.size() - (first_space_at+1)); + } + else { + fraction_part = exp_time; + } + } + else { + integer_part = exp_time; + } + + LoggerD("first_space_at: %d first_slash_at:%d int: [%s] , frac: [%s]", + first_space_at, first_slash_at, integer_part.c_str(), fraction_part.c_str()); + + long integer_value = 0; + long nominator = 0; + long denominator = 1; + + if (integer_part.length() > 0) { + integer_value = atol(integer_part.c_str()); + } + + if (fraction_part.length() > 0) { + if (sscanf(fraction_part.c_str(), "%ld/%ld", &nominator, &denominator) != 2) { + LoggerD("Failed to parse nominator/denominator string: [%s]", + fraction_part.c_str()); + return Rational::createInvalid(); + } + } + + nominator += denominator * integer_value; + LoggerD("%d/%d -> %f", nominator, denominator, (float)nominator / denominator); + + if (0 == nominator) { + //Exposure time = 0 is invalid value + return Rational::createInvalid(); + } + + return Rational(nominator, denominator); +} + +std::string Rational::toString() const +{ + std::stringstream ss; + ss << nominator << "/" << denominator; + return ss.str(); +} + +std::string Rational::toExposureTimeString() const +{ + LoggerD("Entered"); + if (!isValid() || 0 == nominator) { + return std::string(); + } + + std::string output_str; + + if (nominator < denominator) { + output_str = toString(); + } + else if (nominator % denominator == 0) { + std::stringstream ss; + ss << nominator / denominator; + output_str = ss.str(); + } + else { + ExifLong new_nominator = nominator % denominator; + ExifLong new_denominator = denominator; + ExifLong integer_value = nominator / denominator; + + std::stringstream ss; + ss << integer_value << " "; + ss << new_nominator << "/" << new_denominator; + output_str = ss.str(); + } + + return output_str; +} + +} // exif +} // extension diff --git a/src/exif/Rational.h b/src/exif/Rational.h new file mode 100644 index 00000000..f31dd87b --- /dev/null +++ b/src/exif/Rational.h @@ -0,0 +1,97 @@ +// +// Tizen Web Device API +// Copyright (c) 2014 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 __TIZEN_EXIF_RATIONAL_H_ +#define __TIZEN_EXIF_RATIONAL_H_ + +#include +#include +#include + +#include +#include +#include + +#include "ExifUtil.h" + +namespace extension { +namespace exif { + +class Rational; +typedef std::vector Rationals; +typedef std::shared_ptr RationalsPtr; + +/** + * This class represents fraction as nominator/denominator - two ExifLong values + * Rational type is present in Exif specification - used for example in GPS coordinates + */ +class Rational +{ +public: + /** + * Default constructor sets to 0/0 - invalud rational number + */ + Rational(); + + Rational(ExifLong nom, ExifLong denom); + Rational(const ExifRational& exif_rational); + + static Rational createFromDouble(const double value, const long precision = 1000); + static Rational createInvalid(); + + /** + * Returns true if denominator is valid (!= 0) and therefore whole Rational is valid + */ + bool isValid() const; + + double toDouble() const; + + /** + * Returns string in format: nominator/denominator, + * for example: "1/4", "1/1", "5/3". + * + */ + std::string toString() const; + + /** + * Create rational number from exposure string + * Accepted format "(integer) (nominator/denominator)" + * for example: + * "1/5", "4/5" - just fraction part + * "1", "5" - just integer part + * "1 1/5", "4 1/4" - integer + fraction part + */ + static Rational createFromExposureTimeString(const std::string& exp_time); + + /** + * Return time exposure string in following format: + * + * nominator < denominator : "1/5", "4/5" + * nominator == x*denominator : "1", "5" + * nominator > denominator && nominator != x*denominator : "1 1/5", "4 1/4" + */ + std::string toExposureTimeString() const; + + ExifLong nominator; + ExifLong denominator; +}; + +} // exif +} // extension + +#endif // __TIZEN_EXIF_RATIONAL_H_ diff --git a/src/exif/exif.gyp b/src/exif/exif.gyp index e4ea5b2b..be75d89c 100644 --- a/src/exif/exif.gyp +++ b/src/exif/exif.gyp @@ -15,10 +15,27 @@ 'exif_extension.h', 'exif_instance.cc', 'exif_instance.h', + + 'ExifInformation.cpp', + 'ExifInformation.h', + 'ExifUtil.cpp', + 'ExifUtil.h', + 'ExifTagSaver.cpp', + 'ExifTagSaver.h', + 'JpegFile.cpp', + 'JpegFile.h', + 'Rational.cpp', + 'Rational.h', + 'ExifGPSLocation.cpp', + 'ExifGPSLocation.h', ], 'conditions': [ [ 'tizen == 1', { - 'variables': { }, + 'variables': { + 'packages': [ + 'libexif', + ] + }, }], ], }, diff --git a/src/exif/exif_api.js b/src/exif/exif_api.js index 05573522..59d2b998 100644 --- a/src/exif/exif_api.js +++ b/src/exif/exif_api.js @@ -59,9 +59,23 @@ ExifManager.prototype.getExifInfo = function() { } ]); - throw 'Not implemented'; + var callArgs = { + uri: args.uri + }; + + var callback = function(result) { + if (native_.isFailure(result)) { + native_.callIfPossible(args.errorCallback, native_.getErrorObject(result)); + } else { + var exifInfo = native_.getResultObject(result); + args.successCallback(exifInfo); + } + }; + + native_.call('Exif_getExifInfo', callArgs, callback); }; + ExifManager.prototype.saveExifInfo = function() { var args = validator_.validateArgs(arguments, [ { diff --git a/src/exif/exif_instance.cc b/src/exif/exif_instance.cc index 798adeed..f996bd82 100644 --- a/src/exif/exif_instance.cc +++ b/src/exif/exif_instance.cc @@ -1,16 +1,32 @@ -// Copyright (c) 2014 Samsung Electronics Co., Ltd. All Rights Reserved. +// Copyright (c) 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. #include "exif/exif_instance.h" +#include "common/task-queue.h" +#include "common/logger.h" + #include +#include -#include "common/logger.h" +#include +#include +#include +#include + +#include "ExifUtil.h" +#include "JpegFile.h" +#include "ExifInformation.h" namespace extension { namespace exif { +typedef picojson::value JsonValue; +typedef picojson::object JsonObject; +typedef picojson::array JsonArray; +typedef std::string JsonString; + namespace { const char kGetExifInfoCmd[] = "Exif_getExifInfo"; const char kSaveExifInfoCmd[] = "Exif_saveExifInfo"; @@ -19,26 +35,119 @@ const char kGetThumbnailCmd[] = "Exif_getThumbnail"; ExifInstance::ExifInstance() { using namespace std::placeholders; - #define REGISTER_SYNC(c,x) \ - RegisterSyncHandler(c, std::bind(&ExifInstance::x, this, _1, _2)); - REGISTER_SYNC(kGetExifInfoCmd, getExifInfo); - REGISTER_SYNC(kSaveExifInfoCmd, saveExifInfo); - REGISTER_SYNC(kGetThumbnailCmd, getThumbnail); - #undef REGISTER_SYNC + +#define REGISTER_ASYNC(c, x) \ + RegisterHandler(c, std::bind(&ExifInstance::x, this, _1, _2)); + REGISTER_ASYNC(kGetExifInfoCmd, getExifInfo); + REGISTER_ASYNC(kSaveExifInfoCmd, saveExifInfo); + REGISTER_ASYNC(kGetThumbnailCmd, getThumbnail); +#undef REGISTER_ASYNC } -ExifInstance::~ExifInstance() {} +ExifInstance::~ExifInstance() { } void ExifInstance::getExifInfo(const picojson::value& args, picojson::object& out) { - LoggerE("getExifInfo is not implemented"); + LoggerD("ExifInstance::getExifInfo() in c++ A"); + + 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()); + } catch (const common::PlatformException& e) { + ReportError(e, response->get()); + } + }; + + auto get_response = + [callback_id, this](const std::shared_ptr& response) -> void { + picojson::object& obj = response->get(); + obj.insert(std::make_pair("callbackId", callback_id)); + LoggerD("callback is %s", response->serialize().c_str()); + PostMessage(response->serialize().c_str()); + }; + + common::TaskQueue::GetInstance().Queue( + get, get_response, + std::shared_ptr(new JsonValue(JsonObject()))); + + LoggerD("ExifInstance::getExifInfo() END (c++)"); } void ExifInstance::saveExifInfo(const picojson::value& args, picojson::object& out) { - LoggerE("saveExifInfo is not implemented"); + LoggerE("saveExifInfo is not implemented (c++)"); } void ExifInstance::getThumbnail(const picojson::value& args, picojson::object& out) { - LoggerE("getThumbnail is not implemented"); + LoggerE("getThumbnail is not implemented (c++)"); } + } // namespace exif } // namespace extension diff --git a/src/exif/old/ExifGPSLocation.cpp b/src/exif/old/ExifGPSLocation.cpp deleted file mode 100644 index b1b2b493..00000000 --- a/src/exif/old/ExifGPSLocation.cpp +++ /dev/null @@ -1,299 +0,0 @@ -// -// Tizen Web Device API -// Copyright (c) 2014 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 "ExifGPSLocation.h" - -#include - -#include - -namespace DeviceAPI { -namespace Exif { - -GCSPosition::GCSPosition() -{ -} - -GCSPosition::GCSPosition(Rational _degrees, Rational _minutes, Rational _seconds) : - degrees(_degrees), - minutes(_minutes), - seconds(_seconds) -{ -} - -bool GCSPosition::isValid() const -{ - if (!(degrees.isValid() && minutes.isValid() && seconds.isValid())) { - return false; - } - - if ((degrees.toDouble() > 180.0f) || - (minutes.toDouble() > 60.0f) || - (seconds.toDouble() > 60.0f)) { - return false; - } - - return toDouble() <= 180.0f; -} - -double GCSPosition::toDouble() const -{ - const double degrees_value = degrees.toDouble(); - const double minutes_value = minutes.toDouble(); - const double seconds_value = seconds.toDouble(); - return (degrees_value + (minutes_value/60.0) + (seconds_value/3600.0)); -} - -Rationals GCSPosition::toRationalsVector() const -{ - Rationals vec; - vec.push_back(degrees); - vec.push_back(minutes); - vec.push_back(seconds); - return vec; -} - -std::string GCSPosition::toDebugString() const -{ - std::stringstream ss; - ss << degrees.toString() << "d "; - ss << minutes.toString() << "m "; - ss << seconds.toString() << "s"; - return ss.str(); -} - -GCSPosition GCSPosition::createFromDouble(double value) -{ - LOGD("Entered value:%f"); - if (value < 0) { - LOGW("Trying to create GCSPosition with double < 0: %f", value); - return GCSPosition(); - } - - if (value > 180.0) { - LOGW("Trying to create GCSPosition with double > 180.0: %f", value); - return GCSPosition(); - } - - const double d_degrees = floor(value); - double left = value - d_degrees; - - const double d_minutes = floor(left * 60.0); - left -= d_minutes / 60.0; - - const double d_seconds = left * 3600.0; - - LOGD("d_degrees:%f d_minutes:%f d_seconds:%f", d_degrees, d_minutes, d_seconds); - - GCSPosition pos; - pos.degrees = Rational(static_cast(d_degrees), 1); - pos.minutes = Rational(static_cast(d_minutes), 1); - pos.seconds = Rational::createFromDouble(d_seconds); - return pos; -} - -ExifGPSLocation::ExifGPSLocation() : - m_longitude_ref(GPS_LOCATION_WEST), - m_latitude_ref(GPS_LOCATION_NORTH) -{ - for(int i = 0; i < EXIF_GPS_LOCATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES; ++i) { - m_is_set[i] = false; - } -} - -void ExifGPSLocation::setLongitude(const GCSPosition& longitude) -{ - if (!longitude.isValid()) { - LOGW("longitude is not valid!"); - return; - } - - m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE] = true; - m_longitude = longitude; -} - -const GCSPosition& ExifGPSLocation::getLongitude() const -{ - return m_longitude; -} - -void ExifGPSLocation::setLongitudeRef(GPSLocationDirectionLongitude ref) -{ - m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF] = true; - m_longitude_ref = ref; -} - -GPSLocationDirectionLongitude ExifGPSLocation::getLongitudeRef() const -{ - return m_longitude_ref; -} - -void ExifGPSLocation::setLatitude(const GCSPosition& latitude) -{ - if (!latitude.isValid()) { - LOGW("latitude is not valid!"); - return; - } - - m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE] = true; - m_latitude = latitude; -} - -const GCSPosition& ExifGPSLocation::getLatitude() const -{ - return m_latitude; -} - -void ExifGPSLocation::setLatitudeRef(GPSLocationDirectionLatitude ref) -{ - m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF] = true; - m_latitude_ref = ref; -} - -GPSLocationDirectionLatitude ExifGPSLocation::getLatitudeRef() const -{ - return m_latitude_ref; -} - -bool ExifGPSLocation::isSet(ExifGPSLocationAttributes attribute) const -{ - return m_is_set[attribute]; -} - -void ExifGPSLocation::unset(ExifGPSLocationAttributes attribute) -{ - m_is_set[attribute] = false; -} - -void ExifGPSLocation::unsetAll() -{ - m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE] = false; - m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF] = false; - m_longitude = GCSPosition(); - - m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE] = false; - m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF] = false; - m_latitude = GCSPosition(); -} - -bool ExifGPSLocation::isComplete() const -{ - return m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE] && - m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF] && - m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE] && - m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF]; -} - - -bool ExifGPSLocation::isValid() const -{ - return isComplete() && m_latitude.isValid() && m_longitude.isValid(); -} - -Tizen::SimpleCoordinatesPtr ExifGPSLocation::getSimpleCoordinates() const -{ - if (!isComplete()) { - LOGW("Some attributes are not set!"); - return Tizen::SimpleCoordinatesPtr(); - } - - if (!isValid()) { - LOGW("Some attributes are not valid!"); - return Tizen::SimpleCoordinatesPtr(); - } - - const double cur_latitude = getLatitudeValue(); - const double cur_longitude = getLongitudeValue(); - - return Tizen::SimpleCoordinatesPtr( - new Tizen::SimpleCoordinates(cur_latitude, cur_longitude)); -} - -double ExifGPSLocation::getLongitudeValue() const -{ - const double longitude_dir = (m_longitude_ref == GPS_LOCATION_WEST) ? -1.0f : 1.0f; - const double longitude = m_longitude.toDouble() * longitude_dir; - return longitude; -} - -double ExifGPSLocation::getLatitudeValue() const -{ - const double latitude_dir = (m_latitude_ref == GPS_LOCATION_SOUTH) ? -1.0f : 1.0f; - const double latitude = m_latitude.toDouble() * latitude_dir; - return latitude; -} - -bool ExifGPSLocation::set(Tizen::SimpleCoordinatesPtr scoords) -{ - LOGD("Entered"); - if (!scoords) { - LOGW("Trying to set null SimpleCoordinates!"); - return false; - } - - const double longitude = scoords->getLongitude(); - const double latitude = scoords->getLatitude(); - bool updateLongitude = true; - bool updateLatitude = true; - - if(isComplete()) { - updateLatitude = getLatitudeValue() != latitude; - updateLongitude = getLongitudeValue() != longitude; - } - - LOGD("latitude:%f longitude:%f", latitude, longitude); - - GCSPosition gcs_longitude = GCSPosition::createFromDouble(fabs(longitude)); - LOGD("gcs_longitude deg:%s min:%s sec:%s", gcs_longitude.degrees.toString().c_str(), - gcs_longitude.minutes.toString().c_str(), - gcs_longitude.seconds.toString().c_str()); - - GCSPosition gcs_latitude = GCSPosition::createFromDouble(fabs(latitude)); - LOGD("gcs_latitude deg:%s min:%s sec:%s", gcs_latitude.degrees.toString().c_str(), - gcs_latitude.minutes.toString().c_str(), - gcs_latitude.seconds.toString().c_str()); - - if (!gcs_latitude.isValid() || !gcs_longitude.isValid()) { - return false; - } - - if(updateLongitude) { - setLongitude(gcs_longitude); - if (longitude >= 0.0) { - setLongitudeRef(GPS_LOCATION_EAST); - } - else { - setLongitudeRef(GPS_LOCATION_WEST); - } - } - - if(updateLatitude) { - setLatitude(gcs_latitude); - if (latitude >= 0.0) { - setLatitudeRef(GPS_LOCATION_NORTH); - } - else { - setLatitudeRef(GPS_LOCATION_SOUTH); - } - } - - return true; -} - - -} // Exif -} // DeviceAPI diff --git a/src/exif/old/ExifGPSLocation.h b/src/exif/old/ExifGPSLocation.h deleted file mode 100644 index d7aecc7e..00000000 --- a/src/exif/old/ExifGPSLocation.h +++ /dev/null @@ -1,147 +0,0 @@ -// -// Tizen Web Device API -// Copyright (c) 2014 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 __TIZEN_EXIF_EXIF_GPS_LOCATION_H_ -#define __TIZEN_EXIF_EXIF_GPS_LOCATION_H_ - -#include - -#include - -#include "ExifUtil.h" - -namespace DeviceAPI { -namespace Exif { - -enum GPSLocationDirectionLongitude { - GPS_LOCATION_WEST, - GPS_LOCATION_EAST -}; - -enum GPSLocationDirectionLatitude { - GPS_LOCATION_NORTH, - GPS_LOCATION_SOUTH -}; - -enum ExifGPSLocationAttributes { - EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE = 0, - EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF, - EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE, - EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF, - EXIF_GPS_LOCATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES -}; - -/** - * This class represents Global Coordinate System using - * three Rational numbers (as stored in Exif) - */ -struct GCSPosition -{ - GCSPosition(); - GCSPosition(Rational degrees, Rational minutes, Rational seconds); - - /** - * Create GCSPosition from degrees represented as double value - */ - static GCSPosition createFromDouble(double value); - - /** - * Verify that all components are valid Rational numbers and - * each component is within valid range. Sum of degrees, - * minutes and seconds should not be bigger then 180.0 - */ - bool isValid() const; - - /** - * Return position in degrees - */ - double toDouble() const; - - /** - * Return vector of three rationals: dgrees, minutes, seconds - */ - Rationals toRationalsVector() const; - - /** - * Return string for debugging purposes - */ - std::string toDebugString() const; - - Rational degrees; - Rational minutes; - Rational seconds; -}; - -class ExifGPSLocation -{ -public: - ExifGPSLocation(); - - void setLongitude(const GCSPosition& longitude); - const GCSPosition& getLongitude() const; - - void setLongitudeRef(GPSLocationDirectionLongitude ref); - GPSLocationDirectionLongitude getLongitudeRef() const; - - void setLatitude(const GCSPosition& latitude); - const GCSPosition& getLatitude() const; - - void setLatitudeRef(GPSLocationDirectionLatitude ref); - GPSLocationDirectionLatitude getLatitudeRef() const; - - bool isSet(ExifGPSLocationAttributes attribute) const; - void unset(ExifGPSLocationAttributes attribute); - void unsetAll(); - - /** - * Returns true only if all components are set. - */ - bool isComplete() const; - - /** - * Returns true only if all components are set and valid. - */ - bool isValid() const; - - /** - * Returns null pointer if any information is missing or incorrect - */ - Tizen::SimpleCoordinatesPtr getSimpleCoordinates() const; - - /** - * Return true if scoords has been set - */ - bool set(Tizen::SimpleCoordinatesPtr scoords); - -private: - - double getLongitudeValue() const; - double getLatitudeValue() const; - - GCSPosition m_longitude; - GPSLocationDirectionLongitude m_longitude_ref; - - GCSPosition m_latitude; - GPSLocationDirectionLatitude m_latitude_ref; - - bool m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES]; -}; - -} // Exif -} // DeviceAPI - -#endif // __TIZEN_EXIF_EXIF_GPS_LOCATION_H_ diff --git a/src/exif/old/ExifGPSTime.cpp b/src/exif/old/ExifGPSTime.cpp index aebb360d..db8d45a1 100644 --- a/src/exif/old/ExifGPSTime.cpp +++ b/src/exif/old/ExifGPSTime.cpp @@ -25,8 +25,8 @@ #include #include -namespace DeviceAPI { -namespace Exif { +namespace extension { +namespace exif { bool isValidDateFormat(const std::string& date) { @@ -271,5 +271,5 @@ void ExifGPSTime::setDateAndTime(Time::TZDatePtr new_time) m_time[2].toString().c_str()); } -} // Exif -} // DeviceAPI +} // exif +} // extension diff --git a/src/exif/old/ExifGPSTime.h b/src/exif/old/ExifGPSTime.h index 24f15cd7..3ac21f2f 100644 --- a/src/exif/old/ExifGPSTime.h +++ b/src/exif/old/ExifGPSTime.h @@ -24,8 +24,8 @@ #include "ExifUtil.h" -namespace DeviceAPI { -namespace Exif { +namespace extension { +namespace exif { class ExifGPSTime { @@ -78,7 +78,7 @@ private: time_t m_time_and_date; }; -} // Exif -} // DeviceAPI +} // exif +} // extension #endif // __TIZEN_EXIF_EXIF_GPS_TIME_H_ diff --git a/src/exif/old/ExifInformation.cpp b/src/exif/old/ExifInformation.cpp deleted file mode 100644 index c9a39f18..00000000 --- a/src/exif/old/ExifInformation.cpp +++ /dev/null @@ -1,1340 +0,0 @@ -// -// Tizen Web Device API -// Copyright (c) 2014 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 "ExifInformation.h" - -#include -#include -#include - -#include "ExifTagSaver.h" -#include "ExifUtil.h" -#include "JpegFile.h" - -using namespace DeviceAPI::Common; - -namespace DeviceAPI { -namespace Exif { - -const size_t EXIF_UNDEFINED_TYPE_LENGTH = 8; -const std::string EXIF_UNDEFINED_TYPE_ASCII = - std::string("ASCII\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH); -const std::string EXIF_UNDEFINED_TYPE_JIS = - std::string("JIS\0\0\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH); -const std::string EXIF_UNDEFINED_TYPE_UNICODE = - std::string("UNICODE\0", EXIF_UNDEFINED_TYPE_LENGTH); -const std::string EXIF_UNDEFINED_TYPE_UNDEFINED = - std::string("\0\0\0\0\0\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH); - -ExifInformation::ExifInformation() -{ - for (int attr = 0; attr < EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES; attr++) { - unset(static_cast(attr)); - } -} - -ExifInformation::~ExifInformation() -{ -} - -const std::string& ExifInformation::getUri() -{ - LOGD("Entered"); - return m_uri; -} - -void ExifInformation::setUri(const std::string& uri) -{ - LOGD("Entered"); - m_is_set[EXIF_INFORMATION_ATTRIBUTE_URI] = true; - m_uri = uri; -} - -unsigned long ExifInformation::getWidth() const -{ - LOGD("Entered"); - return m_width; -} - -void ExifInformation::setWidth(unsigned long width) -{ - LOGD("Entered"); - m_is_set[EXIF_INFORMATION_ATTRIBUTE_WIDTH] = true; - m_width = width; -} - -unsigned long ExifInformation::getHeight() const -{ - LOGD("Entered"); - return m_height; -} - -void ExifInformation::setHeight(unsigned long height) -{ - LOGD("Entered"); - m_is_set[EXIF_INFORMATION_ATTRIBUTE_HEIGHT] = true; - m_height = height; -} - -const std::string& ExifInformation::getDeviceMaker() -{ - LOGD("Entered"); - return m_device_maker; -} - -void ExifInformation::setDeviceMaker(const std::string& device_maker) -{ - LOGD("Entered"); - m_is_set[EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER] = true; - m_device_maker = device_maker; -} - -const std::string& ExifInformation::getDeviceModel() -{ - LOGD("Entered"); - return m_device_model; -} - -void ExifInformation::setDeviceModel(const std::string& device_model) -{ - LOGD("Entered"); - m_is_set[EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL] = true; - m_device_model = device_model; -} - -time_t ExifInformation::getOriginalTime() const -{ - LOGD("Entered"); - return m_original_time; -} - -void ExifInformation::setOriginalTime(time_t original_time) -{ - LOGD("Entered"); - m_is_set[EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME] = true; - m_original_time = original_time; -} - -ImageOrientation ExifInformation::getOrientation() const -{ - LOGD("Entered"); - return m_orientation; -} - -void ExifInformation::setOrientation(ImageOrientation orientation) -{ - LOGD("Entered"); - if(EXIF_ORIENTATION_NOT_VALID == orientation) { - LOGW("Trying to set NOT VALID orientation"); - return; - } - - m_is_set[EXIF_INFORMATION_ATTRIBUTE_ORIENTATION] = true; - m_orientation = orientation; -} - -const Rational& ExifInformation::getFNumber() const -{ - LOGD("Entered"); - return m_f_number; -} - -void ExifInformation::setFNumber(Rational f_number) -{ - LOGD("Entered"); - if(!f_number.isValid()) { - LOGW("Trying to set invalid F-Number: %s", f_number.toString().c_str()); - return; - } - - m_is_set[EXIF_INFORMATION_ATTRIBUTE_FNUMBER] = true; - m_f_number = f_number; -} - -Common::JSLongLongVector ExifInformation::getIsoSpeedRatings() -{ - LOGD("Entered"); - return m_iso_speed_ratings; -} - -void ExifInformation::setIsoSpeedRatings( - const std::vector& iso_speed_ratings) -{ - LOGD("Entered"); - m_is_set[EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS] = true; - m_iso_speed_ratings = iso_speed_ratings; -} - -void ExifInformation::appendIsoSpeedRatings(long long int iso_speed_rating) -{ - m_is_set[EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS] = true; - m_iso_speed_ratings.push_back(iso_speed_rating); -} - -const Rational& ExifInformation::getExposureTime() -{ - LOGD("Entered"); - return m_exposure_time; -} - -void ExifInformation::setExposureTime(const Rational& exposure_time) -{ - LOGD("Entered"); - if (!exposure_time.isValid() || 0 == exposure_time.nominator) { - LOGW("Trying to set invalid exposure time: [%s]", - exposure_time.toString().c_str()); - return; - } - - m_is_set[EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME] = true; - m_exposure_time = exposure_time; -} - -ExposureProgram ExifInformation::getExposureProgram() -{ - LOGD("Entered"); - return m_exposure_program; -} - -void ExifInformation::setExposureProgram(ExposureProgram exposure_program) -{ - LOGD("Entered"); - if (EXIF_EXPOSURE_PROGRAM_NOT_VALID == exposure_program) { - LOGW("Trying to set NOT VALID exposure program"); - return; - } - - m_is_set[EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM] = true; - m_exposure_program = exposure_program; -} - -bool ExifInformation::getFlash() const -{ - LOGD("Entered"); - return m_flash; -} - -void ExifInformation::setFlash(bool flash) -{ - LOGD("Entered"); - m_is_set[EXIF_INFORMATION_ATTRIBUTE_FLASH] = true; - m_flash = flash; -} - -const Rational& ExifInformation::getFocalLength() const -{ - LOGD("Entered"); - return m_focal_length; -} - -void ExifInformation::setFocalLength(Rational focal_length) -{ - LOGD("Entered"); - if(!focal_length.isValid()) { - LOGW("Trying to set invalid focal length: %s", focal_length.toString().c_str()); - return; - } - - m_is_set[EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH] = true; - m_focal_length = focal_length; -} - -WhiteBalanceMode ExifInformation::getWhiteBalanceMode() const -{ - LOGD("Entered"); - return m_white_balance; -} - -void ExifInformation::setWhiteBalanceMode(WhiteBalanceMode white_balance) -{ - LOGD("Entered"); - if (EXIF_WHITE_BALANCE_MODE_NOT_VALID == white_balance) { - LOGW("Trying to set NOT VALID white balance mode"); - return; - } - - m_is_set[EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE] = true; - m_white_balance = white_balance; -} - -ExifGPSLocation& ExifInformation::getGPSExifLocation() -{ - return m_exif_gps_location; -} - -Tizen::SimpleCoordinatesPtr ExifInformation::getGPSLocation() -{ - if(m_gps_location) { - return m_gps_location; - } - - - Tizen::SimpleCoordinatesPtr nscoords = m_exif_gps_location.getSimpleCoordinates(); - if(!nscoords) { - return nscoords; - } - - m_gps_location = nscoords; - return m_gps_location; -} - -void ExifInformation::setGPSLocation(Tizen::SimpleCoordinatesPtr gps_location) -{ - if(!gps_location) { - LOGW("Trying to set NULL gps location!"); - return; - } - - m_gps_location = gps_location; -} - -void ExifInformation::unsetGPSLocation() -{ - m_gps_location = Tizen::SimpleCoordinatesPtr(); - m_exif_gps_location.unsetAll(); -} - -const Rational& ExifInformation::getGpsAltitude() const -{ - LOGD("Entered"); - return m_gps_altitude; -} - -void ExifInformation::setGpsAltitude(Rational gps_altitude) -{ - LOGD("Entered"); - if(!gps_altitude.isValid()) { - LOGW("Trying to set invalid gps altitude: %s", gps_altitude.toString().c_str()); - return; - } - - m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE] = true; - m_gps_altitude = gps_altitude; -} - -GpsAltitudeRef ExifInformation::getGpsAltitudeRef() const -{ - LOGD("Entered"); - return m_gps_altitude_ref; -} - -void ExifInformation::setGpsAltitudeRef(const GpsAltitudeRef ref) -{ - LOGD("Entered"); - m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF] = true; - m_gps_altitude_ref = ref; -} - -void ExifInformation::setGpsAltitudeWithRef(double gps_altitude) -{ - LOGD("Entered"); - setGpsAltitude(Rational::createFromDouble(fabs(gps_altitude))); - - if(gps_altitude >= 0.0) { - setGpsAltitudeRef(GPS_ALTITUDE_REF_ABOVE_SEA); - } else { - setGpsAltitudeRef(GPS_ALTITUDE_REF_BELOW_SEA); - } - -} - -double ExifInformation::getGpsAltitudeWithRef() const -{ - LOGD("Entered"); - - if(!m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF] || - GPS_ALTITUDE_REF_ABOVE_SEA == m_gps_altitude_ref) { - return m_gps_altitude.toDouble(); - } else { - return -1.0 * m_gps_altitude.toDouble(); - } -} - -const std::string& ExifInformation::getGpsProcessingMethod() const -{ - LOGD("Entered"); - return m_gps_processing_method; -} - -const std::string& ExifInformation::getGpsProcessingMethodType() const -{ - LOGD("Entered"); - return m_gps_processing_method_type; -} - -void ExifInformation::setGpsProcessingMethod(const std::string& type, - const std::string& processing_method) -{ - LOGD("Entered"); - if(type != EXIF_UNDEFINED_TYPE_ASCII && - type != EXIF_UNDEFINED_TYPE_JIS && - type != EXIF_UNDEFINED_TYPE_UNICODE && - type != EXIF_UNDEFINED_TYPE_UNDEFINED) { - LOGW("Trying to set invalid GPSProcessingMethod type: [%s] len:%d", - type.c_str(), type.length()); - return; - } - - m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD] = true; - m_gps_processing_method = processing_method; - m_gps_processing_method_type = type; -} - -ExifGPSTime& ExifInformation::getExifGpsTime() -{ - return m_exif_gps_time; -} - -const ExifGPSTime& ExifInformation::getExifGpsTime() const -{ - return m_exif_gps_time; -} - -Time::TZDatePtr ExifInformation::getGpsTime() -{ - if(m_gps_time) { - return m_gps_time; - } - - if(!m_exif_gps_time.isValid()) { - return Time::TZDatePtr(); - } - - - m_gps_time = m_exif_gps_time.getTZDate(); - return m_gps_time; -} - -void ExifInformation::setGpsTime(Time::TZDatePtr new_time) -{ - if(!new_time) { - LOGW("Trying to set null new_time!"); - return; - } - - m_gps_time = new_time; -} - -void ExifInformation::unsetGPStime() -{ - m_exif_gps_time.unsetAll(); - m_gps_time = NULL; -} - - -const std::string& ExifInformation::getUserComment() -{ - LOGD("Entered"); - return m_user_comment; -} - -const std::string& ExifInformation::getUserCommentType() -{ - LOGD("Entered"); - return m_user_comment_type; -} - -void ExifInformation::setUserComment(const std::string& type, - const std::string& user_comment) -{ - LOGD("Entered"); - if(type != EXIF_UNDEFINED_TYPE_ASCII && - type != EXIF_UNDEFINED_TYPE_JIS && - type != EXIF_UNDEFINED_TYPE_UNICODE && - type != EXIF_UNDEFINED_TYPE_UNDEFINED) { - LOGW("Trying to set invalid user comment type: [%s] len:%d", - type.c_str(), type.length()); - return; - } - - m_is_set[EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT] = true; - m_user_comment_type = type; - m_user_comment = user_comment; -} - -bool ExifInformation::isSet(ExifInformationAttribute attribute) const -{ - LOGD("Entered"); - return m_is_set[attribute]; -} - -void ExifInformation::unset(ExifInformationAttribute attribute) -{ - LOGD("Entered"); - if(attribute >= EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES) { - return; - } - - m_is_set[attribute] = false; - switch (attribute) { - case EXIF_INFORMATION_ATTRIBUTE_URI: - m_uri = std::string(); - break; - case EXIF_INFORMATION_ATTRIBUTE_WIDTH: - m_width = 0; - break; - case EXIF_INFORMATION_ATTRIBUTE_HEIGHT: - m_height = 0; - break; - case EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER: - m_device_maker = std::string(); - break; - case EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL: - m_device_model = std::string(); - break; - case EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME: - m_original_time = 0; - break; - case EXIF_INFORMATION_ATTRIBUTE_ORIENTATION: - m_orientation = EXIF_ORIENTATION_NOT_VALID; - break; - case EXIF_INFORMATION_ATTRIBUTE_FNUMBER: - m_f_number = Rational::createInvalid(); - break; - case EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS: - m_iso_speed_ratings = std::vector(); - break; - case EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME: - m_exposure_time = Rational::createInvalid(); - break; - case EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM: - m_exposure_program = EXIF_EXPOSURE_PROGRAM_NOT_VALID; - break; - case EXIF_INFORMATION_ATTRIBUTE_FLASH: - m_flash = false; - break; - case EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH: - m_focal_length = Rational::createInvalid(); - break; - case EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE: - m_white_balance = EXIF_WHITE_BALANCE_MODE_NOT_VALID; - break; - case EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE: - m_gps_altitude = Rational::createInvalid(); - break; - case EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF: - m_gps_altitude_ref = GPS_ALTITUDE_REF_ABOVE_SEA; - break; - case EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD: - m_gps_processing_method = std::string(); - m_gps_processing_method_type = EXIF_UNDEFINED_TYPE_ASCII; - break; - case EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT: - m_user_comment = std::string(); - m_user_comment_type = EXIF_UNDEFINED_TYPE_ASCII; - break; - default: - break; - } -} - -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) { - LOGW("exif entry is NULL/empty"); - return false; - } - - if(entry->size < EXIF_UNDEFINED_TYPE_LENGTH) { - LOGW("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)); - LOGD( "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)); - LOGD( "Setting ExifInformation height to: [%s]", buf ); - setHeight(atol(buf)); - break; - } - case EXIF_TAG_MAKE: { - //ASCII - Any - exif_entry_get_value(entry, buf, sizeof(buf)); - LOGD( "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)); - LOGD( "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)); - LOGD( "Setting ExifInformation time original to: [%s] time_t:%d", buf, - (int)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) { - LOGW("Couldn't set ExifInformation - orientation is not valid: %d (%s)", - orient, buf); - } - else { - LOGD("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()) { - LOGD("Setting ExifInformation fnumber to: %f (%s)", fnumber.toDouble(), - fnumber.toString().c_str()); - setFNumber(fnumber); - } - else { - LOGW("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); - appendIsoSpeedRatings(iso_rating); - - LOGD("Appending ExifInformation speed ratings with: %d", - static_cast(iso_rating)); - - read_ptr += size_per_member; - } - } - else { - LOGE("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()) { - LOGD("Setting ExifInformation exposure time to: %s (%s)", - exp_time.toString().c_str(), - exp_time.toExposureTimeString().c_str()); - setExposureTime(exp_time); - } - else { - LOGD("Couldn't set ExifInformation - exposure time is not valid: %s", - exp_time.toString().c_str()); - } - } - else { - LOGE("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) { - LOGW("ExposureProgram: %d (%s) is not valid!", exp_program, buf); - } - else { - LOGD("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); - - LOGD( "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()) { - LOGD("Setting ExifInformation focal length to: %f (%s)", - flength.toDouble(), flength.toString().c_str()); - setFocalLength(flength); - } - else { - LOGW("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)); - LOGD( "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_exif_gps_location.setLongitude(longitude); - LOGD("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)); - LOGW("Couldn't set longitude pos - data is not valid: [%s]", buf); - } - break; - } - case EXIF_TAG_GPS_LONGITUDE_REF: { - //ASCII - 2 - if(entry->size < 1) { - LOGW("Longtitude ref entry do not contain enought data!"); - break; - } - - const char ref = static_cast(entry->data[0]); - if ('E' == ref || 'e' == ref) { //East - m_exif_gps_location.setLongitudeRef(GPS_LOCATION_EAST); - LOGD("Setting ExifInformation gps longitude REF to: EAST"); - } - else if ('W' == ref || 'w' == ref) { //West - m_exif_gps_location.setLongitudeRef(GPS_LOCATION_WEST); - LOGD("Setting ExifInformation gps longitude REF to: WEST"); - } - else { - LOGW("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)); - LOGD( "Setting ExifInformation latitude to: [%s], tag->%s", - buf, exif_tag_get_name(entry->tag) ); - - GCSPosition latitude; - if (getGCSPositionFromEntry(entry, exif_data, latitude)) { - m_exif_gps_location.setLatitude(latitude); - LOGD("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 { - LOGW("Couldn't set latitude pos - data is not valid!"); - } - break; - } - case EXIF_TAG_GPS_LATITUDE_REF: { - //ASCII - 2 - if(entry->size < 1) { - LOGW("Latitude ref entry do not contain enought data!"); - break; - } - - const char ref = static_cast(entry->data[0]); - if ('N' == ref || 'n' == ref) { //North - m_exif_gps_location.setLatitudeRef(GPS_LOCATION_NORTH); - LOGD("Setting ExifInformation gps latitude REF to: NORTH"); - } - else if ('S' == ref || 's' == ref) { //South - m_exif_gps_location.setLatitudeRef(GPS_LOCATION_SOUTH); - LOGD("Setting ExifInformation gps latitude REF to: SOUTH"); - } - else { - LOGW("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()) { - LOGD("Setting ExifInformation gps altitude to: %f (%s)", - gps_altitude.toDouble(), gps_altitude.toString().c_str()); - setGpsAltitude(gps_altitude); - } - else { - LOGW("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)); - LOGD( "Setting ExifInformation gps altitude ref to: %d (%s)", - static_cast(altitude_ref), - (altitude_ref > 0) ? "below sea" : "above sea"); - } else { - LOGW("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)) { - LOGD("Extracted GPSProcessingMethod: [%s], len:%d, type:%s", - value.c_str(), value.length(), type.c_str()); - setGpsProcessingMethod(type, value); - - LOGD("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 { - LOGW("GPSProcessingMethod tag contains invalid values!"); - } - break; - } - case EXIF_TAG_GPS_DATE_STAMP: { - //ASCII - 11 - exif_entry_get_value(entry, buf, sizeof(buf)); - LOGD( "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)); - LOGD( "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)) { - LOGD("Extracted UserComment: [%s], len:%d, type:%s", - value.c_str(), value.length(), type.c_str()); - setUserComment(type, value); - - LOGD("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 { - LOGW("UserComment tag contains invalid values!"); - } - - break; - } - default: - LOGD("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) { - LOGE("holder is NULL"); - } - - if (!holder->exif_info) { - LOGE("exif_info is NULL!"); - return; - } - - if (!holder->exif_data) { - LOGE("exif_data is NULL!"); - return; - } - - try { - holder->exif_info->processEntry(entry, holder->exif_data); - } - catch(const BasePlatformException &err) { - LOGE("processEntry thrown exception: %s : %s", err.getName().c_str(), - err.getMessage().c_str()); - } - catch(...) { - LOGE("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) { - LOGE("Error reading exif from file %s", file_path.c_str()); - throw NotFoundException("Error reading exif from file"); - } - - LOGD("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)); - - LOGD("exif_data_foreach_content END"); - - exif_data_unref(ed); - ed = NULL; - - return exif_info; -} - - -void ExifInformation::removeNulledAttributesFromExifData(ExifData* exif_data) -{ - LOGD("Entered"); - if(!exif_data) { - LOGE("exif_data is NULL"); - throw UnknownException("Invalid Exif provided"); - } - - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) { - LOGD("Removing width"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_IMAGE_WIDTH, exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_HEIGHT)) { - LOGD("Removing height"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_IMAGE_LENGTH, exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER)) { - LOGD("Removing device maker"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_MAKE, exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ORIENTATION)) { - LOGD("Removing orientation"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_ORIENTATION, exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) { - LOGD("Removing exposure program"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_EXPOSURE_PROGRAM, exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) { - LOGD("Removing iso speed ratings"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_ISO_SPEED_RATINGS, exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE)) { - LOGD("Removing white balance"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_WHITE_BALANCE, exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL)) { - LOGD("Removing device model"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_MODEL, exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME)) { - LOGD("Removing original time"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_DATE_TIME_ORIGINAL, exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME)) { - LOGD("Removing exposure time"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_EXPOSURE_TIME, exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FNUMBER)) { - LOGD("Removing f-number"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FNUMBER, exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FLASH)) { - LOGD("Removing flash"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FLASH, exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH)) { - LOGD("Removing focal length"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FOCAL_LENGTH, exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE)) { - LOGD("Removing gps altitude"); - ExifTagSaver::removeExifEntryWithTag( - static_cast(EXIF_TAG_GPS_ALTITUDE), exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) { - LOGD("Removing gps altitude ref"); - ExifTagSaver::removeExifEntryWithTag( - static_cast(EXIF_TAG_GPS_ALTITUDE_REF), exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) { - LOGD("Removing gps processing method"); - ExifTagSaver::removeExifEntryWithTag( - static_cast(EXIF_TAG_GPS_PROCESSING_METHOD), exif_data); - } - if (!isSet(EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT)) { - LOGD("Removing user comment"); - ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_USER_COMMENT, exif_data); - } - - if (!m_exif_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE)) { - LOGD("Removing latitude"); - ExifTagSaver::removeExifEntryWithTag( - static_cast(EXIF_TAG_GPS_LATITUDE), exif_data); - } - if (!m_exif_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF)) { - LOGD("Removing latitude ref"); - ExifTagSaver::removeExifEntryWithTag( - static_cast(EXIF_TAG_GPS_LATITUDE_REF), exif_data); - } - if (!m_exif_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE)) { - LOGD("Removing longitude"); - ExifTagSaver::removeExifEntryWithTag( - static_cast(EXIF_TAG_GPS_LONGITUDE), exif_data); - } - if (!m_exif_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF)) { - LOGD("Removing longitude ref"); - ExifTagSaver::removeExifEntryWithTag( - static_cast(EXIF_TAG_GPS_LONGITUDE_REF), exif_data); - } - - if (!m_exif_gps_time.isTimeSet()) { - LOGD("Removing gps time"); - ExifTagSaver::removeExifEntryWithTag( - static_cast(EXIF_TAG_GPS_TIME_STAMP), exif_data); - } - if (!m_exif_gps_time.isDateSet()) { - LOGD("Removing gps date"); - ExifTagSaver::removeExifEntryWithTag( - static_cast(EXIF_TAG_GPS_DATE_STAMP), exif_data); - } -} - -void ExifInformation::updateAttributesInExifData(ExifData* exif_data) -{ - LOGD("Entered"); - if(!exif_data) { - LOGE("exif_data is NULL"); - throw UnknownException("Invalid Exif provided"); - } - - if (isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) { - LOGD("Saving width: %d", getWidth()); - ExifTagSaver::saveToExif(getWidth(), - EXIF_TAG_IMAGE_WIDTH, exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_HEIGHT)) { - LOGD("Saving height: %d", getHeight()); - ExifTagSaver::saveToExif(getHeight(), - EXIF_TAG_IMAGE_LENGTH, exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER)) { - LOGD("Saving device maker: %s", getDeviceMaker().c_str()); - ExifTagSaver::saveToExif(getDeviceMaker(), - EXIF_TAG_MAKE, exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_ORIENTATION)) { - LOGD("Saving orientation: %d", static_cast(getOrientation())); - ExifTagSaver::saveToExif(static_cast(getOrientation()), - EXIF_TAG_ORIENTATION, exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) { - LOGD("Saving exposure program: %d", static_cast(getExposureProgram())); - ExifTagSaver::saveToExif(getExposureProgram(), - EXIF_TAG_EXPOSURE_PROGRAM, exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) { - std::vector iso_ratings = getIsoSpeedRatings(); - LOGD("Saving iso speed ratings count:%d", iso_ratings.size()); - ExifTagSaver::saveToExif(iso_ratings, EXIF_FORMAT_SHORT, - EXIF_TAG_ISO_SPEED_RATINGS, exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE)) { - LOGD("Saving white balance: %d", static_cast(getWhiteBalanceMode())); - ExifTagSaver::saveToExif(getWhiteBalanceMode(), - EXIF_TAG_WHITE_BALANCE, exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL)) { - LOGD("Saving device model: %s", getDeviceModel().c_str()); - ExifTagSaver::saveToExif(getDeviceModel(), - EXIF_TAG_MODEL, exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME)) { - const time_t o_time = getOriginalTime(); - const std::string o_time_str = ExifUtil::timeTToExifDateTimeOriginal(o_time); - LOGD("Saving original time time_t:%d, format:%s", static_cast(o_time), - o_time_str.c_str()); - - ExifTagSaver::saveToExif(o_time_str, - EXIF_TAG_DATE_TIME_ORIGINAL, exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME)) { - Rational exposure_time = getExposureTime(); - if (exposure_time.isValid()) { - LOGD("Saving exposure time: %s (%s)", - exposure_time.toString().c_str(), - exposure_time.toExposureTimeString().c_str()); - - ExifTagSaver::saveToExif(exposure_time, - EXIF_TAG_EXPOSURE_TIME, exif_data); - } - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_FNUMBER)) { - auto f_number = getFNumber(); - LOGD("Saving f-number: %f (%s)", f_number.toDouble(), - f_number.toString().c_str()); - ExifTagSaver::saveToExif(f_number, - EXIF_TAG_FNUMBER, exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_FLASH)) { - LOGD("Saving flash: %s", getFlash() ? "ON" : "OFF"); - ExifTagSaver::saveToExif(getFlash(), - EXIF_TAG_FLASH, exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH)) { - auto f_length = getFocalLength(); - LOGD("Saving focal length:%f (%s)", f_length.toDouble(), - f_length.toString().c_str()); - ExifTagSaver::saveToExif(f_length, - EXIF_TAG_FOCAL_LENGTH, exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE)) { - LOGD("Saving gps altitude:%f (%s)", m_gps_altitude.toDouble(), - m_gps_altitude.toString().c_str()); - ExifTagSaver::saveToExif(m_gps_altitude, - static_cast(EXIF_TAG_GPS_ALTITUDE), exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) { - //Exif spec: - //0 = Sea level - //1 = Sea level reference (negative value) - LOGD("Saving gps altitude ref:%d (%s)", static_cast(m_gps_altitude_ref), - (m_gps_altitude_ref > 0) ? "below sea" : "above sea"); - ExifTagSaver::saveToExif(static_cast(m_gps_altitude_ref), - static_cast(EXIF_TAG_GPS_ALTITUDE_REF), exif_data); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) { - LOGD("Saving gps processing method: [%s] type:%s", - getGpsProcessingMethod().c_str(), getGpsProcessingMethodType().c_str()); - - const std::string joined = getGpsProcessingMethodType() + getGpsProcessingMethod(); - LOGD("joined: [%s]", joined.c_str()); - - ExifTagSaver::saveToExif(joined, - static_cast(EXIF_TAG_GPS_PROCESSING_METHOD), exif_data, false); - } - if (isSet(EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT)) { - LOGD("Saving user comment: %s (type:%s)", getUserComment().c_str(), - getUserCommentType().c_str()); - - const std::string joined = getUserCommentType() + getUserComment(); - LOGD("joined: [%s]", joined.c_str()); - - ExifTagSaver::saveToExif(joined, - EXIF_TAG_USER_COMMENT, exif_data, false); - } - - if(m_gps_location) { - m_exif_gps_location.set(m_gps_location); - } - ExifTagSaver::saveGpsLocationToExif(m_exif_gps_location, exif_data); - - if(m_gps_time) { - m_exif_gps_time.setDateAndTime(m_gps_time); - } - ExifTagSaver::saveGpsTimeToExif(m_exif_gps_time, exif_data); -} - -void ExifInformation::saveToFile(const std::string& file_path) -{ - LOGD("Entered"); - LOGD("Using JpegFile to read: [%s] and Exif if present", file_path.c_str()); - - bool exif_data_is_new = false; - JpegFilePtr jpg_file = JpegFile::loadFile(file_path); - ExifData* exif_data = jpg_file->getExifData(); - - //Exif is not present in file - create new ExifData - if (!exif_data) { - LOGD("Exif is not present in file: [%s] creating new", file_path.c_str()); - - exif_data = exif_data_new(); - exif_data_set_option(exif_data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); - exif_data_set_data_type(exif_data, EXIF_DATA_TYPE_COMPRESSED); - exif_data_set_byte_order(exif_data, EXIF_BYTE_ORDER_MOTOROLA); - exif_data_is_new = true; - } - - if (!exif_data) { - LOGE("Couldn't allocate new ExifData"); - throw UnknownException("Memory allocation failed"); - } - - LOGD("Exif data type: %d", exif_data_get_data_type(exif_data) ); - LOGD("Exif byte order: %d", exif_data_get_byte_order(exif_data) ); - exif_data_set_option(exif_data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); - - try { - //If we have created new ExifData there is nothing to remove - if(!exif_data_is_new) { - //Remove attributes that have been nulled - removeNulledAttributesFromExifData(exif_data); - } - - updateAttributesInExifData(exif_data); - - LOGD("Using JpegFile to save new Exif in: [%s]", file_path.c_str()); - if(exif_data_is_new) { - jpg_file->setNewExifData(exif_data); - } - - jpg_file->saveToFile(file_path); - } - catch (...) { - exif_data_unref(exif_data); - exif_data = NULL; - throw; - } - - exif_data_unref(exif_data); - exif_data = NULL; -} - -} // Exif -} // DeviceAPI diff --git a/src/exif/old/ExifInformation.h b/src/exif/old/ExifInformation.h deleted file mode 100644 index 400dc862..00000000 --- a/src/exif/old/ExifInformation.h +++ /dev/null @@ -1,210 +0,0 @@ -// -// Tizen Web Device API -// Copyright (c) 2014 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 __TIZEN_EXIF_EXIFINFORMATION_H_ -#define __TIZEN_EXIF_EXIFINFORMATION_H_ - -#include -#include - -#include -#include - -#include "ExifGPSLocation.h" -#include "ExifGPSTime.h" - -namespace DeviceAPI { -namespace Exif { - -class ExifInformation; -typedef std::shared_ptr ExifInformationPtr; - -extern const size_t EXIF_UNDEFINED_TYPE_LENGTH; -extern const std::string EXIF_UNDEFINED_TYPE_ASCII; -extern const std::string EXIF_UNDEFINED_TYPE_JIS; -extern const std::string EXIF_UNDEFINED_TYPE_UNICODE; -extern const std::string EXIF_UNDEFINED_TYPE_UNDEFINED; - -enum ExifInformationAttribute{ - EXIF_INFORMATION_ATTRIBUTE_URI, - EXIF_INFORMATION_ATTRIBUTE_WIDTH, - EXIF_INFORMATION_ATTRIBUTE_HEIGHT, - EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER, - EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL, - EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME, - EXIF_INFORMATION_ATTRIBUTE_ORIENTATION, - EXIF_INFORMATION_ATTRIBUTE_FNUMBER, - EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS, - EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME, - EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM, - EXIF_INFORMATION_ATTRIBUTE_FLASH, - EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH, - EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE, - EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE, - EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF, - EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD, - EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT, - EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES -}; - -enum GpsAltitudeRef { - GPS_ALTITUDE_REF_ABOVE_SEA = 0, - GPS_ALTITUDE_REF_BELOW_SEA = 1 -}; - -class ExifInformation -{ -public: - ExifInformation(); - ~ExifInformation(); - - static ExifInformationPtr loadFromURI(const std::string& uri); - void saveToFile(const std::string& file_path); - - const std::string& getUri(); - void setUri(const std::string& uri); - - unsigned long getWidth() const; - void setWidth(unsigned long width); - - unsigned long getHeight() const; - void setHeight(unsigned long height); - - const std::string& getDeviceMaker(); - void setDeviceMaker(const std::string& device_maker); - - const std::string& getDeviceModel(); - void setDeviceModel(const std::string& device_model); - - time_t getOriginalTime() const; - void setOriginalTime(time_t original_time); - - ImageOrientation getOrientation() const; - void setOrientation(ImageOrientation orientation); - - const Rational& getFNumber() const; - void setFNumber(Rational f_number); - - Common::JSLongLongVector getIsoSpeedRatings(); - void setIsoSpeedRatings(const std::vector& iso_speed_ratings); - void appendIsoSpeedRatings(long long int iso_speed_rating); - - const Rational& getExposureTime(); - void setExposureTime(const Rational& exposure_time); - - ExposureProgram getExposureProgram(); - void setExposureProgram(ExposureProgram exposure_program ); - - bool getFlash() const; - void setFlash(bool flash); - - const Rational& getFocalLength() const; - void setFocalLength(Rational focal_length); - - WhiteBalanceMode getWhiteBalanceMode() const; - void setWhiteBalanceMode(WhiteBalanceMode white_balance); - - ExifGPSLocation& getGPSExifLocation(); - Tizen::SimpleCoordinatesPtr getGPSLocation(); - void setGPSLocation(Tizen::SimpleCoordinatesPtr gps_location); - void unsetGPSLocation(); - - const Rational& getGpsAltitude() const; - void setGpsAltitude(Rational gps_altitude); - - GpsAltitudeRef getGpsAltitudeRef() const; - void setGpsAltitudeRef(const GpsAltitudeRef ref); - - /** - * gps_altitude can be negative and positive: - * if gps_altitude < 0.0 GPS_ALTITUDE_REF_BELOW_SEA is set - * if gps_altitude >= 0.0 GPS_ALTITUDE_REF_ABOVE_SEA is set - */ - void setGpsAltitudeWithRef(double gps_altitude); - - /** - * Return gps altitude which can be negative (below sea level) and positive (above sea - * level) - */ - double getGpsAltitudeWithRef() const; - - const std::string& getGpsProcessingMethod() const; - const std::string& getGpsProcessingMethodType() const; - void setGpsProcessingMethod(const std::string& type, - const std::string& processing_method); - - ExifGPSTime& getExifGpsTime(); - const ExifGPSTime& getExifGpsTime() const; - Time::TZDatePtr getGpsTime(); - void setGpsTime(Time::TZDatePtr new_time); - void unsetGPStime(); - - const std::string& getUserComment(); - const std::string& getUserCommentType(); - void setUserComment(const std::string& type, - const std::string& user_comment); - - bool isSet(ExifInformationAttribute attribute) const; - void unset(ExifInformationAttribute attribute); - -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); - - std::string m_uri; - unsigned long m_width; - unsigned long m_height; - std::string m_device_maker; - std::string m_device_model; - - time_t m_original_time; - - ImageOrientation m_orientation; - Rational m_f_number; - Common::JSLongLongVector m_iso_speed_ratings; - Rational m_exposure_time; - ExposureProgram m_exposure_program; - bool m_flash; - Rational m_focal_length; - WhiteBalanceMode m_white_balance; - - ExifGPSLocation m_exif_gps_location; - Tizen::SimpleCoordinatesPtr m_gps_location; - - Rational m_gps_altitude; - GpsAltitudeRef m_gps_altitude_ref; - - std::string m_gps_processing_method; - std::string m_gps_processing_method_type; - - ExifGPSTime m_exif_gps_time; - Time::TZDatePtr m_gps_time; - - std::string m_user_comment; - std::string m_user_comment_type; - - bool m_is_set[EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES]; -}; - -} // Exif -} // DeviceAPI - -#endif // __TIZEN_EXIF_EXIFINFORMATION_H_ diff --git a/src/exif/old/ExifTagSaver.cpp b/src/exif/old/ExifTagSaver.cpp deleted file mode 100644 index 6f6ebf37..00000000 --- a/src/exif/old/ExifTagSaver.cpp +++ /dev/null @@ -1,413 +0,0 @@ -// -// Tizen Web Device API -// Copyright (c) 2014 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 "ExifTagSaver.h" - -#include -#include - -#include - -#include "ExifUtil.h" - -namespace DeviceAPI { - -using namespace DeviceAPI::Common; - -namespace Exif { - -void ExifTagSaver::removeExifEntryWithTag(const ExifTag tag, ExifData* exif_data) -{ - LOGD("Entered tag:%d (0x%x)", tag, tag); - ExifEntry* exif_entry = exif_data_get_entry(exif_data, tag); - if (!exif_entry) { - LOGD("Exif entry with tag:%d (0x%x) is not present", tag, tag); - return; - } - - exif_content_remove_entry(exif_entry->parent, exif_entry); -} - -void ExifTagSaver::saveToExif(long int value, ExifTag tag, ExifData* exif_data) -{ - ExifEntry* entry = prepareEntry(exif_data, tag); - ExifByteOrder order = exif_data_get_byte_order(exif_data); - - switch (entry->format) { - case EXIF_FORMAT_BYTE: - entry->data[0] = static_cast(value); - break; - case EXIF_FORMAT_SHORT: - exif_set_short (entry->data, order, value); - break; - case EXIF_FORMAT_LONG: - exif_set_long (entry->data, order, value); - break; - case EXIF_FORMAT_SLONG: - exif_set_slong (entry->data, order, value); - break; - default: - LOGE("Error: wrong format: %d \n", entry->format ); - } -} - -void ExifTagSaver::saveToExif(const std::string& value, ExifTag tag, ExifData* exif_data, - bool add_zero_character) -{ - ExifEntry* entry = prepareEntry(exif_data, tag); - if (!value.empty()) { - - if (entry->data) { - free(entry->data); - entry->data = NULL; - } - - size_t new_len = value.length(); - if(add_zero_character) { - ++new_len; - } - - entry->size = new_len; - entry->components = new_len; - - entry->data = static_cast(malloc(entry->size)); - memcpy(entry->data, value.c_str(), value.length()); - if(add_zero_character) { - entry->data[value.length()] = '\0'; - } - } -} - -void ExifTagSaver::saveToExif(const Rational& value, ExifTag tag, ExifData* exif_data) -{ - ExifEntry* entry = prepareEntry(exif_data, tag); - entry->format = EXIF_FORMAT_RATIONAL; - - if (ExifTypeInfo::RationalSize != entry->size) { - if (entry->data) { - free(entry->data); - entry->data = NULL; - } - - entry->size = ExifTypeInfo::RationalSize; - entry->data = static_cast(malloc(entry->size)); - memset(entry->data, 0, entry->size); - } - - entry->components = 1; - - ExifByteOrder order = exif_data_get_byte_order(exif_data); - ExifRational r; - r.numerator = value.nominator; - r.denominator = value.denominator; - exif_set_rational(entry->data, order, r); -} - -void ExifTagSaver::saveToExif(const Rationals& value, ExifTag tag, ExifData* exif_data) -{ - ExifEntry* entry = prepareEntry(exif_data, tag); - ExifByteOrder order = exif_data_get_byte_order(exif_data); - entry->format = EXIF_FORMAT_RATIONAL; - - const unsigned int required_size = ExifTypeInfo::RationalSize * value.size(); - if (required_size != entry->size) { - if (entry->data) { - free(entry->data); - entry->data = NULL; - } - - entry->size = required_size; - entry->data = static_cast(malloc(entry->size)); - memset(entry->data, 0, entry->size); - } - - entry->components = value.size(); - for(size_t i = 0; i < value.size(); ++i) - { - ExifRational r; - r.numerator = value[i].nominator; - r.denominator = value[i].denominator; - exif_set_rational(entry->data + i * ExifTypeInfo::RationalSize, order, r); - } -} - -void ExifTagSaver::saveToExif(std::vector& value, ExifFormat store_as, - ExifTag tag, ExifData* exif_data) -{ - ExifEntry* entry = prepareEntry(exif_data, tag); - const ExifByteOrder order = exif_data_get_byte_order(exif_data); - - const size_t size_per_member = ExifUtil::getSizeOfExifFormatType(store_as); - switch (store_as) { - case EXIF_FORMAT_BYTE: - case EXIF_FORMAT_SHORT: - case EXIF_FORMAT_SSHORT: - case EXIF_FORMAT_LONG: - case EXIF_FORMAT_SLONG: - break; - default: - LOGE("output ExifFormat: %d is not supported!"); - return; - } - entry->format = store_as; - - const size_t num_elements = value.size(); - const unsigned int required_size = size_per_member * num_elements; - if (required_size != entry->size) { - if (entry->data) { - free(entry->data); - entry->data = NULL; - } - - entry->size = required_size; - entry->data = static_cast(malloc(entry->size)); - memset(entry->data, 0, entry->size); - } - entry->components = num_elements; - - - switch (store_as) { - case EXIF_FORMAT_BYTE: { - for(size_t i = 0; i < num_elements; ++i) { - entry->data[i] = static_cast(value[i]); - } - break; - } - - case EXIF_FORMAT_SHORT: { - for(size_t i = 0; i < num_elements; ++i) { - exif_set_short(entry->data + i * size_per_member, order, - static_cast(value[i])); - } - break; - } - - case EXIF_FORMAT_SSHORT: { - for(size_t i = 0; i < num_elements; ++i) { - exif_set_sshort(entry->data + i * size_per_member, order, - static_cast(value[i])); - } - break; - } - - case EXIF_FORMAT_LONG: { - for(size_t i = 0; i < num_elements; ++i) { - exif_set_long(entry->data + i * size_per_member, order, - static_cast(value[i])); - } - break; - } - - case EXIF_FORMAT_SLONG: { - for(size_t i = 0; i < num_elements; ++i) { - exif_set_slong(entry->data + i * size_per_member, order, - static_cast(value[i])); - } - break; - } - - default: - break; - } - - - LOGD("entry after save:"); - ExifUtil::printExifEntryInfo(entry, exif_data); -} - -void ExifTagSaver::saveGpsLocationToExif(const ExifGPSLocation& gps_info, - ExifData* exif_data) -{ - if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE)) { - auto latitude = gps_info.getLatitude(); - LOGD("Saving latitude: %s", latitude.toDebugString().c_str()); - saveToExif(latitude.toRationalsVector(), - static_cast(EXIF_TAG_GPS_LATITUDE), exif_data); - } - - if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF)) { - std::string lat_ref = - (gps_info.getLatitudeRef() == GPS_LOCATION_NORTH) ? "N" : "S"; - LOGD("Saving latitude ref: %s", lat_ref.c_str()); - saveToExif(lat_ref, static_cast(EXIF_TAG_GPS_LATITUDE_REF), exif_data); - } - - if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE)) { - - auto longitude = gps_info.getLongitude(); - LOGD("Saving longitude: %s", longitude.toDebugString().c_str()); - saveToExif(longitude.toRationalsVector(), - static_cast(EXIF_TAG_GPS_LONGITUDE), exif_data); - } - - if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF)) { - std::string long_ref = - (gps_info.getLongitudeRef() == GPS_LOCATION_WEST) ? "W" : "E"; - LOGD("Saving longitude ref: %s", long_ref.c_str()); - saveToExif(long_ref, static_cast(EXIF_TAG_GPS_LONGITUDE_REF), exif_data); - } -} - -void ExifTagSaver::saveGpsTimeToExif(const ExifGPSTime& gps_time, - ExifData* exif_data) -{ - if (gps_time.isTimeSet()) { - const Rationals& time = gps_time.getTime(); - LOGD("Saving gps time: [%s]h [%s]m [%s]d", - time[0].toString().c_str(), - time[1].toString().c_str(), - time[2].toString().c_str()); - - saveToExif(time, static_cast(EXIF_TAG_GPS_TIME_STAMP), exif_data); - } - - if (gps_time.isDateSet()) { - std::string date = gps_time.getDate(); - LOGD("Saving gps date: [%s]", date.c_str()); - - saveToExif(date, static_cast(EXIF_TAG_GPS_DATE_STAMP), exif_data); - } -} - -ExifEntry* ExifTagSaver::prepareEntry(ExifData* exif_data, ExifTag tag) -{ - LOGD("Entered m_tag:%d", tag); - - ExifEntry* exif_entry = exif_data_get_entry(exif_data, tag); - if (!exif_entry) { - exif_entry = createNewTag(exif_data, deduceIfdSection(tag), - deduceDataFormat(tag), tag ); - } - - if (!exif_entry) { - LOGE("Couldn't create new Exif tag"); - throw UnknownException("Could not save Exif to file"); - } - - exif_entry_initialize(exif_entry, tag); - - return exif_entry; -} - -ExifEntry* ExifTagSaver::createNewTag(ExifData* exif_data, ExifIfd ifd, - ExifFormat format, ExifTag tag) -{ - LOGD("Creating new tag: %d", tag); - - ExifEntry* new_entry = exif_entry_new(); - new_entry->tag = tag; - new_entry->format = format; - exif_content_add_entry(exif_data->ifd[ifd], new_entry); - exif_entry_initialize(new_entry, tag); - return new_entry; -} - -ExifIfd ExifTagSaver::deduceIfdSection(ExifTag tag) -{ - switch (static_cast(tag)) { - //Tags in IFD_0 Section - case EXIF_TAG_MAKE: - case EXIF_TAG_MODEL: - case EXIF_TAG_IMAGE_WIDTH: - case EXIF_TAG_IMAGE_LENGTH: - case EXIF_TAG_ORIENTATION: - return EXIF_IFD_0; - - //Tags in IFD_EXIF Section - case EXIF_TAG_USER_COMMENT: - case EXIF_TAG_DATE_TIME_ORIGINAL: - case EXIF_TAG_EXPOSURE_TIME: - case EXIF_TAG_FNUMBER: - case EXIF_TAG_EXPOSURE_PROGRAM: - case EXIF_TAG_ISO_SPEED_RATINGS: - case EXIF_TAG_WHITE_BALANCE: - case EXIF_TAG_FLASH: - case EXIF_TAG_FOCAL_LENGTH: - return EXIF_IFD_EXIF; - - //Tags in IFD_GPS Section - case EXIF_TAG_GPS_LATITUDE_REF: - case EXIF_TAG_GPS_LONGITUDE_REF: - case EXIF_TAG_GPS_LATITUDE: - case EXIF_TAG_GPS_LONGITUDE: - case EXIF_TAG_GPS_ALTITUDE: - case EXIF_TAG_GPS_ALTITUDE_REF: - case EXIF_TAG_GPS_TIME_STAMP: - case EXIF_TAG_GPS_PROCESSING_METHOD: - case EXIF_TAG_GPS_DATE_STAMP: - return EXIF_IFD_GPS; - - //Tags in other sections - default: - LOGE("Unsupported tag: %d", tag); - throw UnknownException("Unsupported tag"); - } -} - -ExifFormat ExifTagSaver::deduceDataFormat(ExifTag tag) -{ - switch (static_cast(tag)) { - //Tags with byte type: - case EXIF_TAG_GPS_ALTITUDE_REF: - return EXIF_FORMAT_BYTE; - - //Tags with long type: - case EXIF_TAG_IMAGE_WIDTH: - case EXIF_TAG_IMAGE_LENGTH: - return EXIF_FORMAT_LONG; - - //Tags with short type: - case EXIF_TAG_ORIENTATION: - case EXIF_TAG_EXPOSURE_PROGRAM: - case EXIF_TAG_WHITE_BALANCE: - case EXIF_TAG_FLASH: - return EXIF_FORMAT_SHORT; - - //Tags with ASCII type: - case EXIF_TAG_MAKE: - case EXIF_TAG_MODEL: - case EXIF_TAG_DATE_TIME_ORIGINAL: - case EXIF_TAG_GPS_LATITUDE_REF: - case EXIF_TAG_GPS_LONGITUDE_REF: - case EXIF_TAG_GPS_DATE_STAMP: - return EXIF_FORMAT_ASCII; - - //Tags with rational type: - case EXIF_TAG_EXPOSURE_TIME: - case EXIF_TAG_FNUMBER: - case EXIF_TAG_FOCAL_LENGTH: - case EXIF_TAG_GPS_LATITUDE: - case EXIF_TAG_GPS_LONGITUDE: - case EXIF_TAG_GPS_ALTITUDE: - case EXIF_TAG_GPS_TIME_STAMP: - case EXIF_TAG_ISO_SPEED_RATINGS: - return EXIF_FORMAT_RATIONAL; - - //Tags with undefined type: - case EXIF_TAG_USER_COMMENT: - case EXIF_TAG_GPS_PROCESSING_METHOD: - return EXIF_FORMAT_UNDEFINED; - - //Unsupported tags: - default: - LOGE("Unsupported tag: %d", tag); - throw UnknownException("Unsupported tag"); - } -} - -} // Exif -} // DeviceAPI diff --git a/src/exif/old/ExifTagSaver.h b/src/exif/old/ExifTagSaver.h deleted file mode 100644 index e1c7c4de..00000000 --- a/src/exif/old/ExifTagSaver.h +++ /dev/null @@ -1,62 +0,0 @@ -// -// Tizen Web Device API -// Copyright (c) 2014 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. -// - -/** - * @file ExifTagSaver.h - */ - -#ifndef __TIZEN_EXIF_EXIF_TAG_SAVER_H__ -#define __TIZEN_EXIF_EXIF_TAG_SAVER_H__ - -#include -#include - -#include "ExifGPSLocation.h" -#include "ExifGPSTime.h" - -namespace DeviceAPI { -namespace Exif { - -class ExifTagSaver -{ -public: - static void removeExifEntryWithTag(const ExifTag tag, ExifData* exif_data); - - static void saveToExif(long int value, ExifTag tag, ExifData* exif_data); - static void saveToExif(const std::string& value, ExifTag tag, ExifData* exif_data, - bool add_zero_character = true); - static void saveToExif(const Rational& value, ExifTag tag, ExifData* exif_data); - static void saveToExif(const Rationals& value, ExifTag tag, ExifData* exif_data); - static void saveToExif(std::vector& value, ExifFormat store_as, - ExifTag tag, ExifData* exif_data); - static void saveGpsLocationToExif(const ExifGPSLocation& gps_info, - ExifData* exif_data); - static void saveGpsTimeToExif(const ExifGPSTime& gps_time, - ExifData* exif_data); - -private: - static ExifEntry* prepareEntry(ExifData* exif_data, ExifTag tag); - static ExifIfd deduceIfdSection(ExifTag tag); - static ExifFormat deduceDataFormat(ExifTag tag); - static ExifEntry* createNewTag(ExifData* exif_data, ExifIfd ifd, - ExifFormat format, ExifTag tag); -}; - -} // Exif -} // DeviceAPI - -#endif // __TIZEN_EXIF_EXIF_TAG_SAVER_H__ diff --git a/src/exif/old/ExifUtil.cpp b/src/exif/old/ExifUtil.cpp deleted file mode 100644 index 53e66902..00000000 --- a/src/exif/old/ExifUtil.cpp +++ /dev/null @@ -1,431 +0,0 @@ -// -// Tizen Web Device API -// Copyright (c) 2014 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 "ExifUtil.h" - -#include -#include - -#include -#include - -namespace DeviceAPI { - -using namespace DeviceAPI::Common; - -namespace Exif { - -namespace { -const std::string ORIENTATION_NORMAL = "NORMAL"; -const std::string ORIENTATION_FLIP_HORIZONTAL = "FLIP_HORIZONTAL"; -const std::string ORIENTATION_ROTATE_180 = "ROTATE_180"; -const std::string ORIENTATION_FLIP_VERTICAL = "FLIP_VERTICAL"; -const std::string ORIENTATION_TRANSPOSE = "TRANSPOSE"; -const std::string ORIENTATION_ROTATE_90 = "ROTATE_90"; -const std::string ORIENTATION_TRANSVERSE = "TRANSVERSE"; -const std::string ORIENTATION_ROTATE_270 = "ROTATE_270"; - -const std::string WHITE_BALANCE_MODE_AUTO = "AUTO"; -const std::string WHITE_BALANCE_MODE_MANUAL = "MANUAL"; - -const std::string EXPOSURE_PROGRAM_NOT_DEFINED = "NOT_DEFINED"; -const std::string EXPOSURE_PROGRAM_MANUAL = "MANUAL"; -const std::string EXPOSURE_PROGRAM_NORMAL = "NORMAL"; -const std::string EXPOSURE_PROGRAM_APERTURE_PRIORITY = "APERTURE_PRIORITY"; -const std::string EXPOSURE_PROGRAM_SHUTTER_PRIORITY = "SHUTTER_PRIORITY"; -const std::string EXPOSURE_PROGRAM_CREATIVE_PROGRAM = "CREATIVE_PROGRAM"; -const std::string EXPOSURE_PROGRAM_ACTION_PROGRAM = "ACTION_PROGRAM"; -const std::string EXPOSURE_PROGRAM_PORTRAIT_MODE = "PORTRAIT_MODE"; -const std::string EXPOSURE_PROGRAM_LANDSCAPE_MODE = "LANDSCAPE_MODE"; - -const std::string DUMMY = ""; // For unexpected input handling - -const std::string URI_PREFIX = "file://"; -const std::string URI_ABSOLUTE_PREFIX = "file:///"; -} - -const size_t ExifTypeInfo::ByteSize = 1; -const size_t ExifTypeInfo::ASCIISize = 1; -const size_t ExifTypeInfo::ShortSize = 2; -const size_t ExifTypeInfo::LongSize = 4; -const size_t ExifTypeInfo::RationalSize = 8; -const size_t ExifTypeInfo::UndefinedSize = 1; -const size_t ExifTypeInfo::SLongSize = 4; -const size_t ExifTypeInfo::SRationalSize = 8; - -const ExifByte ExifTypeInfo::ByteId = 1; -const ExifByte ExifTypeInfo::ASCIIId = 2; -const ExifByte ExifTypeInfo::ShortId = 3; -const ExifByte ExifTypeInfo::LongId = 4; -const ExifByte ExifTypeInfo::RationalId = 5; -const ExifByte ExifTypeInfo::UndefinedId = 7; -const ExifByte ExifTypeInfo::SLongId = 9; -const ExifByte ExifTypeInfo::SRationalId = 10; - -ExifUtil::ExifUtil() -{ -} - -ExifUtil::~ExifUtil() -{ -} - -ImageOrientation ExifUtil::stringToOrientation(const std::string& orientation) -{ - LOGD("Entered"); - if (ORIENTATION_NORMAL == orientation) { - return ImageOrientation::EXIF_ORIENTATION_NORMAL; - } - if (ORIENTATION_FLIP_HORIZONTAL == orientation) { - return ImageOrientation::EXIF_ORIENTATION_FLIP_HORIZONTAL; - } - if (ORIENTATION_ROTATE_180 == orientation) { - return ImageOrientation::EXIF_ORIENTATION_ROTATE_180; - } - if (ORIENTATION_FLIP_VERTICAL == orientation) { - return ImageOrientation::EXIF_ORIENTATION_FLIP_VERTICAL; - } - if (ORIENTATION_TRANSPOSE == orientation) { - return ImageOrientation::EXIF_ORIENTATION_TRANSPOSE; - } - if (ORIENTATION_ROTATE_90 == orientation) { - return ImageOrientation::EXIF_ORIENTATION_ROTATE_90; - } - if (ORIENTATION_TRANSVERSE == orientation) { - return ImageOrientation::EXIF_ORIENTATION_TRANSVERSE; - } - if (ORIENTATION_ROTATE_270 == orientation) { - return ImageOrientation::EXIF_ORIENTATION_ROTATE_270; - } - return ImageOrientation::EXIF_ORIENTATION_NOT_VALID; -} - -const std::string& ExifUtil::orientationToString(ImageOrientation orientation) -{ - LOGD("Entered"); - switch (orientation) { - case ImageOrientation::EXIF_ORIENTATION_NORMAL: - return ORIENTATION_NORMAL; - case ImageOrientation::EXIF_ORIENTATION_FLIP_HORIZONTAL: - return ORIENTATION_FLIP_HORIZONTAL; - case ImageOrientation::EXIF_ORIENTATION_ROTATE_180: - return ORIENTATION_ROTATE_180; - case ImageOrientation::EXIF_ORIENTATION_FLIP_VERTICAL: - return ORIENTATION_FLIP_VERTICAL; - case ImageOrientation::EXIF_ORIENTATION_TRANSPOSE: - return ORIENTATION_TRANSPOSE; - case ImageOrientation::EXIF_ORIENTATION_ROTATE_90: - return ORIENTATION_ROTATE_90; - case ImageOrientation::EXIF_ORIENTATION_TRANSVERSE: - return ORIENTATION_TRANSVERSE; - case ImageOrientation::EXIF_ORIENTATION_ROTATE_270: - return ORIENTATION_ROTATE_270; - default: - return DUMMY; - } -} - -WhiteBalanceMode ExifUtil::stringToWhiteBalance(const std::string& white_balance) -{ - LOGD("Entered"); - if (WHITE_BALANCE_MODE_AUTO == white_balance) { - return WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_AUTO; - } - if (WHITE_BALANCE_MODE_MANUAL == white_balance) { - return WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_MANUAL; - } - return WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_NOT_VALID; -} - -const std::string& ExifUtil::whiteBalanceToString(WhiteBalanceMode value) -{ - LOGD("Entered"); - switch (value) { - case WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_AUTO: - return WHITE_BALANCE_MODE_AUTO; - case WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_MANUAL: - return WHITE_BALANCE_MODE_MANUAL; - default: - return DUMMY; - } -} - -ExposureProgram ExifUtil::stringToExposureProgram( - const std::string& exposure_program) -{ - LOGD("Entered"); - if (EXPOSURE_PROGRAM_NOT_DEFINED == exposure_program) { - return EXIF_EXPOSURE_PROGRAM_NOT_DEFINED; - } - if (EXPOSURE_PROGRAM_MANUAL == exposure_program) { - return EXIF_EXPOSURE_PROGRAM_MANUAL; - } - if (EXPOSURE_PROGRAM_NORMAL == exposure_program) { - return EXIF_EXPOSURE_PROGRAM_NORMAL; - } - if (EXPOSURE_PROGRAM_APERTURE_PRIORITY == exposure_program) { - return EXIF_EXPOSURE_PROGRAM_APERTURE_PRIORITY; - } - if (EXPOSURE_PROGRAM_SHUTTER_PRIORITY == exposure_program) { - return EXIF_EXPOSURE_PROGRAM_SHUTTER_PRIORITY; - } - if (EXPOSURE_PROGRAM_CREATIVE_PROGRAM == exposure_program) { - return EXIF_EXPOSURE_PROGRAM_CREATIVE_PROGRAM; - } - if (EXPOSURE_PROGRAM_ACTION_PROGRAM == exposure_program) { - return EXIF_EXPOSURE_PROGRAM_ACTION_PROGRAM; - } - if (EXPOSURE_PROGRAM_PORTRAIT_MODE == exposure_program) { - return EXIF_EXPOSURE_PROGRAM_PORTRAIT_MODE; - } - if (EXPOSURE_PROGRAM_LANDSCAPE_MODE == exposure_program) { - return EXIF_EXPOSURE_PROGRAM_LANDSCAPE_MODE; - } - return EXIF_EXPOSURE_PROGRAM_NOT_VALID; -} - -const std::string& ExifUtil::exposureProgramToString(ExposureProgram value) -{ - LOGD("Entered"); - switch (value) { - case ExposureProgram::EXIF_EXPOSURE_PROGRAM_NOT_DEFINED: - return EXPOSURE_PROGRAM_NOT_DEFINED; - case ExposureProgram::EXIF_EXPOSURE_PROGRAM_MANUAL: - return EXPOSURE_PROGRAM_MANUAL; - case ExposureProgram::EXIF_EXPOSURE_PROGRAM_NORMAL: - return EXPOSURE_PROGRAM_NORMAL; - case ExposureProgram::EXIF_EXPOSURE_PROGRAM_APERTURE_PRIORITY: - return EXPOSURE_PROGRAM_APERTURE_PRIORITY; - case ExposureProgram::EXIF_EXPOSURE_PROGRAM_SHUTTER_PRIORITY: - return EXPOSURE_PROGRAM_SHUTTER_PRIORITY; - case ExposureProgram::EXIF_EXPOSURE_PROGRAM_CREATIVE_PROGRAM: - return EXPOSURE_PROGRAM_CREATIVE_PROGRAM; - case ExposureProgram::EXIF_EXPOSURE_PROGRAM_ACTION_PROGRAM: - return EXPOSURE_PROGRAM_ACTION_PROGRAM; - case ExposureProgram::EXIF_EXPOSURE_PROGRAM_PORTRAIT_MODE: - return EXPOSURE_PROGRAM_PORTRAIT_MODE; - case ExposureProgram::EXIF_EXPOSURE_PROGRAM_LANDSCAPE_MODE: - return EXPOSURE_PROGRAM_LANDSCAPE_MODE; - default: - return DUMMY; - } -} - -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 BasePlatformException &err) { - LOGE("Couldn't resolve path: %s, got:%s (%s)", absolute_path.c_str(), - (err.getName()).c_str(), (err.getMessage()).c_str()); - } - catch(...) { - LOGE("Couldn't resolve path: %s", absolute_path.c_str()); - } -} - -std::string ExifUtil::convertUriToPath(const std::string& str) -{ - std::string path = ltrim(str); - std::string prefix = path.substr(0, URI_PREFIX.size()); - - if (prefix == URI_PREFIX) { - return path.substr(URI_PREFIX.size()); - } - else { - return path; - } -} - -std::string ExifUtil::ltrim(const std::string& s) -{ - std::string str = s; - std::string::iterator i; - for (i = str.begin(); i != str.end(); i++) { - if (!isspace(*i)) { - break; - } - } - if (i == str.end()) { - str.clear(); - } - else { - str.erase(str.begin(), i); - } - return str; -} - -time_t ExifUtil::exifDateTimeOriginalToTimeT(const char* string) -{ - int year, month, day, hour, min, sec; - if (sscanf(string, "%d:%d:%d %d:%d:%d", - &year, &month, &day, &hour, &min, &sec) >= 6) { - return convertToTimeT(year, month, day, hour, min, sec); - } - - return 0; -} - -std::string ExifUtil::timeTToExifDateTimeOriginal(time_t time) -{ - int year, month, day, hour, min, sec; - extractFromTimeT(time, year, month, day, hour, min, sec); - - std::ostringstream ss; - ss << std::setfill('0') << std::setw(4) << year << ':' ; - ss << std::setfill('0') << std::setw(2) << month << ':' ; - ss << std::setfill('0') << std::setw(2) << day << ' ' ; - - ss << std::setfill('0') << std::setw(2) << hour << ':' ; - ss << std::setfill('0') << std::setw(2) << min << ':' ; - ss << std::setfill('0') << std::setw(2) << sec; - return ss.str(); -} - -size_t ExifUtil::getSizeOfExifFormatType(ExifFormat format) -{ - size_t size_per_member = 0; - switch (format) { - case EXIF_FORMAT_BYTE: - size_per_member = 1; - break; - - case EXIF_FORMAT_SHORT: - case EXIF_FORMAT_SSHORT: - size_per_member = 2; - break; - - case EXIF_FORMAT_LONG: - case EXIF_FORMAT_SLONG: - size_per_member = 4; - break; - - case EXIF_FORMAT_RATIONAL: - case EXIF_FORMAT_SRATIONAL: - size_per_member = 8; - break; - - default: - LOGE("output ExifFormat: %d is not supported!"); - return 0; - } - - return size_per_member; -} - -void ExifUtil::printExifEntryInfo(ExifEntry* entry, ExifData* exif_data) -{ - char buf[2000]; - std::stringstream ss; - - if (!entry) { - LOGE("entry is null"); - return; - } - - if (!entry->data) { - LOGE("entry data is null"); - return; - } - - unsigned char* read_buf_ptr = entry->data; - - size_t size_per_member = getSizeOfExifFormatType(entry->format); - if (0 == size_per_member) { - size_per_member = 1; //display as array of bytes - } - - for(unsigned long compi = 0; compi < entry->components; ++compi) { - - if (compi > 0) { - ss << " "; - } - - for(size_t i = 0; i < size_per_member; ++i) { - unsigned int value = read_buf_ptr[i]; - ss << std::hex << std::setw(2) << std::setfill('0') << value; - } - - read_buf_ptr += size_per_member; - } - - LOGD("Entry{name:%s type:%s size:%d components:%d value:%s RAW DATA:[%s]}", - exif_tag_get_name(entry->tag), - exif_format_get_name(entry->format), - (int)entry->size, - (int)entry->components, - exif_entry_get_value(entry, buf, sizeof(buf)), - ss.str().c_str()); -} - -void ExifUtil::extractFromTimeT(const time_t time, - int& out_year, int& out_month, int& out_day, - int& out_hour, int& out_min, int& out_sec) -{ - struct tm* utc = gmtime(&time); - - out_year = utc->tm_year + 1900; - out_month = utc->tm_mon + 1; - out_day = utc->tm_mday; - out_hour = utc->tm_hour; - out_min = utc->tm_min; - out_sec = utc->tm_sec; -} - -time_t ExifUtil::convertToTimeT(int year, int month, int day, - int hour, int min, int sec) -{ - time_t tmp_time = 0; - struct tm* timeinfo = localtime(&tmp_time); - timeinfo->tm_year = year - 1900; - timeinfo->tm_mon = month - 1; - timeinfo->tm_mday = day; - - timeinfo->tm_hour = hour; - timeinfo->tm_min = min; - timeinfo->tm_sec = sec; - - //From mktime documentation: - //"The values of the members tm_wday and tm_yday of timeptr are ignored" - return timegm(timeinfo); -} - -} // Exif -} // DeviceAPI diff --git a/src/exif/old/ExifUtil.h b/src/exif/old/ExifUtil.h deleted file mode 100644 index b687c625..00000000 --- a/src/exif/old/ExifUtil.h +++ /dev/null @@ -1,153 +0,0 @@ -// -// Tizen Web Device API -// Copyright (c) 2014 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 __TIZEN_EXIF_EXIFUTIL_H_ -#define __TIZEN_EXIF_EXIFUTIL_H_ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "Rational.h" - -namespace DeviceAPI { -namespace Exif { - -enum ImageOrientation { - EXIF_ORIENTATION_NORMAL = 1, - EXIF_ORIENTATION_FLIP_HORIZONTAL = 2, - EXIF_ORIENTATION_ROTATE_180 = 3, - EXIF_ORIENTATION_FLIP_VERTICAL = 4, - EXIF_ORIENTATION_TRANSPOSE = 5, - EXIF_ORIENTATION_ROTATE_90 = 6, - EXIF_ORIENTATION_TRANSVERSE = 7, - EXIF_ORIENTATION_ROTATE_270 = 8, - EXIF_ORIENTATION_NOT_VALID, -}; - -enum WhiteBalanceMode { - EXIF_WHITE_BALANCE_MODE_AUTO = 0, - EXIF_WHITE_BALANCE_MODE_MANUAL = 1, - EXIF_WHITE_BALANCE_MODE_NOT_VALID -}; - -enum ExposureProgram { - EXIF_EXPOSURE_PROGRAM_NOT_DEFINED = 0, - EXIF_EXPOSURE_PROGRAM_MANUAL = 1, - EXIF_EXPOSURE_PROGRAM_NORMAL = 2, - EXIF_EXPOSURE_PROGRAM_APERTURE_PRIORITY = 3, - EXIF_EXPOSURE_PROGRAM_SHUTTER_PRIORITY = 4, - EXIF_EXPOSURE_PROGRAM_CREATIVE_PROGRAM = 5, - EXIF_EXPOSURE_PROGRAM_ACTION_PROGRAM = 6, - EXIF_EXPOSURE_PROGRAM_PORTRAIT_MODE = 7, - EXIF_EXPOSURE_PROGRAM_LANDSCAPE_MODE = 8, - EXIF_EXPOSURE_PROGRAM_NOT_VALID -}; - -/** - * From Exif 2.2 specification: - * The following types are used in Exif: - * 1 = BYTE An 8-bit unsigned integer., - * 2 = ASCII An 8-bit byte containing one 7-bit ASCII code. The final byte is terminated - * with NULL., - * 3 = SHORT A 16-bit (2-byte) unsigned integer, - * 4 = LONG A 32-bit (4-byte) unsigned integer, - * 5 = RATIONAL Two LONGs. The first LONG is the numerator and the second LONG expresses - * the denominator., - * 7 = UNDEFINED An 8-bit byte that can take any value depending on the field definition, - * 9 = SLONG A 32-bit (4-byte) signed integer (2's complement notation), - * 10 = SRATIONAL Two SLONGs. The first SLONG is the numerator and the second SLONG is the - * denominator. - */ -struct ExifTypeInfo { - - /** - * Number of bytes used by each exif type - */ - static const size_t ByteSize; //1 byte - static const size_t ASCIISize; //1 byte (*N) - static const size_t ShortSize; //2 bytes - static const size_t LongSize; //4 bytes - static const size_t RationalSize; //8 bytes - static const size_t UndefinedSize; //1 byte (*N) - static const size_t SLongSize; //4 bytes - static const size_t SRationalSize; //8 bytes - - /** - * Id values used by Exif to identify type - */ - static const ExifByte ByteId; // 1 - static const ExifByte ASCIIId; // 2 - static const ExifByte ShortId; // 3 - static const ExifByte LongId; // 4 - static const ExifByte RationalId; // 5 - static const ExifByte UndefinedId; // 7 - static const ExifByte SLongId; // 9 - static const ExifByte SRationalId; //10 -}; - -class ExifUtil -{ -public: - ExifUtil(); - virtual ~ExifUtil(); - - static ImageOrientation stringToOrientation(const std::string& orientation); - static const std::string& orientationToString(ImageOrientation value); - - static WhiteBalanceMode stringToWhiteBalance(const std::string& white_balance); - static const std::string& whiteBalanceToString(WhiteBalanceMode value); - - static ExposureProgram stringToExposureProgram(const std::string& exposure_program); - static const std::string& exposureProgramToString(ExposureProgram value); - - static bool isValidAbsoluteURI(const std::string& uri); - static void 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); - - static std::string convertUriToPath(const std::string& str); - static std::string ltrim(const std::string& s); - - static time_t exifDateTimeOriginalToTimeT(const char* string); - static std::string timeTToExifDateTimeOriginal(time_t time); - - static size_t getSizeOfExifFormatType(ExifFormat format); - static void printExifEntryInfo(ExifEntry* entry, ExifData* exif_data); - - static void extractFromTimeT(const time_t time, - int& out_year, int& out_month, int& out_day, - int& out_hour, int& out_min, int& out_sec); - - static time_t convertToTimeT(int year, int month, int day, - int hour, int min, int sec); -}; - -} // EXIF -} // DeviceApi - -#endif // __TIZEN_EXIF_EXIFUTIL_H_ diff --git a/src/exif/old/JpegFile.cpp b/src/exif/old/JpegFile.cpp deleted file mode 100644 index a03272ea..00000000 --- a/src/exif/old/JpegFile.cpp +++ /dev/null @@ -1,733 +0,0 @@ -// -// Tizen Web Device API -// Copyright (c) 2014 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. -// - -// -// For details of JPEG file format see: -// http://www.media.mit.edu/pia/Research/deepview/exif.html - -#include "JpegFile.h" - -#include -#include -#include -#include - -#include -#include - -namespace DeviceAPI { - -using namespace DeviceAPI::Common; - -namespace Exif { - -/** - * Size of maximal JPEG's section data length - * (since it is stored as unsigned short limit is 2^16 -1) - */ -const unsigned int MAX_JPEG_SECTION_DATA_SIZE = 65535; - -/** - * JPEG's section data length includes 2 bytes for length therefore we need to - * substract 2 from MAX_JPEG_SECTION_DATA_SIZE - */ -const unsigned int MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE = MAX_JPEG_SECTION_DATA_SIZE - 2; - -bool isJpegMarker(const int value) -{ - return value >= JPEG_MARKER_LOWEST_ID && value <= JPEG_MARKER_HIGHEST_ID; -} - -JpegMarker castToJpegMarker(const unsigned char byte) -{ - if (byte < JPEG_MARKER_LOWEST_ID || byte > JPEG_MARKER_HIGHEST_ID) { - return JPEG_MARKER_UNKNOWN; - } - - return static_cast(byte); -} - -long readUShortBE(unsigned char* src) -{ - return ((static_cast(src[0]) << 8) | static_cast(src[1])); -} - -void writeUShortBE(unsigned short value, unsigned char* buffer) -{ - buffer[0] = static_cast(value >> 8); - buffer[1] = static_cast(value); -} - -struct CArrayDeleter { - void operator()(void* buffer) { free(buffer); } -}; - -JpegFile::JpegFile() : - m_in_data(NULL), - m_in_data_size(0), - m_image_data(NULL), - m_image_size(0), - m_padding_data(NULL), - m_padding_data_size(0), - m_in_file(NULL), - m_out_file(NULL) -{ - -} - -JpegFile::~JpegFile() -{ - delete [] m_in_data; - m_in_data = NULL; - m_in_data_size = 0; - - m_padding_data = NULL; - m_padding_data_size = 0; - - for(SectionsVec::iterator it = m_sections.begin(); it != m_sections.end(); ++it) { - JpegFileSectionPtr cur = *it; - - if (cur->exif_data) { - exif_data_unref(cur->exif_data); - cur->exif_data = NULL; - } - - cur->data_ptr = NULL; - cur->size = 0; - cur->type = JPEG_MARKER_UNKNOWN; - } - - m_image_data = NULL; - m_image_size = 0; - - if (m_in_file) { - fclose(m_in_file); - m_in_file = NULL; - } - - if (m_out_file) { - fclose(m_out_file); - m_out_file = NULL; - } -} - -JpegFilePtr JpegFile::loadFile(const std::string& path) -{ - JpegFile* new_jpg = new (std::nothrow) JpegFile(); - if (!new_jpg) { - LOGE("Couldn't allocate Jpegfile!"); - throw UnknownException("Memory allocation failed"); - } - - JpegFilePtr jpg_ptr(new_jpg); - jpg_ptr->load(path); - return jpg_ptr; -} - -void JpegFile::load(const std::string& path) -{ - LOGD("Entered file:%s", path.c_str()); - - m_source_file_path = path; - - m_in_file = fopen(path.c_str(), "rb"); - if (!m_in_file) { - LOGE("Couldn't open Jpeg file: [%s]", path.c_str()); - throw NotFoundException("Could not open JPG file"); - } - - fseek(m_in_file, 0, SEEK_END); - const size_t in_file_size = static_cast(ftell(m_in_file)); - fseek(m_in_file, 0, SEEK_SET); - LOGD("JPEG file: [%s] size:%d", path.c_str(), in_file_size); - if (0 == in_file_size) { - LOGE("Input file [%s] is empty!", path.c_str()); - throw UnknownException("JPEG file is invalid"); - } - - m_in_data = new (std::nothrow) unsigned char[in_file_size]; - if (!m_in_data) { - LOGE("Couldn't allocate buffer with size: %d", in_file_size); - throw UnknownException("Memory allocation failed"); - } - - m_in_data_size = in_file_size; - - const size_t read_bytes = fread(m_in_data, 1, m_in_data_size, m_in_file); - if (read_bytes != m_in_data_size) { - LOGE("Couldn't read all: %d bytes. Read only: %d bytes!", m_in_data_size, - read_bytes); - throw UnknownException("Could not read JPEG file"); - } - - if (fclose(m_in_file) == EOF) { - LOGE("Couldn't close input file: %s!", path.c_str()); - } - m_in_file = NULL; - - generateListOfSections(); -} - -std::string JpegFile::getPartOfFile(const size_t offset, - const size_t num_bytes_before, - const size_t num_bytes_after) -{ - long long int start = static_cast(offset) - num_bytes_before; - if (start < 0) { - start = 0; - } - - long long int end = static_cast(offset) + num_bytes_after; - if (end >= m_in_data_size) { - end = m_in_data_size - 1; - } - - std::stringstream ss; - ss << std::setfill('0') << std::setw(2) << std::hex; - for(long long int i = start; i <= end; ++i) { - ss << static_cast(m_in_data[i]); - } - return ss.str(); -} - - -void JpegFile::generateListOfSections() -{ - LOGD("Entered"); - - //JPEG starts with: - //FFD8 (2 bytes) - SOI Marker - // - //then: - //N sections - format of section: - //0xFF(1 byte) + Marker Number(1 byte) + Data size(2 bytes) + Data - // - //then: - //SOS 0xFF(1 byte) + Marker Number(1 byte) + Data size(2 bytes) + Data - // - //Image data - // - //FFD9 (2 bytes) - EOI Marker - // - //Warning: some images taken on Android contains some extra data at the end - //we will keep it in m_padding_data - - m_padding_data = NULL; - m_padding_data_size = 0; - - for(size_t offset = 0, iterration = 0; offset < m_in_data_size;++iterration) { - - LOGD("offset:%d | Starting iteration: %d", offset, iterration); - const size_t search_len = 10; - size_t search_offset = 0; - for(search_offset = 0; search_offset < search_len; ++search_offset) { - //Skip bytes until first no 0xff - unsigned char& tmp_marker = m_in_data[offset + search_offset]; - if (tmp_marker != 0xff) { - break; - } - } - - if (search_len == search_offset) { - LOGE("offset:%d | Couldn't find marker! RAW DATA:{%s}", offset, - getPartOfFile(offset, 0, 10).c_str()); - throw UnknownException("JPEG file is invalid"); - } - - const size_t section_offset = offset + search_offset - 1; - unsigned char* section_begin = m_in_data + section_offset; - - offset = section_offset; //Move to section begin - LOGD("offset:%d | Moved to section begin", offset); - - if (!isJpegMarker(section_begin[1])) { - LOGE("offset:%d | Is not valid marker: 0x%x RAW DATA:{%s}", offset, - section_begin[1], getPartOfFile(section_offset,0,4).c_str()); - throw UnknownException("JPEG file is invalid"); - } - - const JpegMarker cur_marker = castToJpegMarker(section_begin[1]); - LOGD("offset:%d | Found valid marker: 0x%x RAW DATA:{%s}", offset, - cur_marker, - getPartOfFile(section_offset,0,4).c_str()); - - offset += 2; //Read 0xffxx marker tag - 2 bytes - - JpegFileSectionPtr section; - { - JpegFileSection* sec = new (std::nothrow) JpegFileSection(); - if (!sec) { - LOGE("Couldn't allocate JpegFileSection"); - throw UnknownException("Memory allocation failed"); - } - - section = JpegFileSectionPtr(sec); - } - - section->type = cur_marker; - m_sections.push_back(section); - if (cur_marker == JPEG_MARKER_SOI || - cur_marker == JPEG_MARKER_EOI) { - LOGD("offset:%d | Found: %s marker, moving to next marker at:%d", - section_offset, ((cur_marker == JPEG_MARKER_SOI) ? "SOI" : "EOI"), - offset); - - if(cur_marker == JPEG_MARKER_EOI && m_padding_data != NULL) { - LOGW("Padding data have been found - do not try to parse end of file"); - break; - } - } - else { - //From JPEG/EXIF info: - // Please notice that "Data" contains Data size descriptor, if there is - // a Marker like this; - // - // FF C1 00 0C - // It means this Marker(0xFFC1) has 0x000C(equal 12)bytes of data. But the - // data size '12' includes "Data size" descriptor, it follows only 10 bytes of - // data after 0x000C. - // - - const long total_section_len = readUShortBE(section_begin + 2); //Include data - //size 2 bytes - - const long section_data_len = total_section_len - 2; //Exclude data - //size 2 bytes - - LOGD("offset:%d tag:0x%x | Read total_section_len:%d (data len:%d)", - section_offset, cur_marker, total_section_len, section_data_len); - - offset += 2; //Read data size - 2 bytes - - if (total_section_len < 0) { - LOGE("offset:%d tag:0x%x | Error: total_section_len is: %d < 0", offset, - cur_marker, total_section_len); - throw UnknownException("JPEG file is invalid"); - } - - if (section_offset + 2 + total_section_len > m_in_data_size) { - LOGE("offset:%d tag:0x%x | Error: current section offset:%d" - " + 2 + total_section_len:%d = %d is greater then file size:%d", - offset, cur_marker, - section_offset, total_section_len, - section_offset + total_section_len, m_in_data_size); - throw UnknownException("JPEG file is invalid"); - } - - if (JPEG_MARKER_APP1 == cur_marker) { - //TODO: verify this - //-4 --> 0xFF(1 byte)+Marker Number(1 byte)+Data size(2 bytes)) - //const unsigned int exif_data_size = section_length - 4; - - const unsigned int exif_data_size = total_section_len + 2; - section->exif_data = exif_data_new_from_data (section_begin, - exif_data_size); - - LOGD("offset:%d tag:0x%x | Loading exif from offset:%d" - " len:%d exif_data_new_from_data returned: %p", - offset, cur_marker, section_offset, exif_data_size, - section->exif_data); - - if (!section->exif_data) { - LOGW("offset:%d tag:0x%x | Couldn't load Exif!", offset, cur_marker); - } - } - - //This just saves pointer not copying data - section->data_ptr = section_begin + 2 + 2; //2 bytes marker + 2 bytes data size - section->size = section_data_len; //Exclude data size - - if (JPEG_MARKER_SOS == cur_marker) { - //Calculate offset of first image data which is just after this SOS section - const size_t image_data_offset = section_offset + 2 + total_section_len; - - //Calculate size of image data from start to expected EOI at end of file. - // - //-2 (exclude ending EOI marker (2 bytes) - size_t image_size = m_in_data_size - image_data_offset - 2; - LOGW("offset:%d tag:0x%x | Image data offset:%d Estimated image size:%d", - offset, cur_marker, image_data_offset, image_size); - - m_image_data = m_in_data + image_data_offset; - - size_t eoi_tag_index = 0; - bool found_eoi_tag = searchForTagInBuffer(m_in_data + image_data_offset, - m_in_data + m_in_data_size, JPEG_MARKER_EOI, eoi_tag_index); - if(!found_eoi_tag) { - LOGE("Could not find EOI tag! Assume that there is no EOI and rest of " - "JPEG file contains image data stream: image_size+= 2"); - image_size += 2; //Skip expected EOI tag which is not present - } else { - LOGD("EOI tag found at offset: %d from SOS data", eoi_tag_index); - - if(eoi_tag_index != image_size) { - LOGW("Estimated image size:%d doesn't match EOI tag index:%d" - " delta:%d", image_size, eoi_tag_index, - image_size - eoi_tag_index); - - LOGW("Setting image_size to EOI tag: %d", eoi_tag_index); - image_size = eoi_tag_index; - - m_padding_data = m_image_data + image_size + 2; //(skip EOI tag) - m_padding_data_size = (m_in_data + m_in_data_size) - m_padding_data; - LOGW("Saving padding data from offset:%d with size:%d", - m_padding_data - m_in_data, m_padding_data_size); - } - } - - m_image_size = image_size; - - offset = image_data_offset + image_size; - LOGD("offset:%d tag:0x%x | SOS Offset moved to next marker", offset, - cur_marker); - } - else { - offset += section_data_len; - LOGD("offset:%d tag:0x%x | Offset moved to next marker", offset, cur_marker); - } - } - } -} - -bool JpegFile::searchForTagInBuffer(const unsigned char* buffer_start, - const unsigned char* buffer_end, - const JpegMarker marker, - size_t& out_index) -{ - LOGD("Entered start:%p end:%p marker:0x%x", buffer_start, buffer_end, marker); - - if(!buffer_start) { - LOGE("buffer_start is NULL"); - return false; - } - - if(!buffer_end) { - LOGE("buffer_end is NULL"); - return false; - } - - if(buffer_end <= buffer_start) { - LOGE("buffer_end: %p <= buffer_start: %p", buffer_end, buffer_start); - return false; - } - - LOGD("Bytes to scan: %d", static_cast(buffer_end - buffer_start)); - const unsigned char marker_uchar = static_cast(marker); - - for(const unsigned char* ptr = buffer_start; ptr < buffer_end; ++ptr) { - - if((0xff == *ptr) && (ptr+1 < buffer_end)) { - if(marker_uchar == *(ptr+1)) { - out_index = static_cast(ptr - buffer_start); - return true; - } - } - } - - out_index = 0; - return false; -} - -void JpegFile::setNewExifData(ExifData* new_exif_data) -{ - if (!new_exif_data) { - LOGE("Trying to set NULL exif_data!"); - throw UnknownException("Could not save Exif in JPEG file"); - } - - JpegFileSectionPtr exif = getExifSection(); - if (!exif) { - LOGW("Could't find Exif section - creating new one"); - { - JpegFileSection* new_sec = new (std::nothrow) JpegFileSection(); - if (!new_sec) { - LOGE("Couldn't allocate JpegFileSection"); - throw UnknownException("Memory allocation failed"); - } - new_sec->type = JPEG_MARKER_APP1; - - exif = JpegFileSectionPtr(new_sec); - } - - SectionsVec::iterator insert_it = m_sections.begin(); - bool soi_is_present = false; - - if (insert_it != m_sections.end()) { - if ((*insert_it)->type != JPEG_MARKER_SOI) { - LOGW("First section is not SOI - Start Of Image!"); - } - else { - soi_is_present = true; - } - } - - if (!soi_is_present) { - LOGW("SOI section is missing"); - throw UnknownException("JPEG file is invalid"); - } - - //Insert new Exif sections just after SOI - ++insert_it; - if (insert_it != m_sections.begin()) { - m_sections.insert(insert_it, exif); - } - else { - //This shouldn't happen since we at lest need SOS and EOI sections - m_sections.push_back(exif); - } - } - - //We don't want to save old data - exif->data_ptr = NULL; - exif->size = 0; - - exif_data_unref(exif->exif_data); - exif_data_ref (new_exif_data); - exif->exif_data = new_exif_data; -} - -ExifData* JpegFile::getExifData() -{ - JpegFileSectionPtr exif = getExifSection(); - if (!exif) { - return NULL; - } - - exif_data_ref(exif->exif_data); - return exif->exif_data; -} - -void JpegFile::saveToFile(const std::string& out_path) -{ - LOGD("Entered out_path:%s", out_path.c_str()); - try { - saveToFilePriv(out_path); - } - catch (...) { - LOGE("Exception occured during saveToFilePriv " - "original file: [%] new: [%s]", - m_source_file_path.c_str(), - out_path.c_str()); - - if (out_path == m_source_file_path) { - - LOGD("Trying to recover broken JPEG file: [%s]", out_path.c_str()); - //We were writing to source file and since something went wrong let's - //restore old file - we have it in m_in_data - - FILE* outf = fopen(out_path.c_str(), "wb"); - if (!outf) { - LOGE("Couldn't open output file: [%s] - JPEG file will not be restored!"); - } - else { - size_t bytes_wrote = fwrite(m_in_data, 1, m_in_data_size, outf); - if (bytes_wrote != m_in_data_size) { - LOGE("Couldn't restore whole JPEG! " - "Only %d of %d bytes have been wrote!", - bytes_wrote, m_in_data_size); - } - if (EOF == fclose(outf)) { - LOGE("Couldn't close restore output file: [%s]", out_path.c_str()); - } - } - } - - throw; - } -} - -void JpegFile::saveToFilePriv(const std::string& out_path) -{ - LOGD("Entered out_path:%s", out_path.c_str()); - - m_out_file = fopen(out_path.c_str(), "wb"); - if (!m_out_file) { - LOGE("Couldn't open output file: %s", out_path.c_str()); - throw UnknownException("Could not write JPEG file"); - } - - unsigned char tmp_buf[128]; - size_t offset = 0; - - int section_index = 0; - for(SectionsVec::iterator it = m_sections.begin(); - it != m_sections.end(); - ++it, ++ section_index) { - - JpegFileSectionPtr cur = *it; - const JpegMarker cur_marker = cur->type; - - LOGD("offset:%d | Section: %d marker 0x%x", offset, section_index, cur_marker); - - size_t bytes_to_write = 0; - size_t bytes_wrote = 0; - - tmp_buf[0] = 0xff; - tmp_buf[1] = cur_marker; - bytes_to_write += 2; - - bool write_section_data = false; - - bool write_exif_data = false; - - std::unique_ptr exif_output_data; - unsigned int exif_output_size = 0; - - if (cur_marker != JPEG_MARKER_SOI && - cur_marker != JPEG_MARKER_EOI) { - - unsigned short section_size = 2; - if (JPEG_MARKER_APP1 && cur->exif_data) { - - unsigned char* tmp = NULL; - exif_data_save_data (cur->exif_data, &tmp, &exif_output_size); - if (!tmp || 0 == exif_output_size) { - LOGE("Couldn't generate RAW Exif data!"); - throw UnknownException("Could not save Exif in JPEG file"); - } - - LOGD("offset:%d | Generated Exif RAW Data length:%d", offset, - exif_output_size); - - exif_output_data.reset(tmp); - - if (exif_output_size > MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE) { - LOGE("exif_output_size:%d is greater then maximum JPEG section" - "data block size: %d", exif_output_size, - MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE); - throw UnknownException("Exif data is to big to be saved in JPEG file"); - } - section_size += exif_output_size; - write_exif_data = true; - } - else { - section_size += cur->size; - write_section_data = true; - } - - writeUShortBE(section_size, tmp_buf + bytes_to_write); - bytes_to_write += 2; - } - - LOGD("offset:%d | Writing section: marker:0x%x size:%d", offset, cur_marker, - cur->size); - - bytes_wrote = fwrite(tmp_buf, 1, bytes_to_write, m_out_file); - offset += bytes_wrote; - - if (bytes_wrote != bytes_to_write) { - LOGE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write, - bytes_wrote); - throw UnknownException("Could not write JPEG file"); - } - - if (write_section_data && cur->size > 0) { - LOGD("offset:%d | Writing data with length:%d", offset, cur->size); - - bytes_to_write = cur->size; - bytes_wrote = fwrite(cur->data_ptr, 1, bytes_to_write, m_out_file); - offset += bytes_wrote; - - if (bytes_wrote != bytes_to_write) { - LOGE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write, - bytes_wrote); - throw UnknownException("Could not write JPEG file"); - } - } - - if (write_exif_data && exif_output_data && exif_output_size > 0) { - LOGD("offset:%d | Writing new exif data with length:%d", offset, - exif_output_size); - - bytes_to_write = exif_output_size; - bytes_wrote = fwrite(exif_output_data.get(), 1, bytes_to_write, m_out_file); - offset += bytes_wrote; - - if (bytes_wrote != bytes_to_write) { - LOGE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write, - bytes_wrote); - throw UnknownException("Could not write JPEG file"); - } - } - - if (JPEG_MARKER_SOS == cur_marker) { - LOGD("offset:%d | Writing image data stream with lenght:%d", offset, - m_image_size); - - bytes_to_write = m_image_size; - bytes_wrote = fwrite(m_image_data, 1, bytes_to_write, m_out_file); - offset += bytes_wrote; - - if (bytes_wrote != bytes_to_write) { - LOGE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write, - bytes_wrote); - throw UnknownException("Could not write JPEG file"); - } - } - } - - if(m_padding_data && m_padding_data_size > 0) { - LOGD("Padding data exists and contains:%d bytes saving to JPEG file"); - const size_t bytes_wrote = fwrite(m_image_data, 1, m_padding_data_size, - m_out_file); - - if (bytes_wrote != m_padding_data_size) { - LOGE("Couldn't wrote %d bytes! Only %d bytes wrote", m_padding_data_size, - bytes_wrote); - throw UnknownException("Could not write JPEG file"); - } - } - - if (fclose(m_out_file) == EOF) { - LOGE("Couldn't close output file: %s", out_path.c_str()); - m_out_file = NULL; - } else { - m_out_file = NULL; - LOGD("Closed output file: %s wrote:%d bytes: %d", out_path.c_str(), offset); - } -} - -JpegFileSectionPtr JpegFile::getExifSection() -{ - size_t num_exif_sections = 0; - JpegFileSectionPtr first_exif_section; - - for(SectionsVec::iterator it = m_sections.begin(); it != m_sections.end(); ++it) { - JpegFileSectionPtr cur = *it; - - if (JPEG_MARKER_APP1 == cur->type) { - if (!cur->exif_data) { - LOGW("Warning: found APP1 section but exif_data is NULL (Not Exif?)"); - continue; - } - - ++num_exif_sections; - if (!first_exif_section) { - first_exif_section = cur; - } - else { - LOGW("Warning: found %d APP1/Exif sections - only first is currently supported!"); - } - } - } - - return first_exif_section; -} - - -} // namespace Exif -} // namespace DeviceAPI diff --git a/src/exif/old/JpegFile.h b/src/exif/old/JpegFile.h deleted file mode 100644 index bde69597..00000000 --- a/src/exif/old/JpegFile.h +++ /dev/null @@ -1,138 +0,0 @@ -// -// Tizen Web Device API -// Copyright (c) 2014 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 __TIZEN_EXIF_JPEG_FILE_H_ -#define __TIZEN_EXIF_JPEG_FILE_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace DeviceAPI { -namespace Exif { - -enum JpegMarker{ - JPEG_MARKER_UNKNOWN = 0x00, - JPEG_MARKER_LOWEST_ID = 0xc0, - JPEG_MARKER_SOI = 0xd8, //Start Of Image - JPEG_MARKER_EOI = 0xd9, //End Of Image - JPEG_MARKER_SOS = 0xda, //Start Of Stream - JPEG_MARKER_APP1 = 0xe1, //Application Data 1 - for Exif - JPEG_MARKER_HIGHEST_ID = 0xfe -}; - -struct JpegFileSection; -typedef std::shared_ptr JpegFileSectionPtr; - -struct JpegFileSection -{ - JpegFileSection() : - type(JPEG_MARKER_UNKNOWN), - data_ptr(NULL), - size(0), - exif_data(NULL) {}; - - JpegMarker type; - unsigned char* data_ptr; - unsigned short size; - - ExifData* exif_data; -}; - - -class JpegFile; -typedef std::shared_ptr JpegFilePtr; - -class JpegFile { -public: - static JpegFilePtr loadFile(const std::string& path); - ~JpegFile(); - - void setNewExifData(ExifData* new_exif_data); - - /** - * You are responsible to unreference returned data with: exif_data_unref(...) - * Example: - * ExifData* ed = jpeg.getExifData(); - * if(ed) { - * doSth(ed); - * exif_data_unref(ed); - * } - */ - ExifData* getExifData(); - - void saveToFile(const std::string& out_path); - -private: - JpegFile(); - void load(const std::string& path); - void generateListOfSections(); - - std::string getPartOfFile(const size_t offset, - const size_t num_bytes_before = 10, - const size_t num_bytes_after = 10); - - JpegFileSectionPtr getExifSection(); - void saveToFilePriv(const std::string& out_path); - - /** - * Search for first occurence of specific tag inside buffer. - * - * buffer_end is the first byte that should not be checked: - * [buffer_start ... buffer_end) - * - * For example EOI - search for first 'ffd9' in buffer - */ - static bool searchForTagInBuffer(const unsigned char* buffer_start, - const unsigned char* buffer_end, - const JpegMarker marker, - size_t& out_index); - - std::string m_source_file_path; - - unsigned char* m_in_data; - size_t m_in_data_size; - - unsigned char* m_image_data; - size_t m_image_size; - - /** - * This contains any bytes after EOI. - * Usually there should be no extra bytes after EOI unfortunately - * some cameras saves extra bytes (for example Android). - */ - unsigned char* m_padding_data; - size_t m_padding_data_size; - - FILE* m_in_file; - FILE* m_out_file; - - typedef std::vector SectionsVec; - SectionsVec m_sections; -}; - - -} // namespace Exif -} // namespace DeviceApi - -#endif // __TIZEN_EXIF_JPEG_FILE_H_ diff --git a/src/exif/old/Rational.cpp b/src/exif/old/Rational.cpp deleted file mode 100644 index 3b7c49fb..00000000 --- a/src/exif/old/Rational.cpp +++ /dev/null @@ -1,270 +0,0 @@ -// -// Tizen Web Device API -// Copyright (c) 2014 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 "Rational.h" - -#include - -namespace DeviceAPI { -namespace Exif { - -namespace { -const double DOUBLE_ERROR_REPRESENTATION = static_cast(0x7FFFFFFF); -} //anonymous namespace - -Rational::Rational() : - nominator(0), - denominator(0) -{ -} - -Rational::Rational(ExifLong nom, ExifLong denom) : - nominator(nom), - denominator(denom) -{ -} - -Rational::Rational(const ExifRational& exif_rational) : - nominator(exif_rational.numerator), - denominator(exif_rational.denominator) -{ -} - -Rational Rational::createFromDouble(const double value, const long precision) -{ - LOGD("Entered value:%f precision:%d", value, precision); - if (value < 0.0) { - LOGW("Trying to create negative Rational: %f!", value); - return Rational(); - } - - if (value < 0.000000001) { - LOGD("Skipping calculation returning: Rational(0,1)"); - return Rational(0,1); - } - - long m[2][2]; - double x, startx; - long ai; - - startx = x = value; - - // initialize matrix - m[0][0] = m[1][1] = 1; - m[0][1] = m[1][0] = 0; - - //loop finding terms until denom gets too big - do { - ai = static_cast(x); - if(m[1][0] * ai + m[1][1] > precision) { - break; - } - - long t = m[0][0] * ai + m[0][1]; - m[0][1] = m[0][0]; - m[0][0] = t; - - t = m[1][0] * ai + m[1][1]; - m[1][1] = m[1][0]; - m[1][0] = t; - - if (x == static_cast(ai)) { - break; // AF: division by zero - } - - x = 1 / (x - static_cast(ai)); - if (x > DOUBLE_ERROR_REPRESENTATION) { - break; // AF: representation failure - } - } while(1); - - // now remaining x is between 0 and 1/ai - // approx as either 0 or 1/m where m is max that will fit in precision - // first try zero - const double error0 = startx - ((double) m[0][0] / (double) m[1][0]); - const long numerator0 = m[0][0]; - const long denominator0 = m[1][0]; - - LOGD("%ld/%ld, error = %e\n", numerator0, denominator0, error0); - - /* now try other possibility */ - ai = (precision - m[1][1]) / m[1][0]; - m[0][0] = m[0][0] * ai + m[0][1]; - m[1][0] = m[1][0] * ai + m[1][1]; - - double error1m = startx - - (static_cast(m[0][0]) / static_cast(m[1][0])); - LOGD("%ld/%ld, error = %e\n", m[0][0], m[1][0], error1m ); - - long result_numerator = 0; - long result_denominator = 0; - - if (error0 < error1m ) { - result_numerator = numerator0; - result_denominator = denominator0; - } - else { - result_numerator = m[0][0]; - result_denominator = m[1][0]; - } - - if (result_numerator < 0) { - result_numerator *= -1; - } - if (result_denominator < 0) { - result_denominator *= -1; - } - - LOGD("Rational(%d, %d) error0 < error1m:%d", result_numerator, result_denominator, - error0 < error1m); - - return Rational(numerator0, denominator0); -} - -Rational Rational::createInvalid() -{ - return Rational(0,0); -} - -bool Rational::isValid() const -{ - if (0 == denominator) { - return false; - } - else { - return true; - } -} - -double Rational::toDouble() const -{ - if (!isValid()) { - return NAN; - } - - return (double)nominator / (double)denominator; -} - -Rational Rational::createFromExposureTimeString(const std::string& exp_time) -{ - LOGD("Entered"); - if (exp_time.length() == 0) { - return Rational::createInvalid(); //lets assume that empty string means 0, - //however exposure time = 0 is not valid value - } - - std::string integer_part; - std::string fraction_part; - - int first_space_at = -1; - int first_slash_at = -1; - - for(size_t i=0; i < exp_time.size(); ++i) { - - const char& cur = exp_time[i]; - if (first_space_at < 0 && ' ' == cur) { - first_space_at = i; - } - if (first_slash_at < 0 && '/' == cur) { - first_slash_at = i; - } - } - - if (first_slash_at > 0) { - if (first_space_at > 0) { - integer_part = exp_time.substr(0,first_space_at); - fraction_part = exp_time.substr(first_space_at+1, - exp_time.size() - (first_space_at+1)); - } - else { - fraction_part = exp_time; - } - } - else { - integer_part = exp_time; - } - - LOGD("first_space_at: %d first_slash_at:%d int: [%s] , frac: [%s]", - first_space_at, first_slash_at, integer_part.c_str(), fraction_part.c_str()); - - long integer_value = 0; - long nominator = 0; - long denominator = 1; - - if (integer_part.length() > 0) { - integer_value = atol(integer_part.c_str()); - } - - if (fraction_part.length() > 0) { - if (sscanf(fraction_part.c_str(), "%ld/%ld", &nominator, &denominator) != 2) { - LOGD("Failed to parse nominator/denominator string: [%s]", - fraction_part.c_str()); - return Rational::createInvalid(); - } - } - - nominator += denominator * integer_value; - LOGD("%d/%d -> %f", nominator, denominator, (float)nominator / denominator); - - if (0 == nominator) { - //Exposure time = 0 is invalid value - return Rational::createInvalid(); - } - - return Rational(nominator, denominator); -} - -std::string Rational::toString() const -{ - std::stringstream ss; - ss << nominator << "/" << denominator; - return ss.str(); -} - -std::string Rational::toExposureTimeString() const -{ - LOGD("Entered"); - if (!isValid() || 0 == nominator) { - return std::string(); - } - - std::string output_str; - - if (nominator < denominator) { - output_str = toString(); - } - else if (nominator % denominator == 0) { - std::stringstream ss; - ss << nominator / denominator; - output_str = ss.str(); - } - else { - ExifLong new_nominator = nominator % denominator; - ExifLong new_denominator = denominator; - ExifLong integer_value = nominator / denominator; - - std::stringstream ss; - ss << integer_value << " "; - ss << new_nominator << "/" << new_denominator; - output_str = ss.str(); - } - - return output_str; -} - -} // Exif -} // DeviceAPI \ No newline at end of file diff --git a/src/exif/old/Rational.h b/src/exif/old/Rational.h deleted file mode 100644 index 4903759b..00000000 --- a/src/exif/old/Rational.h +++ /dev/null @@ -1,97 +0,0 @@ -// -// Tizen Web Device API -// Copyright (c) 2014 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 __TIZEN_EXIF_RATIONAL_H_ -#define __TIZEN_EXIF_RATIONAL_H_ - -#include -#include -#include - -#include -#include -#include - -#include "ExifUtil.h" - -namespace DeviceAPI { -namespace Exif { - -class Rational; -typedef std::vector Rationals; -typedef std::shared_ptr RationalsPtr; - -/** - * This class represents fraction as nominator/denominator - two ExifLong values - * Rational type is present in Exif specification - used for example in GPS coordinates - */ -class Rational -{ -public: - /** - * Default constructor sets to 0/0 - invalud rational number - */ - Rational(); - - Rational(ExifLong nom, ExifLong denom); - Rational(const ExifRational& exif_rational); - - static Rational createFromDouble(const double value, const long precision = 1000); - static Rational createInvalid(); - - /** - * Returns true if denominator is valid (!= 0) and therefore whole Rational is valid - */ - bool isValid() const; - - double toDouble() const; - - /** - * Returns string in format: nominator/denominator, - * for example: "1/4", "1/1", "5/3". - * - */ - std::string toString() const; - - /** - * Create rational number from exposure string - * Accepted format "(integer) (nominator/denominator)" - * for example: - * "1/5", "4/5" - just fraction part - * "1", "5" - just integer part - * "1 1/5", "4 1/4" - integer + fraction part - */ - static Rational createFromExposureTimeString(const std::string& exp_time); - - /** - * Return time exposure string in following format: - * - * nominator < denominator : "1/5", "4/5" - * nominator == x*denominator : "1", "5" - * nominator > denominator && nominator != x*denominator : "1 1/5", "4 1/4" - */ - std::string toExposureTimeString() const; - - ExifLong nominator; - ExifLong denominator; -}; - -} // Exif -} // DeviceApi - -#endif // __TIZEN_EXIF_RATIONAL_H_ \ No newline at end of file