--- /dev/null
+//
+// 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 <sstream>
+#include <math.h>
+
+#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<ExifLong>(d_degrees), 1);
+ pos.minutes = Rational(static_cast<ExifLong>(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
--- /dev/null
+//
+// 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 <string>
+#include <vector>
+
+//#include <SimpleCoordinates.h>
+
+#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_
--- /dev/null
+//
+// 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 <memory>
+#include <math.h>
+
+#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<ExifInformationAttribute>(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<long long int>& 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<long long int>();
+ 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<const char*>(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<unsigned int>(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<const char*>(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<ImageOrientation>(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<int>(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<ExposureProgram>(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<char>(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<int>(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<char>(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<int>(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<ExifByte>(entry->data[0]);
+ if(static_cast<ExifByte>(GPS_ALTITUDE_REF_ABOVE_SEA) == altitude_ref ||
+ static_cast<ExifByte>(GPS_ALTITUDE_REF_BELOW_SEA) == altitude_ref) {
+ setGpsAltitudeRef(static_cast<GpsAltitudeRef>(altitude_ref));
+ LoggerD( "Setting ExifInformation gps altitude ref to: %d (%s)",
+ static_cast<int>(altitude_ref),
+ (altitude_ref > 0) ? "below sea" : "above sea");
+ } else {
+ LoggerW("GPS altitude ref is invalid:%d should be 0 or 1!",
+ static_cast<int>(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<ExifInfoAndDataHolder*>(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<void*>(&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<ExifTag>(EXIF_TAG_GPS_ALTITUDE), exif_data);
+ }
+ if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) {
+ LoggerD("Removing gps altitude ref");
+ ExifTagSaver::removeExifEntryWithTag(
+ static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF), exif_data);
+ }
+ if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) {
+ LoggerD("Removing gps processing method");
+ ExifTagSaver::removeExifEntryWithTag(
+ static_cast<ExifTag>(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<ExifTag>(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<ExifTag>(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<ExifTag>(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<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF), exif_data);
+ }
+/*
+ if (!m_exif_gps_time.isTimeSet()) {
+ LoggerD("Removing gps time");
+ ExifTagSaver::removeExifEntryWithTag(
+ static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP), exif_data);
+ }
+ if (!m_exif_gps_time.isDateSet()) {
+ LoggerD("Removing gps date");
+ ExifTagSaver::removeExifEntryWithTag(
+ static_cast<ExifTag>(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<int>(getOrientation()));
+ ExifTagSaver::saveToExif(static_cast<long int>(getOrientation()),
+ EXIF_TAG_ORIENTATION, exif_data);
+ }
+ if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) {
+ LoggerD("Saving exposure program: %d", static_cast<int>(getExposureProgram()));
+ ExifTagSaver::saveToExif(getExposureProgram(),
+ EXIF_TAG_EXPOSURE_PROGRAM, exif_data);
+ }
+ if (isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) {
+ //std::vector<long long int> 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<int>(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<int>(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<ExifTag>(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<int>(m_gps_altitude_ref),
+ (m_gps_altitude_ref > 0) ? "below sea" : "above sea");
+ ExifTagSaver::saveToExif(static_cast<long int>(m_gps_altitude_ref),
+ static_cast<ExifTag>(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<ExifTag>(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
--- /dev/null
+//
+// 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 <libexif/exif-loader.h>
+#include <string>
+
+//#include <JSVector.h>
+//#include <TimeDuration.h>
+
+#include "ExifGPSLocation.h"
+//#include "ExifGPSTime.h"
+
+namespace extension {
+namespace exif {
+
+class ExifInformation;
+typedef std::shared_ptr<ExifInformation> 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<long long int>& 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_
--- /dev/null
+//
+// 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 <libexif/exif-format.h>
+#include <sstream>
+#include <cstring>
+
+#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<unsigned char>(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<unsigned char*>(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<unsigned char*>(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<unsigned char*>(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<long long int>& 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<unsigned char*>(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<ExifByte>(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<ExifShort>(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<ExifSShort>(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<ExifLong>(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<ExifSLong>(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<ExifTag>(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<ExifTag>(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<ExifTag>(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<ExifTag>(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<ExifTag>(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<ExifTag>(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<unsigned int>(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<unsigned int>(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
--- /dev/null
+//
+// 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 <string>
+#include <libexif/exif-data.h>
+
+#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<long long int>& 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__
--- /dev/null
+//
+// 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 <iomanip>
+#include <sstream>
+
+#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
--- /dev/null
+//
+// 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 <libexif/exif-data.h>
+#include <libexif/exif-entry.h>
+#include <libexif/exif-utils.h>
+#include <string>
+#include <vector>
+
+//#include <Node.h>
+//#include <Path.h>
+//#include <TZDate.h>
+
+//#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_
--- /dev/null
+//
+// 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 <iomanip>
+#include <limits>
+#include <stdio.h>
+#include <sstream>
+
+#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<JpegMarker>(byte);
+}
+
+long readUShortBE(unsigned char* src)
+{
+ return ((static_cast<long>(src[0]) << 8) | static_cast<long>(src[1]));
+}
+
+void writeUShortBE(unsigned short value, unsigned char* buffer)
+{
+ buffer[0] = static_cast<unsigned char>(value >> 8);
+ buffer[1] = static_cast<unsigned char>(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<size_t>(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<long long int>(offset) - num_bytes_before;
+ if (start < 0) {
+ start = 0;
+ }
+
+ long long int end = static_cast<long long int>(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<int>(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<size_t>(buffer_end - buffer_start));
+ const unsigned char marker_uchar = static_cast<unsigned char>(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<size_t>(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<unsigned char, CArrayDeleter> 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
--- /dev/null
+//
+// 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 <memory>
+#include <string>
+#include <vector>
+#include <stdio.h>
+#include <map>
+#include <libexif/exif-data.h>
+#include <libexif/exif-entry.h>
+#include <libexif/exif-utils.h>
+
+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<JpegFileSection> 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<JpegFile> 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<JpegFileSectionPtr> SectionsVec;
+ SectionsVec m_sections;
+};
+
+
+} // namespace exif
+} // namespace extension
+
+#endif // __TIZEN_EXIF_JPEG_FILE_H_
--- /dev/null
+//
+// 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 <sstream>
+
+namespace extension {
+namespace exif {
+
+namespace {
+const double DOUBLE_ERROR_REPRESENTATION = static_cast<double>(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<long>(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<double>(ai)) {
+ break; // AF: division by zero
+ }
+
+ x = 1 / (x - static_cast<double>(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<double>(m[0][0]) / static_cast<double>(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
--- /dev/null
+//
+// 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 <string>
+#include <vector>
+#include <memory>
+
+#include <libexif/exif-utils.h>
+#include <libexif/exif-entry.h>
+#include <libexif/exif-data.h>
+
+#include "ExifUtil.h"
+
+namespace extension {
+namespace exif {
+
+class Rational;
+typedef std::vector<Rational> Rationals;
+typedef std::shared_ptr<Rationals> 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_
'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',
+ ]
+ },
}],
],
},
}
]);
- 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, [
{
-// 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 <string>
+#include <sstream>
-#include "common/logger.h"
+#include <libexif/exif-data.h>
+#include <libexif/exif-entry.h>
+#include <libexif/exif-utils.h>
+#include <libexif/exif-loader.h>
+
+#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";
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<std::string>();
+
+ const double callback_id = args.get("callbackId").get<double>();
+ auto get = [=](const std::shared_ptr<JsonValue>& 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<JsonObject>();
+ 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<picojson::object>());
+ } catch (const common::PlatformException& e) {
+ ReportError(e, response->get<picojson::object>());
+ }
+ };
+
+ auto get_response =
+ [callback_id, this](const std::shared_ptr<JsonValue>& response) -> void {
+ picojson::object& obj = response->get<picojson::object>();
+ 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<JsonValue>(
+ get, get_response,
+ std::shared_ptr<JsonValue>(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
+++ /dev/null
-//
-// 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 <sstream>
-
-#include <Logger.h>
-
-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<ExifLong>(d_degrees), 1);
- pos.minutes = Rational(static_cast<ExifLong>(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
+++ /dev/null
-//
-// 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 <string>
-
-#include <SimpleCoordinates.h>
-
-#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_
#include <Logger.h>
#include <PlatformException.h>
-namespace DeviceAPI {
-namespace Exif {
+namespace extension {
+namespace exif {
bool isValidDateFormat(const std::string& date)
{
m_time[2].toString().c_str());
}
-} // Exif
-} // DeviceAPI
+} // exif
+} // extension
#include "ExifUtil.h"
-namespace DeviceAPI {
-namespace Exif {
+namespace extension {
+namespace exif {
class ExifGPSTime
{
time_t m_time_and_date;
};
-} // Exif
-} // DeviceAPI
+} // exif
+} // extension
#endif // __TIZEN_EXIF_EXIF_GPS_TIME_H_
+++ /dev/null
-//
-// 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 <Logger.h>
-#include <memory>
-#include <PlatformException.h>
-
-#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<ExifInformationAttribute>(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<long long int>& 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<long long int>();
- 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<const char*>(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<unsigned int>(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<const char*>(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<ImageOrientation>(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<int>(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<ExposureProgram>(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<char>(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<int>(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<char>(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<int>(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<ExifByte>(entry->data[0]);
- if(static_cast<ExifByte>(GPS_ALTITUDE_REF_ABOVE_SEA) == altitude_ref ||
- static_cast<ExifByte>(GPS_ALTITUDE_REF_BELOW_SEA) == altitude_ref) {
- setGpsAltitudeRef(static_cast<GpsAltitudeRef>(altitude_ref));
- LOGD( "Setting ExifInformation gps altitude ref to: %d (%s)",
- static_cast<int>(altitude_ref),
- (altitude_ref > 0) ? "below sea" : "above sea");
- } else {
- LOGW("GPS altitude ref is invalid:%d should be 0 or 1!",
- static_cast<int>(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<ExifInfoAndDataHolder*>(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<void*>(&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<ExifTag>(EXIF_TAG_GPS_ALTITUDE), exif_data);
- }
- if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) {
- LOGD("Removing gps altitude ref");
- ExifTagSaver::removeExifEntryWithTag(
- static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF), exif_data);
- }
- if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) {
- LOGD("Removing gps processing method");
- ExifTagSaver::removeExifEntryWithTag(
- static_cast<ExifTag>(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<ExifTag>(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<ExifTag>(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<ExifTag>(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<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF), exif_data);
- }
-
- if (!m_exif_gps_time.isTimeSet()) {
- LOGD("Removing gps time");
- ExifTagSaver::removeExifEntryWithTag(
- static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP), exif_data);
- }
- if (!m_exif_gps_time.isDateSet()) {
- LOGD("Removing gps date");
- ExifTagSaver::removeExifEntryWithTag(
- static_cast<ExifTag>(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<int>(getOrientation()));
- ExifTagSaver::saveToExif(static_cast<long int>(getOrientation()),
- EXIF_TAG_ORIENTATION, exif_data);
- }
- if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) {
- LOGD("Saving exposure program: %d", static_cast<int>(getExposureProgram()));
- ExifTagSaver::saveToExif(getExposureProgram(),
- EXIF_TAG_EXPOSURE_PROGRAM, exif_data);
- }
- if (isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) {
- std::vector<long long int> 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<int>(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<int>(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<ExifTag>(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<int>(m_gps_altitude_ref),
- (m_gps_altitude_ref > 0) ? "below sea" : "above sea");
- ExifTagSaver::saveToExif(static_cast<long int>(m_gps_altitude_ref),
- static_cast<ExifTag>(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<ExifTag>(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
+++ /dev/null
-//
-// 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 <libexif/exif-loader.h>
-#include <string>
-
-#include <JSVector.h>
-#include <TimeDuration.h>
-
-#include "ExifGPSLocation.h"
-#include "ExifGPSTime.h"
-
-namespace DeviceAPI {
-namespace Exif {
-
-class ExifInformation;
-typedef std::shared_ptr<ExifInformation> 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<long long int>& 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_
+++ /dev/null
-//
-// 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 <libexif/exif-format.h>
-#include <sstream>
-
-#include <PlatformException.h>
-
-#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<unsigned char>(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<unsigned char*>(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<unsigned char*>(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<unsigned char*>(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<long long int>& 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<unsigned char*>(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<ExifByte>(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<ExifShort>(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<ExifSShort>(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<ExifLong>(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<ExifSLong>(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<ExifTag>(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<ExifTag>(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<ExifTag>(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<ExifTag>(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<ExifTag>(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<ExifTag>(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<unsigned int>(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<unsigned int>(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
+++ /dev/null
-//
-// 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 <string>
-#include <libexif/exif-data.h>
-
-#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<long long int>& 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__
+++ /dev/null
-//
-// 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 <iomanip>
-#include <sstream>
-
-#include <Logger.h>
-#include <PlatformException.h>
-
-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
+++ /dev/null
-//
-// 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 <libexif/exif-data.h>
-#include <libexif/exif-entry.h>
-#include <libexif/exif-utils.h>
-#include <string>
-#include <vector>
-
-#include <Node.h>
-#include <Path.h>
-#include <TZDate.h>
-
-#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_
+++ /dev/null
-//
-// 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 <iomanip>
-#include <limits>
-#include <stdio.h>
-#include <sstream>
-
-#include <Logger.h>
-#include <PlatformException.h>
-
-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<JpegMarker>(byte);
-}
-
-long readUShortBE(unsigned char* src)
-{
- return ((static_cast<long>(src[0]) << 8) | static_cast<long>(src[1]));
-}
-
-void writeUShortBE(unsigned short value, unsigned char* buffer)
-{
- buffer[0] = static_cast<unsigned char>(value >> 8);
- buffer[1] = static_cast<unsigned char>(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<size_t>(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<long long int>(offset) - num_bytes_before;
- if (start < 0) {
- start = 0;
- }
-
- long long int end = static_cast<long long int>(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<int>(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<size_t>(buffer_end - buffer_start));
- const unsigned char marker_uchar = static_cast<unsigned char>(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<size_t>(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<unsigned char, CArrayDeleter> 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
+++ /dev/null
-//
-// 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 <memory>
-#include <string>
-#include <vector>
-#include <stdio.h>
-#include <map>
-#include <libexif/exif-data.h>
-#include <libexif/exif-entry.h>
-#include <libexif/exif-utils.h>
-
-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<JpegFileSection> 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<JpegFile> 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<JpegFileSectionPtr> SectionsVec;
- SectionsVec m_sections;
-};
-
-
-} // namespace Exif
-} // namespace DeviceApi
-
-#endif // __TIZEN_EXIF_JPEG_FILE_H_
+++ /dev/null
-//
-// 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 <Logger.h>
-
-namespace DeviceAPI {
-namespace Exif {
-
-namespace {
-const double DOUBLE_ERROR_REPRESENTATION = static_cast<double>(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<long>(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<double>(ai)) {
- break; // AF: division by zero
- }
-
- x = 1 / (x - static_cast<double>(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<double>(m[0][0]) / static_cast<double>(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
+++ /dev/null
-//
-// 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 <string>
-#include <vector>
-#include <memory>
-
-#include <libexif/exif-utils.h>
-#include <libexif/exif-entry.h>
-#include <libexif/exif-data.h>
-
-#include "ExifUtil.h"
-
-namespace DeviceAPI {
-namespace Exif {
-
-class Rational;
-typedef std::vector<Rational> Rationals;
-typedef std::shared_ptr<Rationals> 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