|
Packit |
01d647 |
// ***************************************************************** -*- C++ -*-
|
|
Packit |
01d647 |
/*
|
|
Packit |
01d647 |
* Copyright (C) 2004-2018 Exiv2 authors
|
|
Packit |
01d647 |
* This program is part of the Exiv2 distribution.
|
|
Packit |
01d647 |
*
|
|
Packit |
01d647 |
* This program is free software; you can redistribute it and/or
|
|
Packit |
01d647 |
* modify it under the terms of the GNU General Public License
|
|
Packit |
01d647 |
* as published by the Free Software Foundation; either version 2
|
|
Packit |
01d647 |
* of the License, or (at your option) any later version.
|
|
Packit |
01d647 |
*
|
|
Packit |
01d647 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
01d647 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
01d647 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
01d647 |
* GNU General Public License for more details.
|
|
Packit |
01d647 |
*
|
|
Packit |
01d647 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
01d647 |
* along with this program; if not, write to the Free Software
|
|
Packit |
01d647 |
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
/*
|
|
Packit |
01d647 |
File: convert.cpp
|
|
Packit |
01d647 |
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
|
|
Packit |
01d647 |
Vladimir Nadvornik (vn) <nadvornik@suse.cz>
|
|
Packit |
01d647 |
History: 17-Mar-08, ahu: created basic converter framework
|
|
Packit |
01d647 |
20-May-08, vn: added actual conversion logic
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
// *****************************************************************************
|
|
Packit |
01d647 |
// included header files
|
|
Packit |
01d647 |
#include "config.h"
|
|
Packit |
01d647 |
#include "types.hpp"
|
|
Packit |
01d647 |
#include "error.hpp"
|
|
Packit |
01d647 |
#include "exif.hpp"
|
|
Packit |
01d647 |
#include "iptc.hpp"
|
|
Packit |
01d647 |
#include "xmp_exiv2.hpp"
|
|
Packit |
01d647 |
#include "futils.hpp"
|
|
Packit |
01d647 |
#include "convert.hpp"
|
|
Packit |
01d647 |
#include "unused.h"
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// + standard includes
|
|
Packit |
01d647 |
#include <utility>
|
|
Packit |
01d647 |
#include <iostream>
|
|
Packit |
01d647 |
#include <iomanip>
|
|
Packit |
01d647 |
#include <ios>
|
|
Packit |
01d647 |
#include <sstream>
|
|
Packit |
01d647 |
#include <stdio.h> // for snprintf (C99)
|
|
Packit |
01d647 |
#ifdef _MSC_VER
|
|
Packit |
01d647 |
# define snprintf _snprintf
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
#include <cstring>
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
#if defined WIN32 && !defined __CYGWIN__
|
|
Packit |
01d647 |
# include <windows.h>
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
#ifdef EXV_HAVE_ICONV
|
|
Packit |
01d647 |
# include <iconv.h>
|
|
Packit |
01d647 |
# include <errno.h>
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Adobe XMP Toolkit
|
|
Packit |
01d647 |
#ifdef EXV_HAVE_XMP_TOOLKIT
|
|
Packit |
01d647 |
# define TXMP_STRING_TYPE std::string
|
|
Packit |
01d647 |
# ifdef EXV_ADOBE_XMPSDK
|
|
Packit |
01d647 |
# include <XMP.hpp>
|
|
Packit |
01d647 |
# else
|
|
Packit |
01d647 |
# include <XMPSDK.hpp>
|
|
Packit |
01d647 |
# endif
|
|
Packit |
01d647 |
# include <MD5.h>
|
|
Packit |
01d647 |
#endif // EXV_HAVE_XMP_TOOLKIT
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// *****************************************************************************
|
|
Packit |
01d647 |
// local declarations
|
|
Packit |
01d647 |
namespace {
|
|
Packit |
01d647 |
#if defined WIN32 && !defined __CYGWIN__
|
|
Packit |
01d647 |
// Convert string charset with Windows functions.
|
|
Packit |
01d647 |
bool convertStringCharsetWindows(std::string& str, const char* from, const char* to);
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
#if defined EXV_HAVE_ICONV
|
|
Packit |
01d647 |
// Convert string charset with iconv.
|
|
Packit |
01d647 |
bool convertStringCharsetIconv(std::string& str, const char* from, const char* to);
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Get the text value of an XmpDatum \em pos.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
If \em pos refers to a LangAltValue, \em value is set to the default language
|
|
Packit |
01d647 |
entry without the x-default qualifier. If there is no default but
|
|
Packit |
01d647 |
exactly one entry, \em value is set to this entry, without the qualifier.
|
|
Packit |
01d647 |
The return code indicates if the operation was successful.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
bool getTextValue(std::string& value, const Exiv2::XmpData::iterator& pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// *****************************************************************************
|
|
Packit |
01d647 |
// class member definitions
|
|
Packit |
01d647 |
namespace Exiv2 {
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
//! Metadata conversions.
|
|
Packit |
01d647 |
class Converter {
|
|
Packit |
01d647 |
public:
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Type for metadata converter functions, taking two key strings,
|
|
Packit |
01d647 |
\em from and \em to.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
These functions have access to both the source and destination metadata
|
|
Packit |
01d647 |
containers and store the result directly in the destination container.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
typedef void (Converter::*ConvertFct)(const char* from, const char* to);
|
|
Packit |
01d647 |
//! Structure to define conversions between two keys.
|
|
Packit |
01d647 |
struct Conversion {
|
|
Packit |
01d647 |
MetadataId metadataId_; //!< Type of metadata for the first key.
|
|
Packit |
01d647 |
const char* key1_; //!< First metadata key.
|
|
Packit |
01d647 |
const char* key2_; //!< Second metadata key (always an XMP key for now).
|
|
Packit |
01d647 |
ConvertFct key1ToKey2_; //!< Conversion from first to second key.
|
|
Packit |
01d647 |
ConvertFct key2ToKey1_; //!< Conversion from second to first key.
|
|
Packit |
01d647 |
};
|
|
Packit |
01d647 |
public:
|
|
Packit |
01d647 |
//! @name Creators
|
|
Packit |
01d647 |
//@{
|
|
Packit |
01d647 |
//! Constructor for Exif tags and XMP properties.
|
|
Packit |
01d647 |
Converter(ExifData& exifData, XmpData& xmpData);
|
|
Packit |
01d647 |
//! Constructor for Iptc tags and XMP properties.
|
|
Packit |
01d647 |
Converter(IptcData& iptcData, XmpData& xmpData, const char *iptcCharset = 0);
|
|
Packit |
01d647 |
//@}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
//! @name Manipulators
|
|
Packit |
01d647 |
//@{
|
|
Packit |
01d647 |
//! Convert Exif tags or IPTC datasets to XMP properties according to the conversion table.
|
|
Packit |
01d647 |
void cnvToXmp();
|
|
Packit |
01d647 |
//! Convert XMP properties to Exif tags or IPTC datasets according to the conversion table.
|
|
Packit |
01d647 |
void cnvFromXmp();
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Set the erase flag.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
This flag indicates whether successfully converted source records are erased.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void setErase(bool onoff =true) { erase_ = onoff; }
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Set the overwrite flag.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
This flag indicates whether existing target records are overwritten.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void setOverwrite(bool onoff =true) { overwrite_ = onoff; }
|
|
Packit |
01d647 |
//@}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
//! @name Conversion functions (manipulators)
|
|
Packit |
01d647 |
//@{
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Do nothing conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Use when, for example, a one-way conversion is needed.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvNone(const char*, const char*);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Simple Exif to XMP conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Sets the XMP property to an XmpText value containing the Exif value string.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvExifValue(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Convert the tag Exif.Photo.UserComment to XMP.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Todo: Convert the Exif comment to UTF-8 if necessary.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvExifComment(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Converts Exif tag with multiple components to XMP array.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converts Exif tag with multiple components to XMP array. This function is
|
|
Packit |
01d647 |
used for ComponentsConfiguration tag.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvExifArray(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Exif date to XMP conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Sets the XMP property to an XmpText value containing date and time. This function
|
|
Packit |
01d647 |
combines values from multiple Exif tags as described in XMP specification. It
|
|
Packit |
01d647 |
is used for DateTime, DateTimeOriginal, DateTimeDigitized and GPSTimeStamp.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvExifDate(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Exif version to XMP conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converts ExifVersion tag to XmpText value.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvExifVersion(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Exif GPS version to XMP conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converts GPSVersionID tag to XmpText value.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvExifGPSVersion(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Exif Flash to XMP conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converts Flash tag to XMP structure.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvExifFlash(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Exif GPS coordinate to XMP conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converts GPS coordinates tag to XmpText value. It combines multiple Exif tags
|
|
Packit |
01d647 |
as described in XMP specification.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvExifGPSCoord(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Simple XMP to Exif conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Sets the Exif tag according to the XMP property.
|
|
Packit |
01d647 |
For LangAlt values, only the x-default entry is used.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Todo: Escape non-ASCII characters in XMP text values
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvXmpValue(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Convert the tag Xmp.exif.UserComment to Exif.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvXmpComment(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Converts XMP array to Exif tag with multiple components.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converts XMP array to Exif tag with multiple components. This function is
|
|
Packit |
01d647 |
used for ComponentsConfiguration tag.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvXmpArray(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief XMP to Exif date conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converts the XmpText value to Exif date and time. This function
|
|
Packit |
01d647 |
sets multiple Exif tags as described in XMP specification. It
|
|
Packit |
01d647 |
is used for DateTime, DateTimeOriginal, DateTimeDigitized and GPSTimeStamp.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvXmpDate(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief XMP to Exif version conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converts XmpText value to ExifVersion tag.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvXmpVersion(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief XMP to Exif GPS version conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converts XmpText value to GPSVersionID tag.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvXmpGPSVersion(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief XMP to Exif Flash conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converts XMP structure to Flash tag.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvXmpFlash(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief XMP to Exif GPS coordinate conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converts XmpText value to GPS coordinates tags. It sets multiple Exif tags
|
|
Packit |
01d647 |
as described in XMP specification.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvXmpGPSCoord(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief IPTC dataset to XMP conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Multiple IPTC datasets with the same key are converted to an XMP array.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvIptcValue(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief XMP to IPTC dataset conversion function.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Each array element of an XMP array value is added as one IPTC dataset.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void cnvXmpValueToIptc(const char* from, const char* to);
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Write exif:NativeDigest and tiff:NativeDigest properties to XMP.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Compute digests from Exif values and write them to exif:NativeDigest
|
|
Packit |
01d647 |
and tiff:NativeDigest properties. This should be compatible with XMP SDK.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void writeExifDigest();
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Copies metadata in appropriate direction.
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
From values of exif:NativeDigest and tiff:NativeDigest detects which of
|
|
Packit |
01d647 |
XMP and Exif was updated more recently and copies metadata in appropriate direction.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void syncExifWithXmp();
|
|
Packit |
01d647 |
//@}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
//! @name Accessors
|
|
Packit |
01d647 |
//@{
|
|
Packit |
01d647 |
//! Get the value of the erase flag, see also setErase(bool on).
|
|
Packit |
01d647 |
bool erase() const { return erase_; }
|
|
Packit |
01d647 |
//! Get the value of the overwrite flag, see also setOverwrite(bool on).
|
|
Packit |
01d647 |
bool overwrite() const { return overwrite_; }
|
|
Packit |
01d647 |
//@}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
private:
|
|
Packit |
01d647 |
bool prepareExifTarget(const char* to, bool force =false);
|
|
Packit |
01d647 |
bool prepareIptcTarget(const char* to, bool force =false);
|
|
Packit |
01d647 |
bool prepareXmpTarget(const char* to, bool force =false);
|
|
Packit |
01d647 |
std::string computeExifDigest(bool tiff);
|
|
Packit |
01d647 |
std::string computeIptcDigest();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// DATA
|
|
Packit |
01d647 |
static const Conversion conversion_[]; //
|
|
Packit |
01d647 |
bool erase_;
|
|
Packit |
01d647 |
bool overwrite_;
|
|
Packit |
01d647 |
ExifData *exifData_;
|
|
Packit |
01d647 |
IptcData *iptcData_;
|
|
Packit |
01d647 |
XmpData *xmpData_;
|
|
Packit |
01d647 |
const char *iptcCharset_;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
}; // class Converter
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Order is important for computing digests
|
|
Packit |
01d647 |
const Converter::Conversion Converter::conversion_[] = {
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.ImageWidth", "Xmp.tiff.ImageWidth", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.ImageLength", "Xmp.tiff.ImageLength", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.BitsPerSample", "Xmp.tiff.BitsPerSample", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.Compression", "Xmp.tiff.Compression", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.PhotometricInterpretation", "Xmp.tiff.PhotometricInterpretation", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.Orientation", "Xmp.tiff.Orientation", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.SamplesPerPixel", "Xmp.tiff.SamplesPerPixel", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.PlanarConfiguration", "Xmp.tiff.PlanarConfiguration", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.YCbCrSubSampling", "Xmp.tiff.YCbCrSubSampling", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.YCbCrPositioning", "Xmp.tiff.YCbCrPositioning", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.XResolution", "Xmp.tiff.XResolution", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.YResolution", "Xmp.tiff.YResolution", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.ResolutionUnit", "Xmp.tiff.ResolutionUnit", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.TransferFunction", "Xmp.tiff.TransferFunction", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.WhitePoint", "Xmp.tiff.WhitePoint", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.PrimaryChromaticities", "Xmp.tiff.PrimaryChromaticities", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.YCbCrCoefficients", "Xmp.tiff.YCbCrCoefficients", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.ReferenceBlackWhite", "Xmp.tiff.ReferenceBlackWhite", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.DateTime", "Xmp.xmp.ModifyDate", &Converter::cnvExifDate , &Converter::cnvXmpDate }, // MWG Guidelines
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.ImageDescription", "Xmp.dc.description", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.Make", "Xmp.tiff.Make", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.Model", "Xmp.tiff.Model", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.Software", "Xmp.tiff.Software", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.Artist", "Xmp.dc.creator", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.Rating", "Xmp.xmp.Rating", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Image.Copyright", "Xmp.dc.rights", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.ExifVersion", "Xmp.exif.ExifVersion", &Converter::cnvExifVersion, &Converter::cnvXmpVersion },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.FlashpixVersion", "Xmp.exif.FlashpixVersion", &Converter::cnvExifVersion, &Converter::cnvXmpVersion },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.ColorSpace", "Xmp.exif.ColorSpace", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.ComponentsConfiguration", "Xmp.exif.ComponentsConfiguration", &Converter::cnvExifArray, &Converter::cnvXmpArray },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.CompressedBitsPerPixel", "Xmp.exif.CompressedBitsPerPixel", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.PixelXDimension", "Xmp.exif.PixelXDimension", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.PixelYDimension", "Xmp.exif.PixelYDimension", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.UserComment", "Xmp.exif.UserComment", &Converter::cnvExifComment, &Converter::cnvXmpComment },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.RelatedSoundFile", "Xmp.exif.RelatedSoundFile", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.DateTimeOriginal", "Xmp.photoshop.DateCreated", &Converter::cnvExifDate, &Converter::cnvXmpDate }, // MWG Guidelines
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.DateTimeDigitized", "Xmp.xmp.CreateDate", &Converter::cnvExifDate, &Converter::cnvXmpDate }, // MWG Guidelines
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.ExposureTime", "Xmp.exif.ExposureTime", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.FNumber", "Xmp.exif.FNumber", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.ExposureProgram", "Xmp.exif.ExposureProgram", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.SpectralSensitivity", "Xmp.exif.SpectralSensitivity", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.ISOSpeedRatings", "Xmp.exif.ISOSpeedRatings", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.OECF", "Xmp.exif.OECF", &Converter::cnvExifValue, &Converter::cnvXmpValue }, // FIXME ?
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.ShutterSpeedValue", "Xmp.exif.ShutterSpeedValue", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.ApertureValue", "Xmp.exif.ApertureValue", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.BrightnessValue", "Xmp.exif.BrightnessValue", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.ExposureBiasValue", "Xmp.exif.ExposureBiasValue", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.MaxApertureValue", "Xmp.exif.MaxApertureValue", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.SubjectDistance", "Xmp.exif.SubjectDistance", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.MeteringMode", "Xmp.exif.MeteringMode", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.LightSource", "Xmp.exif.LightSource", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.Flash", "Xmp.exif.Flash", &Converter::cnvExifFlash, &Converter::cnvXmpFlash },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.FocalLength", "Xmp.exif.FocalLength", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.SubjectArea", "Xmp.exif.SubjectArea", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.FlashEnergy", "Xmp.exif.FlashEnergy", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.SpatialFrequencyResponse", "Xmp.exif.SpatialFrequencyResponse", &Converter::cnvExifValue, &Converter::cnvXmpValue }, // FIXME ?
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.FocalPlaneXResolution", "Xmp.exif.FocalPlaneXResolution", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.FocalPlaneYResolution", "Xmp.exif.FocalPlaneYResolution", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.FocalPlaneResolutionUnit", "Xmp.exif.FocalPlaneResolutionUnit", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.SubjectLocation", "Xmp.exif.SubjectLocation", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.ExposureIndex", "Xmp.exif.ExposureIndex", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.SensingMethod", "Xmp.exif.SensingMethod", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.FileSource", "Xmp.exif.FileSource", &Converter::cnvExifValue, &Converter::cnvXmpValue }, // FIXME ?
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.SceneType", "Xmp.exif.SceneType", &Converter::cnvExifValue, &Converter::cnvXmpValue }, // FIXME ?
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.CFAPattern", "Xmp.exif.CFAPattern", &Converter::cnvExifValue, &Converter::cnvXmpValue }, // FIXME ?
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.CustomRendered", "Xmp.exif.CustomRendered", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.ExposureMode", "Xmp.exif.ExposureMode", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.WhiteBalance", "Xmp.exif.WhiteBalance", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.DigitalZoomRatio", "Xmp.exif.DigitalZoomRatio", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.FocalLengthIn35mmFilm", "Xmp.exif.FocalLengthIn35mmFilm", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.SceneCaptureType", "Xmp.exif.SceneCaptureType", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.GainControl", "Xmp.exif.GainControl", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.Contrast", "Xmp.exif.Contrast", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.Saturation", "Xmp.exif.Saturation", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.Sharpness", "Xmp.exif.Sharpness", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.DeviceSettingDescription", "Xmp.exif.DeviceSettingDescription", &Converter::cnvExifValue, &Converter::cnvXmpValue }, // FIXME ?
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.SubjectDistanceRange", "Xmp.exif.SubjectDistanceRange", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.Photo.ImageUniqueID", "Xmp.exif.ImageUniqueID", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSVersionID", "Xmp.exif.GPSVersionID", &Converter::cnvExifGPSVersion, &Converter::cnvXmpGPSVersion },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSLatitude", "Xmp.exif.GPSLatitude", &Converter::cnvExifGPSCoord, &Converter::cnvXmpGPSCoord },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSLongitude", "Xmp.exif.GPSLongitude", &Converter::cnvExifGPSCoord, &Converter::cnvXmpGPSCoord },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSAltitudeRef", "Xmp.exif.GPSAltitudeRef", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSAltitude", "Xmp.exif.GPSAltitude", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSTimeStamp", "Xmp.exif.GPSTimeStamp", &Converter::cnvExifDate, &Converter::cnvXmpDate }, // FIXME ?
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSSatellites", "Xmp.exif.GPSSatellites", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSStatus", "Xmp.exif.GPSStatus", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSMeasureMode", "Xmp.exif.GPSMeasureMode", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSDOP", "Xmp.exif.GPSDOP", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSSpeedRef", "Xmp.exif.GPSSpeedRef", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSSpeed", "Xmp.exif.GPSSpeed", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSTrackRef", "Xmp.exif.GPSTrackRef", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSTrack", "Xmp.exif.GPSTrack", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSImgDirectionRef", "Xmp.exif.GPSImgDirectionRef", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSImgDirection", "Xmp.exif.GPSImgDirection", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSMapDatum", "Xmp.exif.GPSMapDatum", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSDestLatitude", "Xmp.exif.GPSDestLatitude", &Converter::cnvExifGPSCoord, &Converter::cnvXmpGPSCoord },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSDestLongitude", "Xmp.exif.GPSDestLongitude", &Converter::cnvExifGPSCoord, &Converter::cnvXmpGPSCoord },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSDestBearingRef", "Xmp.exif.GPSDestBearingRef", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSDestBearing", "Xmp.exif.GPSDestBearing", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSDestDistanceRef", "Xmp.exif.GPSDestDistanceRef", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSDestDistance", "Xmp.exif.GPSDestDistance", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSProcessingMethod", "Xmp.exif.GPSProcessingMethod", &Converter::cnvExifValue, &Converter::cnvXmpValue }, // FIXME ?
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSAreaInformation", "Xmp.exif.GPSAreaInformation", &Converter::cnvExifValue, &Converter::cnvXmpValue }, // FIXME ?
|
|
Packit |
01d647 |
{ mdExif, "Exif.GPSInfo.GPSDifferential", "Xmp.exif.GPSDifferential", &Converter::cnvExifValue, &Converter::cnvXmpValue },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.ObjectName", "Xmp.dc.title", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.Urgency", "Xmp.photoshop.Urgency", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.Category", "Xmp.photoshop.Category", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.SuppCategory", "Xmp.photoshop.SupplementalCategories", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.Keywords", "Xmp.dc.subject", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.SubLocation", "Xmp.iptc.Location", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.SpecialInstructions","Xmp.photoshop.Instructions", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.DateCreated", "Xmp.photoshop.DateCreated", &Converter::cnvNone, &Converter::cnvXmpValueToIptc }, // FIXME to IPTC Date and IPTC Time
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.DigitizationDate", "Xmp.xmp.CreateDate", &Converter::cnvNone, &Converter::cnvXmpValueToIptc }, // FIXME to IPTC Date and IPTC Time
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.Byline", "Xmp.dc.creator", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.BylineTitle", "Xmp.photoshop.AuthorsPosition", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.City", "Xmp.photoshop.City", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.ProvinceState", "Xmp.photoshop.State", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.CountryCode", "Xmp.iptc.CountryCode", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.CountryName", "Xmp.photoshop.Country", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.TransmissionReference", "Xmp.photoshop.TransmissionReference", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.Headline", "Xmp.photoshop.Headline", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.Credit", "Xmp.photoshop.Credit", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.Source", "Xmp.photoshop.Source", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.Copyright", "Xmp.dc.rights", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.Caption", "Xmp.dc.description", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc },
|
|
Packit |
01d647 |
{ mdIptc, "Iptc.Application2.Writer", "Xmp.photoshop.CaptionWriter", &Converter::cnvIptcValue, &Converter::cnvXmpValueToIptc }
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converter::Converter(ExifData& exifData, XmpData& xmpData)
|
|
Packit |
01d647 |
: erase_(false), overwrite_(true), exifData_(&exifData), iptcData_(0), xmpData_(&xmpData), iptcCharset_(0)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converter::Converter(IptcData& iptcData, XmpData& xmpData, const char *iptcCharset)
|
|
Packit |
01d647 |
: erase_(false), overwrite_(true), exifData_(0), iptcData_(&iptcData), xmpData_(&xmpData), iptcCharset_(iptcCharset)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvToXmp()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
for (unsigned int i = 0; i < EXV_COUNTOF(conversion_); ++i) {
|
|
Packit |
01d647 |
const Conversion& c = conversion_[i];
|
|
Packit |
01d647 |
if ( (c.metadataId_ == mdExif && exifData_)
|
|
Packit |
01d647 |
|| (c.metadataId_ == mdIptc && iptcData_)) {
|
|
Packit |
01d647 |
EXV_CALL_MEMBER_FN(*this, c.key1ToKey2_)(c.key1_, c.key2_);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvFromXmp()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
for (unsigned int i = 0; i < EXV_COUNTOF(conversion_); ++i) {
|
|
Packit |
01d647 |
const Conversion& c = conversion_[i];
|
|
Packit |
01d647 |
if ( (c.metadataId_ == mdExif && exifData_)
|
|
Packit |
01d647 |
|| (c.metadataId_ == mdIptc && iptcData_)) {
|
|
Packit |
01d647 |
EXV_CALL_MEMBER_FN(*this, c.key2ToKey1_)(c.key2_, c.key1_);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvNone(const char*, const char*)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool Converter::prepareExifTarget(const char* to, bool force)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(to));
|
|
Packit |
01d647 |
if (pos == exifData_->end()) return true;
|
|
Packit |
01d647 |
if (!overwrite_ && !force) return false;
|
|
Packit |
01d647 |
exifData_->erase(pos);
|
|
Packit |
01d647 |
return true;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool Converter::prepareIptcTarget(const char* to, bool force)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::IptcData::iterator pos = iptcData_->findKey(IptcKey(to));
|
|
Packit |
01d647 |
if (pos == iptcData_->end()) return true;
|
|
Packit |
01d647 |
if (!overwrite_ && !force) return false;
|
|
Packit |
01d647 |
while ((pos = iptcData_->findKey(IptcKey(to))) != iptcData_->end()) {
|
|
Packit |
01d647 |
iptcData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return true;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool Converter::prepareXmpTarget(const char* to, bool force)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(to));
|
|
Packit |
01d647 |
if (pos == xmpData_->end()) return true;
|
|
Packit |
01d647 |
if (!overwrite_ && !force) return false;
|
|
Packit |
01d647 |
xmpData_->erase(pos);
|
|
Packit |
01d647 |
return true;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvExifValue(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from));
|
|
Packit |
01d647 |
if (pos == exifData_->end()) return;
|
|
Packit |
01d647 |
std::string value = pos->toString();
|
|
Packit |
01d647 |
if (!pos->value().ok()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (!prepareXmpTarget(to)) return;
|
|
Packit |
01d647 |
(*xmpData_)[to] = value;
|
|
Packit |
01d647 |
if (erase_) exifData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvExifComment(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from));
|
|
Packit |
01d647 |
if (pos == exifData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareXmpTarget(to)) return;
|
|
Packit |
01d647 |
const CommentValue* cv = dynamic_cast<const CommentValue*>(&pos->value());
|
|
Packit |
01d647 |
if (cv == 0) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
// Todo: Convert to UTF-8 if necessary
|
|
Packit |
01d647 |
(*xmpData_)[to] = cv->comment();
|
|
Packit |
01d647 |
if (erase_) exifData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvExifArray(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from));
|
|
Packit |
01d647 |
if (pos == exifData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareXmpTarget(to)) return;
|
|
Packit |
01d647 |
for (int i = 0; i < pos->count(); ++i) {
|
|
Packit |
01d647 |
std::string value = pos->toString(i);
|
|
Packit |
01d647 |
if (!pos->value().ok()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
(*xmpData_)[to] = value;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (erase_) exifData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvExifDate(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from));
|
|
Packit |
01d647 |
if (pos == exifData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareXmpTarget(to)) return;
|
|
Packit |
01d647 |
int year, month, day, hour, min, sec;
|
|
Packit |
01d647 |
std::string subsec;
|
|
Packit |
01d647 |
char buf[30];
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (std::string(from) != "Exif.GPSInfo.GPSTimeStamp") {
|
|
Packit |
01d647 |
std::string value = pos->toString();
|
|
Packit |
01d647 |
if (!pos->value().ok()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (sscanf(value.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec) != 6) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to
|
|
Packit |
01d647 |
<< ", unable to parse '" << value << "'\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else { // "Exif.GPSInfo.GPSTimeStamp"
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool ok = true;
|
|
Packit |
01d647 |
if (pos->count() != 3) ok = false;
|
|
Packit |
01d647 |
if (ok) {
|
|
Packit |
01d647 |
for (int i = 0; i < 3; ++i) {
|
|
Packit |
01d647 |
if (pos->toRational(i).second == 0) {
|
|
Packit |
01d647 |
ok = false;
|
|
Packit |
01d647 |
break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (!ok) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
double dhour = pos->toFloat(0);
|
|
Packit |
01d647 |
double dmin = pos->toFloat(1);
|
|
Packit |
01d647 |
// Hack: Need Value::toDouble
|
|
Packit |
01d647 |
Rational r = pos->toRational(2);
|
|
Packit |
01d647 |
double dsec = static_cast<double>(r.first)/r.second;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (!pos->value().ok()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
dsec = dhour * 3600.0 + dmin * 60.0 + dsec;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
hour = static_cast<int>(dsec / 3600.0);
|
|
Packit |
01d647 |
dsec -= hour * 3600;
|
|
Packit |
01d647 |
min = static_cast<int>(dsec / 60.0);
|
|
Packit |
01d647 |
dsec -= min * 60;
|
|
Packit |
01d647 |
sec = static_cast<int>(dsec);
|
|
Packit |
01d647 |
dsec -= sec;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
snprintf(buf, sizeof(buf), "%.9f", dsec);
|
|
Packit |
01d647 |
buf[sizeof(buf) - 1] = 0;
|
|
Packit |
01d647 |
buf[1] = '.'; // some locales use ','
|
|
Packit |
01d647 |
subsec = buf + 1;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Exiv2::ExifData::iterator datePos = exifData_->findKey(ExifKey("Exif.GPSInfo.GPSDateStamp"));
|
|
Packit |
01d647 |
if (datePos == exifData_->end()) {
|
|
Packit |
01d647 |
datePos = exifData_->findKey(ExifKey("Exif.Photo.DateTimeOriginal"));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (datePos == exifData_->end()) {
|
|
Packit |
01d647 |
datePos = exifData_->findKey(ExifKey("Exif.Photo.DateTimeDigitized"));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (datePos == exifData_->end()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
std::string value = datePos->toString();
|
|
Packit |
01d647 |
if (sscanf(value.c_str(), "%d:%d:%d", &year, &month, &day) != 3) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to
|
|
Packit |
01d647 |
<< ", unable to parse '" << value << "'\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
const char* subsecTag = 0;
|
|
Packit |
01d647 |
if (std::string(from) == "Exif.Image.DateTime") {
|
|
Packit |
01d647 |
subsecTag = "Exif.Photo.SubSecTime";
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else if (std::string(from) == "Exif.Photo.DateTimeOriginal") {
|
|
Packit |
01d647 |
subsecTag = "Exif.Photo.SubSecTimeOriginal";
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else if (std::string(from) == "Exif.Photo.DateTimeDigitized") {
|
|
Packit |
01d647 |
subsecTag = "Exif.Photo.SubSecTimeDigitized";
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (subsecTag) {
|
|
Packit |
01d647 |
ExifData::iterator subsec_pos = exifData_->findKey(ExifKey(subsecTag));
|
|
Packit |
01d647 |
if ( subsec_pos != exifData_->end()
|
|
Packit |
01d647 |
&& subsec_pos->typeId() == asciiString) {
|
|
Packit |
01d647 |
std::string ss = subsec_pos->toString();
|
|
Packit |
01d647 |
if (!ss.empty()) {
|
|
Packit |
01d647 |
bool ok = false;
|
|
Packit |
01d647 |
stringTo<long>(ss, ok);
|
|
Packit |
01d647 |
if (ok) subsec = std::string(".") + ss;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (erase_) exifData_->erase(subsec_pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (subsec.size() > 10) subsec = subsec.substr(0, 10);
|
|
Packit |
01d647 |
snprintf(buf, sizeof(buf), "%4d-%02d-%02dT%02d:%02d:%02d%s",
|
|
Packit |
01d647 |
year, month, day, hour, min, sec, subsec.c_str());
|
|
Packit |
01d647 |
buf[sizeof(buf) - 1] = 0;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
(*xmpData_)[to] = buf;
|
|
Packit |
01d647 |
if (erase_) exifData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvExifVersion(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from));
|
|
Packit |
01d647 |
if (pos == exifData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareXmpTarget(to)) return;
|
|
Packit |
01d647 |
std::ostringstream value;
|
|
Packit |
01d647 |
for (int i = 0; i < pos->count(); ++i) {
|
|
Packit |
01d647 |
value << static_cast<char>(pos->toLong(i));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
(*xmpData_)[to] = value.str();
|
|
Packit |
01d647 |
if (erase_) exifData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvExifGPSVersion(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from));
|
|
Packit |
01d647 |
if (pos == exifData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareXmpTarget(to)) return;
|
|
Packit |
01d647 |
std::ostringstream value;
|
|
Packit |
01d647 |
for (int i = 0; i < pos->count(); ++i) {
|
|
Packit |
01d647 |
if (i > 0) value << '.';
|
|
Packit |
01d647 |
value << pos->toLong(i);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
(*xmpData_)[to] = value.str();
|
|
Packit |
01d647 |
if (erase_) exifData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvExifFlash(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from));
|
|
Packit |
01d647 |
if (pos == exifData_->end() || pos->count() == 0) return;
|
|
Packit |
01d647 |
if (!prepareXmpTarget(to)) return;
|
|
Packit |
01d647 |
int value = pos->toLong();
|
|
Packit |
01d647 |
if (!pos->value().ok()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
(*xmpData_)["Xmp.exif.Flash/exif:Fired"] = static_cast<bool>(value & 1);
|
|
Packit |
01d647 |
(*xmpData_)["Xmp.exif.Flash/exif:Return"] = (value >> 1) & 3;
|
|
Packit |
01d647 |
(*xmpData_)["Xmp.exif.Flash/exif:Mode"] = (value >> 3) & 3;
|
|
Packit |
01d647 |
(*xmpData_)["Xmp.exif.Flash/exif:Function"] = static_cast<bool>((value >> 5) & 1);
|
|
Packit |
01d647 |
(*xmpData_)["Xmp.exif.Flash/exif:RedEyeMode"] = static_cast<bool>((value >> 6) & 1);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (erase_) exifData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvExifGPSCoord(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from));
|
|
Packit |
01d647 |
if (pos == exifData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareXmpTarget(to)) return;
|
|
Packit |
01d647 |
if (pos->count() != 3) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
Exiv2::ExifData::iterator refPos = exifData_->findKey(ExifKey(std::string(from) + "Ref"));
|
|
Packit |
01d647 |
if (refPos == exifData_->end()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
double deg[3];
|
|
Packit |
01d647 |
for (int i = 0; i < 3; ++i) {
|
|
Packit |
01d647 |
const int32_t z = pos->toRational(i).first;
|
|
Packit |
01d647 |
const int32_t d = pos->toRational(i).second;
|
|
Packit |
01d647 |
if (d == 0) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
// Hack: Need Value::toDouble
|
|
Packit |
01d647 |
deg[i] = static_cast<double>(z)/d;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
double min = deg[0] * 60.0 + deg[1] + deg[2] / 60.0;
|
|
Packit |
01d647 |
int ideg = static_cast<int>(min / 60.0);
|
|
Packit |
01d647 |
min -= ideg * 60;
|
|
Packit |
01d647 |
std::ostringstream oss;
|
|
Packit |
01d647 |
oss << ideg << ","
|
|
Packit |
01d647 |
<< std::fixed << std::setprecision(7) << min
|
|
Packit |
01d647 |
<< refPos->toString().c_str()[0];
|
|
Packit |
01d647 |
(*xmpData_)[to] = oss.str();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (erase_) exifData_->erase(pos);
|
|
Packit |
01d647 |
if (erase_) exifData_->erase(refPos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvXmpValue(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from));
|
|
Packit |
01d647 |
if (pos == xmpData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareExifTarget(to)) return;
|
|
Packit |
01d647 |
std::string value;
|
|
Packit |
01d647 |
if (!getTextValue(value, pos)) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
// Todo: Escape non-ASCII characters in XMP text values
|
|
Packit |
01d647 |
ExifKey key(to);
|
|
Packit |
01d647 |
Exifdatum ed(key);
|
|
Packit |
01d647 |
if (0 == ed.setValue(value)) {
|
|
Packit |
01d647 |
exifData_->add(ed);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (erase_) xmpData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvXmpComment(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (!prepareExifTarget(to)) return;
|
|
Packit |
01d647 |
Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from));
|
|
Packit |
01d647 |
if (pos == xmpData_->end()) return;
|
|
Packit |
01d647 |
std::string value;
|
|
Packit |
01d647 |
if (!getTextValue(value, pos)) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
// Assumes the XMP value is encoded in UTF-8, as it should be
|
|
Packit |
01d647 |
(*exifData_)[to] = "charset=Unicode " + value;
|
|
Packit |
01d647 |
if (erase_) xmpData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvXmpArray(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (!prepareExifTarget(to)) return;
|
|
Packit |
01d647 |
Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from));
|
|
Packit |
01d647 |
if (pos == xmpData_->end()) return;
|
|
Packit |
01d647 |
std::ostringstream array;
|
|
Packit |
01d647 |
for (int i = 0; i < pos->count(); ++i) {
|
|
Packit |
01d647 |
std::string value = pos->toString(i);
|
|
Packit |
01d647 |
if (!pos->value().ok()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
array << value;
|
|
Packit |
01d647 |
if (i != pos->count() - 1) array << " ";
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
(*exifData_)[to] = array.str();
|
|
Packit |
01d647 |
if (erase_) xmpData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvXmpDate(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from));
|
|
Packit |
01d647 |
if (pos == xmpData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareExifTarget(to)) return;
|
|
Packit |
01d647 |
#ifdef EXV_HAVE_XMP_TOOLKIT
|
|
Packit |
01d647 |
std::string value = pos->toString();
|
|
Packit |
01d647 |
if (!pos->value().ok()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
XMP_DateTime datetime;
|
|
Packit |
01d647 |
try {
|
|
Packit |
01d647 |
SXMPUtils::ConvertToDate(value, &datetime);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
catch (const XMP_Error& e) {
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << " (" << e.GetErrMsg() << ")\n";
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
#else
|
|
Packit |
01d647 |
catch (const XMP_Error&) {
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
#endif // SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
char buf[30];
|
|
Packit |
01d647 |
if (std::string(to) != "Exif.GPSInfo.GPSTimeStamp") {
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
SXMPUtils::ConvertToLocalTime(&datetime);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
snprintf(buf, sizeof(buf), "%4d:%02d:%02d %02d:%02d:%02d",
|
|
Packit |
01d647 |
static_cast<int>(datetime.year),
|
|
Packit |
01d647 |
static_cast<int>(datetime.month),
|
|
Packit |
01d647 |
static_cast<int>(datetime.day),
|
|
Packit |
01d647 |
static_cast<int>(datetime.hour),
|
|
Packit |
01d647 |
static_cast<int>(datetime.minute),
|
|
Packit |
01d647 |
static_cast<int>(datetime.second));
|
|
Packit |
01d647 |
buf[sizeof(buf) - 1] = 0;
|
|
Packit |
01d647 |
(*exifData_)[to] = buf;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (datetime.nanoSecond) {
|
|
Packit |
01d647 |
const char* subsecTag = 0;
|
|
Packit |
01d647 |
if (std::string(to) == "Exif.Image.DateTime") {
|
|
Packit |
01d647 |
subsecTag = "Exif.Photo.SubSecTime";
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else if (std::string(to) == "Exif.Photo.DateTimeOriginal") {
|
|
Packit |
01d647 |
subsecTag = "Exif.Photo.SubSecTimeOriginal";
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else if (std::string(to) == "Exif.Photo.DateTimeDigitized") {
|
|
Packit |
01d647 |
subsecTag = "Exif.Photo.SubSecTimeDigitized";
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (subsecTag) {
|
|
Packit |
01d647 |
prepareExifTarget(subsecTag, true);
|
|
Packit |
01d647 |
(*exifData_)[subsecTag] = toString(datetime.nanoSecond);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else { // "Exif.GPSInfo.GPSTimeStamp"
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Ignore the time zone, assuming the time is in UTC as it should be
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
URational rhour(datetime.hour, 1);
|
|
Packit |
01d647 |
URational rmin(datetime.minute, 1);
|
|
Packit |
01d647 |
URational rsec(datetime.second, 1);
|
|
Packit |
01d647 |
if (datetime.nanoSecond != 0) {
|
|
Packit |
01d647 |
if (datetime.second != 0) {
|
|
Packit |
01d647 |
// Add the seconds to rmin so that the ns fit into rsec
|
|
Packit |
01d647 |
rmin.second = 60;
|
|
Packit |
01d647 |
rmin.first *= 60;
|
|
Packit |
01d647 |
rmin.first += datetime.second;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
rsec.second = 1000000000;
|
|
Packit |
01d647 |
rsec.first = datetime.nanoSecond;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
std::ostringstream array;
|
|
Packit |
01d647 |
array << rhour << " " << rmin << " " << rsec;
|
|
Packit |
01d647 |
(*exifData_)[to] = array.str();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
prepareExifTarget("Exif.GPSInfo.GPSDateStamp", true);
|
|
Packit |
01d647 |
snprintf(buf, sizeof(buf), "%4d:%02d:%02d",
|
|
Packit |
01d647 |
static_cast<int>(datetime.year),
|
|
Packit |
01d647 |
static_cast<int>(datetime.month),
|
|
Packit |
01d647 |
static_cast<int>(datetime.day));
|
|
Packit |
01d647 |
buf[sizeof(buf) - 1] = 0;
|
|
Packit |
01d647 |
(*exifData_)["Exif.GPSInfo.GPSDateStamp"] = buf;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (erase_) xmpData_->erase(pos);
|
|
Packit |
01d647 |
#else
|
|
Packit |
01d647 |
# ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
# endif
|
|
Packit |
01d647 |
#endif // !EXV_HAVE_XMP_TOOLKIT
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvXmpVersion(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from));
|
|
Packit |
01d647 |
if (pos == xmpData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareExifTarget(to)) return;
|
|
Packit |
01d647 |
std::string value = pos->toString();
|
|
Packit |
01d647 |
if (!pos->value().ok() || value.length() < 4) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
std::ostringstream array;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
array << static_cast<int>(value[0]) << " "
|
|
Packit |
01d647 |
<< static_cast<int>(value[1]) << " "
|
|
Packit |
01d647 |
<< static_cast<int>(value[2]) << " "
|
|
Packit |
01d647 |
<< static_cast<int>(value[3]);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
(*exifData_)[to] = array.str();
|
|
Packit |
01d647 |
if (erase_) xmpData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvXmpGPSVersion(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from));
|
|
Packit |
01d647 |
if (pos == xmpData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareExifTarget(to)) return;
|
|
Packit |
01d647 |
std::string value = pos->toString();
|
|
Packit |
01d647 |
if (!pos->value().ok()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
for (unsigned i = 0; i < value.length(); ++i) {
|
|
Packit |
01d647 |
if (value[i] == '.') value[i] = ' ';
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
(*exifData_)[to] = value;
|
|
Packit |
01d647 |
if (erase_) xmpData_->erase(pos);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvXmpFlash(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Fired"));
|
|
Packit |
01d647 |
if (pos == xmpData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareExifTarget(to)) return;
|
|
Packit |
01d647 |
unsigned short value = 0;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (pos != xmpData_->end() && pos->count() > 0) {
|
|
Packit |
01d647 |
int fired = pos->toLong();
|
|
Packit |
01d647 |
if (pos->value().ok())
|
|
Packit |
01d647 |
value |= fired & 1;
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
else
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << std::string(from) + "/exif:Fired" << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Return"));
|
|
Packit |
01d647 |
if (pos != xmpData_->end() && pos->count() > 0) {
|
|
Packit |
01d647 |
int ret = pos->toLong();
|
|
Packit |
01d647 |
if (pos->value().ok())
|
|
Packit |
01d647 |
value |= (ret & 3) << 1;
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
else
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << std::string(from) + "/exif:Return" << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Mode"));
|
|
Packit |
01d647 |
if (pos != xmpData_->end() && pos->count() > 0) {
|
|
Packit |
01d647 |
int mode = pos->toLong();
|
|
Packit |
01d647 |
if (pos->value().ok())
|
|
Packit |
01d647 |
value |= (mode & 3) << 3;
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
else
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << std::string(from) + "/exif:Mode" << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Function"));
|
|
Packit |
01d647 |
if (pos != xmpData_->end() && pos->count() > 0) {
|
|
Packit |
01d647 |
int function = pos->toLong();
|
|
Packit |
01d647 |
if (pos->value().ok())
|
|
Packit |
01d647 |
value |= (function & 1) << 5;
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
else
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << std::string(from) + "/exif:Function" << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:RedEyeMode"));
|
|
Packit |
01d647 |
if (pos != xmpData_->end() && pos->count() > 0) {
|
|
Packit |
01d647 |
int red = pos->toLong();
|
|
Packit |
01d647 |
if (pos->value().ok())
|
|
Packit |
01d647 |
value |= (red & 1) << 6;
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
else
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << std::string(from) + "/exif:RedEyeMode" << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
(*exifData_)[to] = value;
|
|
Packit |
01d647 |
if (erase_) xmpData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvXmpGPSCoord(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from));
|
|
Packit |
01d647 |
if (pos == xmpData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareExifTarget(to)) return;
|
|
Packit |
01d647 |
std::string value = pos->toString();
|
|
Packit |
01d647 |
if (!pos->value().ok()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (value.empty()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << from << " is empty\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
double deg = 0.0;
|
|
Packit |
01d647 |
double min = 0.0;
|
|
Packit |
01d647 |
double sec = 0.0;
|
|
Packit |
01d647 |
char ref = value[value.length() - 1];
|
|
Packit |
01d647 |
char sep1 = '\0';
|
|
Packit |
01d647 |
char sep2 = '\0';
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
value.erase(value.length() - 1);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
std::istringstream in(value);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
in >> deg >> sep1 >> min >> sep2;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (sep2 == ',') {
|
|
Packit |
01d647 |
in >> sec;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
sec = (min - static_cast<int>(min)) * 60.0;
|
|
Packit |
01d647 |
min = static_cast<double>(static_cast<int>(min));
|
|
Packit |
01d647 |
sep2 = ',';
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if ( in.bad() || !(ref == 'N' || ref == 'S' || ref == 'E' || ref == 'W')
|
|
Packit |
01d647 |
|| sep1 != ',' || sep2 != ',' || !in.eof()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Rational rdeg = floatToRationalCast(static_cast<float>(deg));
|
|
Packit |
01d647 |
Rational rmin = floatToRationalCast(static_cast<float>(min));
|
|
Packit |
01d647 |
Rational rsec = floatToRationalCast(static_cast<float>(sec));
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
std::ostringstream array;
|
|
Packit |
01d647 |
array << rdeg << " " << rmin << " " << rsec;
|
|
Packit |
01d647 |
(*exifData_)[to] = array.str();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
prepareExifTarget((std::string(to) + "Ref").c_str(), true);
|
|
Packit |
01d647 |
char ref_str[2] = {ref, 0};
|
|
Packit |
01d647 |
(*exifData_)[std::string(to) + "Ref"] = ref_str;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (erase_) xmpData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvIptcValue(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::IptcData::iterator pos = iptcData_->findKey(IptcKey(from));
|
|
Packit |
01d647 |
if (pos == iptcData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareXmpTarget(to)) return;
|
|
Packit |
01d647 |
while (pos != iptcData_->end()) {
|
|
Packit |
01d647 |
if (pos->key() == from) {
|
|
Packit |
01d647 |
std::string value = pos->toString();
|
|
Packit |
01d647 |
if (!pos->value().ok()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
++pos;
|
|
Packit |
01d647 |
continue;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (iptcCharset_) convertStringCharset(value, iptcCharset_, "UTF-8");
|
|
Packit |
01d647 |
(*xmpData_)[to] = value;
|
|
Packit |
01d647 |
if (erase_) {
|
|
Packit |
01d647 |
pos = iptcData_->erase(pos);
|
|
Packit |
01d647 |
continue;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
++pos;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::cnvXmpValueToIptc(const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
XmpData::iterator pos = xmpData_->findKey(XmpKey(from));
|
|
Packit |
01d647 |
if (pos == xmpData_->end()) return;
|
|
Packit |
01d647 |
if (!prepareIptcTarget(to)) return;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (pos->typeId() == langAlt || pos->typeId() == xmpText) {
|
|
Packit |
01d647 |
std::string value;
|
|
Packit |
01d647 |
if (!getTextValue(value, pos)) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
(*iptcData_)[to] = value;
|
|
Packit |
01d647 |
(*iptcData_)["Iptc.Envelope.CharacterSet"] = "\033%G"; // indicate UTF-8 encoding
|
|
Packit |
01d647 |
if (erase_) xmpData_->erase(pos);
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
int count = pos->count();
|
|
Packit |
01d647 |
bool added = false;
|
|
Packit |
01d647 |
for (int i = 0; i < count; ++i) {
|
|
Packit |
01d647 |
std::string value = pos->toString(i);
|
|
Packit |
01d647 |
if (!pos->value().ok()) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
continue;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
IptcKey key(to);
|
|
Packit |
01d647 |
Iptcdatum id(key);
|
|
Packit |
01d647 |
id.setValue(value);
|
|
Packit |
01d647 |
iptcData_->add(id);
|
|
Packit |
01d647 |
added = true;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (added) (*iptcData_)["Iptc.Envelope.CharacterSet"] = "\033%G"; // indicate UTF-8 encoding
|
|
Packit |
01d647 |
if (erase_) xmpData_->erase(pos);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
#ifdef EXV_HAVE_XMP_TOOLKIT
|
|
Packit |
01d647 |
std::string Converter::computeExifDigest(bool tiff)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
std::ostringstream res;
|
|
Packit |
01d647 |
MD5_CTX context;
|
|
Packit |
01d647 |
unsigned char digest[16];
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
MD5Init ( &context );
|
|
Packit |
01d647 |
for (unsigned int i = 0; i < EXV_COUNTOF(conversion_); ++i) {
|
|
Packit |
01d647 |
const Conversion& c = conversion_[i];
|
|
Packit |
01d647 |
if (c.metadataId_ == mdExif) {
|
|
Packit |
01d647 |
Exiv2::ExifKey key(c.key1_);
|
|
Packit |
01d647 |
if (tiff && key.groupName() != "Image") continue;
|
|
Packit |
01d647 |
if (!tiff && key.groupName() == "Image") continue;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (!res.str().empty()) res << ',';
|
|
Packit |
01d647 |
res << key.tag();
|
|
Packit |
01d647 |
Exiv2::ExifData::iterator pos = exifData_->findKey(key);
|
|
Packit |
01d647 |
if (pos == exifData_->end()) continue;
|
|
Packit |
01d647 |
DataBuf data(pos->size());
|
|
Packit |
01d647 |
pos->copy(data.pData_, littleEndian /* FIXME ? */);
|
|
Packit |
01d647 |
MD5Update ( &context, data.pData_, data.size_);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
MD5Final(digest, &context);
|
|
Packit |
01d647 |
res << ';';
|
|
Packit |
01d647 |
res << std::setw(2) << std::setfill('0') << std::hex << std::uppercase;
|
|
Packit |
01d647 |
for (int i = 0; i < 16; ++i) {
|
|
Packit |
01d647 |
res << static_cast<int>(digest[i]);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return res.str();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
#else
|
|
Packit |
01d647 |
std::string Converter::computeExifDigest(bool)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return std::string("");
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::writeExifDigest()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
#ifdef EXV_HAVE_XMP_TOOLKIT
|
|
Packit |
01d647 |
(*xmpData_)["Xmp.tiff.NativeDigest"] = computeExifDigest(true);
|
|
Packit |
01d647 |
(*xmpData_)["Xmp.exif.NativeDigest"] = computeExifDigest(false);
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void Converter::syncExifWithXmp()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Exiv2::XmpData::iterator td = xmpData_->findKey(XmpKey("Xmp.tiff.NativeDigest"));
|
|
Packit |
01d647 |
Exiv2::XmpData::iterator ed = xmpData_->findKey(XmpKey("Xmp.exif.NativeDigest"));
|
|
Packit |
01d647 |
if (td != xmpData_->end() && ed != xmpData_->end()) {
|
|
Packit |
01d647 |
if (td->value().toString() == computeExifDigest(true) &&
|
|
Packit |
01d647 |
ed->value().toString() == computeExifDigest(false)) {
|
|
Packit |
01d647 |
// We have both digests and the values match
|
|
Packit |
01d647 |
// XMP is up-to-date, we should update Exif
|
|
Packit |
01d647 |
setOverwrite(true);
|
|
Packit |
01d647 |
setErase(false);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
cnvFromXmp();
|
|
Packit |
01d647 |
writeExifDigest();
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
// We have both digests and the values do not match
|
|
Packit |
01d647 |
// Exif was modified after XMP, we should update XMP
|
|
Packit |
01d647 |
setOverwrite(true);
|
|
Packit |
01d647 |
setErase(false);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
cnvToXmp();
|
|
Packit |
01d647 |
writeExifDigest();
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
// We don't have both digests, it is probably the first conversion to XMP
|
|
Packit |
01d647 |
setOverwrite(false); // to be safe
|
|
Packit |
01d647 |
setErase(false);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
cnvToXmp();
|
|
Packit |
01d647 |
writeExifDigest();
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
std::string Converter::computeIptcDigest()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
#ifdef EXV_HAVE_XMP_TOOLKIT
|
|
Packit |
01d647 |
std::ostringstream res;
|
|
Packit |
01d647 |
MD5_CTX context;
|
|
Packit |
01d647 |
unsigned char digest[16];
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
MD5Init(&context);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
DataBuf data = IptcParser::encode(*iptcData_);
|
|
Packit |
01d647 |
MD5Update(&context, data.pData_, data.size_);
|
|
Packit |
01d647 |
MD5Final(digest, &context);
|
|
Packit |
01d647 |
res << std::setw(2) << std::setfill('0') << std::hex << std::uppercase;
|
|
Packit |
01d647 |
for (int i = 0; i < 16; ++i) {
|
|
Packit |
01d647 |
res << static_cast<int>(digest[i]);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return res.str();
|
|
Packit |
01d647 |
#else
|
|
Packit |
01d647 |
return std::string("");
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// *************************************************************************
|
|
Packit |
01d647 |
// free functions
|
|
Packit |
01d647 |
void copyExifToXmp(const ExifData& exifData, XmpData& xmpData)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Converter converter(const_cast<ExifData&>(exifData), xmpData);
|
|
Packit |
01d647 |
converter.cnvToXmp();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void moveExifToXmp(ExifData& exifData, XmpData& xmpData)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Converter converter(exifData, xmpData);
|
|
Packit |
01d647 |
converter.setErase();
|
|
Packit |
01d647 |
converter.cnvToXmp();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void copyXmpToExif(const XmpData& xmpData, ExifData& exifData)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Converter converter(exifData, const_cast<XmpData&>(xmpData));
|
|
Packit |
01d647 |
converter.cnvFromXmp();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void moveXmpToExif(XmpData& xmpData, ExifData& exifData)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Converter converter(exifData, xmpData);
|
|
Packit |
01d647 |
converter.setErase();
|
|
Packit |
01d647 |
converter.cnvFromXmp();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void syncExifWithXmp(ExifData& exifData, XmpData& xmpData)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Converter converter(exifData, xmpData);
|
|
Packit |
01d647 |
converter.syncExifWithXmp();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void copyIptcToXmp(const IptcData& iptcData, XmpData& xmpData, const char *iptcCharset)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (!iptcCharset) iptcCharset = iptcData.detectCharset();
|
|
Packit |
01d647 |
if (!iptcCharset) iptcCharset = "ISO-8859-1";
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Converter converter(const_cast<IptcData&>(iptcData), xmpData, iptcCharset);
|
|
Packit |
01d647 |
converter.cnvToXmp();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void moveIptcToXmp(IptcData& iptcData, XmpData& xmpData, const char *iptcCharset)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (!iptcCharset) iptcCharset = iptcData.detectCharset();
|
|
Packit |
01d647 |
if (!iptcCharset) iptcCharset = "ISO-8859-1";
|
|
Packit |
01d647 |
Converter converter(iptcData, xmpData, iptcCharset);
|
|
Packit |
01d647 |
converter.setErase();
|
|
Packit |
01d647 |
converter.cnvToXmp();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void copyXmpToIptc(const XmpData& xmpData, IptcData& iptcData)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Converter converter(iptcData, const_cast<XmpData&>(xmpData));
|
|
Packit |
01d647 |
converter.cnvFromXmp();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void moveXmpToIptc(XmpData& xmpData, IptcData& iptcData)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Converter converter(iptcData, xmpData);
|
|
Packit |
01d647 |
converter.setErase();
|
|
Packit |
01d647 |
converter.cnvFromXmp();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool convertStringCharset(std::string &str, const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (0 == strcmp(from, to)) return true; // nothing to do
|
|
Packit |
01d647 |
bool ret = false;
|
|
Packit |
01d647 |
#if defined EXV_HAVE_ICONV
|
|
Packit |
01d647 |
ret = convertStringCharsetIconv(str, from, to);
|
|
Packit |
01d647 |
#elif defined WIN32 && !defined __CYGWIN__
|
|
Packit |
01d647 |
ret = convertStringCharsetWindows(str, from, to);
|
|
Packit |
01d647 |
#else
|
|
Packit |
01d647 |
# ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "Charset conversion required but no character mapping functionality available.\n";
|
|
Packit |
01d647 |
# endif
|
|
Packit |
01d647 |
UNUSED(str);
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return ret;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // namespace Exiv2
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// *****************************************************************************
|
|
Packit |
01d647 |
// local definitions
|
|
Packit |
01d647 |
namespace {
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
using namespace Exiv2;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
#if defined WIN32 && !defined __CYGWIN__
|
|
Packit |
01d647 |
bool swapBytes(std::string& str)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
// Naive byte-swapping, I'm sure this can be done more efficiently
|
|
Packit |
01d647 |
if (str.size() & 1) {
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
EXV_DEBUG << "swapBytes: Size " << str.size() << " of input string is not even.\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return false;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
for (unsigned int i = 0; i < str.size() / 2; ++i) {
|
|
Packit |
01d647 |
char t = str[2 * i];
|
|
Packit |
01d647 |
str[2 * i] = str[2 * i + 1];
|
|
Packit |
01d647 |
str[2 * i + 1] = t;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return true;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool mb2wc(UINT cp, std::string& str)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (str.empty()) return true;
|
|
Packit |
01d647 |
int len = MultiByteToWideChar(cp, 0, str.c_str(), (int)str.size(), 0, 0);
|
|
Packit |
01d647 |
if (len == 0) {
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
EXV_DEBUG << "mb2wc: Failed to determine required size of output buffer.\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return false;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
std::vector<std::string::value_type> out;
|
|
Packit |
01d647 |
out.resize(len * 2);
|
|
Packit |
01d647 |
int ret = MultiByteToWideChar(cp, 0, str.c_str(), (int)str.size(), (LPWSTR)&out[0], len * 2);
|
|
Packit |
01d647 |
if (ret == 0) {
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
EXV_DEBUG << "mb2wc: Failed to convert the input string to a wide character string.\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return false;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
str.assign(out.begin(), out.end());
|
|
Packit |
01d647 |
return true;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool wc2mb(UINT cp, std::string& str)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (str.empty()) return true;
|
|
Packit |
01d647 |
if (str.size() & 1) {
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
EXV_DEBUG << "wc2mb: Size " << str.size() << " of input string is not even.\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return false;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
int len = WideCharToMultiByte(cp, 0, (LPCWSTR)str.data(), (int)str.size() / 2, 0, 0, 0, 0);
|
|
Packit |
01d647 |
if (len == 0) {
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
EXV_DEBUG << "wc2mb: Failed to determine required size of output buffer.\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return false;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
std::vector<std::string::value_type> out;
|
|
Packit |
01d647 |
out.resize(len);
|
|
Packit |
01d647 |
int ret = WideCharToMultiByte(cp, 0, (LPCWSTR)str.data(), (int)str.size() / 2, (LPSTR)&out[0], len, 0, 0);
|
|
Packit |
01d647 |
if (ret == 0) {
|
|
Packit |
01d647 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit |
01d647 |
EXV_DEBUG << "wc2mb: Failed to convert the input string to a multi byte string.\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return false;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
str.assign(out.begin(), out.end());
|
|
Packit |
01d647 |
return true;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool utf8ToUcs2be(std::string& str)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
bool ret = mb2wc(CP_UTF8, str);
|
|
Packit |
01d647 |
if (ret) ret = swapBytes(str);
|
|
Packit |
01d647 |
return ret;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool utf8ToUcs2le(std::string& str)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return mb2wc(CP_UTF8, str);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool ucs2beToUtf8(std::string& str)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
bool ret = swapBytes(str);
|
|
Packit |
01d647 |
if (ret) ret = wc2mb(CP_UTF8, str);
|
|
Packit |
01d647 |
return ret;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool ucs2beToUcs2le(std::string& str)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return swapBytes(str);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool ucs2leToUtf8(std::string& str)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return wc2mb(CP_UTF8, str);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool ucs2leToUcs2be(std::string& str)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return swapBytes(str);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool iso88591ToUtf8(std::string& str)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
bool ret = mb2wc(28591, str);
|
|
Packit |
01d647 |
if (ret) ret = wc2mb(CP_UTF8, str);
|
|
Packit |
01d647 |
return ret;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool asciiToUtf8(std::string& /*str*/)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
// nothing to do
|
|
Packit |
01d647 |
return true;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
typedef bool (*ConvFct)(std::string& str);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
struct ConvFctList {
|
|
Packit |
01d647 |
bool operator==(const std::pair<const char*, const char*> &fromTo) const
|
|
Packit |
01d647 |
{ return 0 == strcmp(from_, fromTo.first) && 0 == strcmp(to_, fromTo.second); }
|
|
Packit |
01d647 |
const char* from_;
|
|
Packit |
01d647 |
const char* to_;
|
|
Packit |
01d647 |
ConvFct convFct_;
|
|
Packit |
01d647 |
};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
const ConvFctList convFctList[] = {
|
|
Packit |
01d647 |
{ "UTF-8", "UCS-2BE", utf8ToUcs2be },
|
|
Packit |
01d647 |
{ "UTF-8", "UCS-2LE", utf8ToUcs2le },
|
|
Packit |
01d647 |
{ "UCS-2BE", "UTF-8", ucs2beToUtf8 },
|
|
Packit |
01d647 |
{ "UCS-2BE", "UCS-2LE", ucs2beToUcs2le },
|
|
Packit |
01d647 |
{ "UCS-2LE", "UTF-8", ucs2leToUtf8 },
|
|
Packit |
01d647 |
{ "UCS-2LE", "UCS-2BE", ucs2leToUcs2be },
|
|
Packit |
01d647 |
{ "ISO-8859-1", "UTF-8", iso88591ToUtf8 },
|
|
Packit |
01d647 |
{ "ASCII", "UTF-8", asciiToUtf8 }
|
|
Packit |
01d647 |
// Update the convertStringCharset() documentation if you add more here!
|
|
Packit |
01d647 |
};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool convertStringCharsetWindows(std::string& str, const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
bool ret = false;
|
|
Packit |
01d647 |
const ConvFctList* p = find(convFctList, std::make_pair(from, to));
|
|
Packit |
01d647 |
std::string tmpstr = str;
|
|
Packit |
01d647 |
if (p) ret = p->convFct_(tmpstr);
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
EXV_WARNING << "No Windows function to map character string from " << from << " to " << to << " available.\n";
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
if (ret) str = tmpstr;
|
|
Packit |
01d647 |
return ret;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
#endif // defined WIN32 && !defined __CYGWIN__
|
|
Packit |
01d647 |
#if defined EXV_HAVE_ICONV
|
|
Packit |
01d647 |
bool convertStringCharsetIconv(std::string& str, const char* from, const char* to)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (0 == strcmp(from, to)) return true; // nothing to do
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool ret = true;
|
|
Packit |
01d647 |
iconv_t cd;
|
|
Packit |
01d647 |
cd = iconv_open(to, from);
|
|
Packit |
01d647 |
if (cd == (iconv_t)(-1)) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "iconv_open: " << strError() << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
return false;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
std::string outstr;
|
|
Packit |
01d647 |
EXV_ICONV_CONST char* inptr = const_cast<char*>(str.c_str());
|
|
Packit |
01d647 |
size_t inbytesleft = str.length();
|
|
Packit |
01d647 |
while (inbytesleft) {
|
|
Packit |
01d647 |
char outbuf[256];
|
|
Packit |
01d647 |
char* outptr = outbuf;
|
|
Packit |
01d647 |
size_t outbytesleft = sizeof(outbuf);
|
|
Packit |
01d647 |
size_t rc = iconv(cd,
|
|
Packit |
01d647 |
&inptr,
|
|
Packit |
01d647 |
&inbytesleft,
|
|
Packit |
01d647 |
&outptr,
|
|
Packit |
01d647 |
&outbytesleft);
|
|
Packit |
01d647 |
const size_t outbytesProduced = sizeof(outbuf) - outbytesleft;
|
|
Packit |
01d647 |
if (rc == size_t(-1) && errno != E2BIG) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_WARNING << "iconv: " << strError()
|
|
Packit |
01d647 |
<< " inbytesleft = " << inbytesleft << "\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
ret = false;
|
|
Packit |
01d647 |
break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
outstr.append(std::string(outbuf, outbytesProduced));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (cd != (iconv_t)(-1)) {
|
|
Packit |
01d647 |
iconv_close(cd);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (ret) str = outstr;
|
|
Packit |
01d647 |
return ret;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
#endif // EXV_HAVE_ICONV
|
|
Packit |
01d647 |
bool getTextValue(std::string& value, const XmpData::iterator& pos)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (pos->typeId() == langAlt) {
|
|
Packit |
01d647 |
// get the default language entry without x-default qualifier
|
|
Packit |
01d647 |
value = pos->toString(0);
|
|
Packit |
01d647 |
if (!pos->value().ok() && pos->count() == 1) {
|
|
Packit |
01d647 |
// If there is no default but exactly one entry, take that
|
|
Packit |
01d647 |
// without the qualifier
|
|
Packit |
01d647 |
value = pos->toString();
|
|
Packit |
01d647 |
if ( pos->value().ok()
|
|
Packit |
01d647 |
&& value.length() > 5 && value.substr(0, 5) == "lang=") {
|
|
Packit |
01d647 |
const std::string::size_type first_space_pos = value.find_first_of(' ');
|
|
Packit |
01d647 |
if (first_space_pos != std::string::npos) {
|
|
Packit |
01d647 |
value = value.substr(first_space_pos + 1);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
value.clear();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
value = pos->toString();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return pos->value().ok();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
}
|