Update .clang-format file & apply clang-format to whole project

main
Luis Díaz Más 3 years ago
parent 0641a5f539
commit 30bf563f4d

@ -1,41 +1,20 @@
---
# Indentation for all files
ColumnLimit: 120
IndentWidth: 4
TabWidth: 4
UseTab: Never
# C++ Options
Language: Cpp
Standard: c++17
BasedOnStyle: Google
# Useful for sorting the project inclusions and standard library inclusions separately
IncludeBlocks: Preserve
AccessModifierOffset: -4
ContinuationIndentWidth: 4
# Constructor initializers better formatted in presence of preprocessor conditions (see image.cpp)
BreakConstructorInitializers: AfterColon
AllowAllConstructorInitializersOnNextLine: true
# break braces for most of the cases (except conditionals and loops)
BreakBeforeBraces: Custom
BraceWrapping:
AfterStruct: true
AfterClass: true
AfterFunction: true
AfterControlStatement: false
AfterEnum: true
AfterNamespace: true
# Do not allow SingleLine statements (to improve coverage statistics)
AllowShortFunctionsOnASingleLine: None
AllowShortBlocksOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
Cpp11BracedListStyle: true
...

File diff suppressed because it is too large Load Diff

@ -12,314 +12,308 @@
#define ACTIONS_HPP_
// *****************************************************************************
#include "exiv2app.hpp"
#include <unordered_map>
#include "exiv2app.hpp"
// *****************************************************************************
// class declarations
namespace Exiv2 {
class ExifData;
class Image;
class Metadatum;
class PreviewImage;
}
class ExifData;
class Image;
class Metadatum;
class PreviewImage;
} // namespace Exiv2
// *****************************************************************************
// namespace extensions
/// @brief Contains all action classes (task subclasses).
namespace Action {
//! Enumerates all tasks
enum TaskType { none, adjust, print, rename, erase, extract, insert,
modify, fixiso, fixcom };
//! Enumerates all tasks
enum TaskType { none, adjust, print, rename, erase, extract, insert, modify, fixiso, fixcom };
// *****************************************************************************
// class definitions
/*!
@brief Abstract base class for all concrete actions.
Task provides a simple interface that actions must implement and a few
commonly used helpers.
*/
class Task {
public:
//! Shortcut for an auto pointer.
using UniquePtr = std::unique_ptr<Task>;
//! Virtual destructor.
virtual ~Task() = default;
//! Virtual copy construction.
virtual UniquePtr clone() const = 0;
/// @brief Application interface to perform a task.
/// @param path Path of the file to process.
/// @return 0 if successful.
virtual int run(const std::string& path) =0;
bool setBinary(bool b)
{
bool bResult = binary_;
binary_ = b;
return bResult ;
}
bool binary() { return binary_ ; }
private:
//! copy binary_ from command-line params to task
bool binary_ {false} ;
}; // class Task
/*!
@brief Task factory.
Creates an instance of the task of the requested type. The factory is
implemented as a singleton, which can be accessed only through the static
member function instance().
*/
class TaskFactory {
public:
/*!
@brief Get access to the task factory.
Clients access the task factory exclusively through this method. (SINGLETON)
*/
static TaskFactory& instance();
//! Prevent copy construction: not implemented.
TaskFactory(const TaskFactory& rhs) = delete;
//! Destructor
void cleanup();
/*!
@brief Create a task.
@param type Identifies the type of task to create.
@return An auto pointer that owns a task of the requested type. If
the task type is not supported, the pointer is 0.
@remark The caller of the function should check the content of the
returned auto pointer and take appropriate action (e.g., throw
an exception) if it is 0.
*/
Task::UniquePtr create(TaskType type);
private:
//! Prevent construction other than through instance().
TaskFactory();
//! List of task types and corresponding prototypes.
std::unordered_map<TaskType, Task::UniquePtr> registry_;
};
//! %Print the Exif (or other metadata) of a file to stdout
class Print : public Task {
public:
~Print() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
//! Print the Jpeg comment
int printComment();
//! Print list of available preview images
int printPreviewList();
//! Print Exif summary information
int printSummary();
//! Print Exif, IPTC and XMP metadata in user defined format
int printList();
//! Return true if key should be printed, else false
static bool grepTag(const std::string& key);
//! Return true if key should be printed, else false
static bool keyTag(const std::string& key);
//! Print all metadata in a user defined format
int printMetadata(const Exiv2::Image* image);
//! Print a metadatum in a user defined format, return true if something was printed
bool printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* image);
//! Print the label for a summary line
void printLabel(const std::string& label) const;
/*!
@brief Print one summary line with a label (if provided) and requested
data. A line break is printed only if a label is provided.
@return 1 if a line was written, 0 if the key was not found.
*/
int printTag(const Exiv2::ExifData& exifData,
const std::string& key,
const std::string& label ="") const;
//! Type for an Exiv2 Easy access function
using EasyAccessFct = Exiv2::ExifData::const_iterator (*)(const Exiv2::ExifData& ed);
/*!
@brief Print one summary line with a label (if provided) and requested
data. A line break is printed only if a label is provided.
@return 1 if a line was written, 0 if the information was not found.
*/
int printTag(const Exiv2::ExifData& exifData,
EasyAccessFct easyAccessFct,
const std::string& label ="",
EasyAccessFct easyAccessFctFallback =NULL) const;
private:
std::string path_;
int align_{0}; // for the alignment of the summary output
};
/// @brief %Rename a file to its metadata creation timestamp, in the specified format.
class Rename : public Task {
public:
~Rename() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
}; // class Rename
//! %Adjust the Exif (or other metadata) timestamps
class Adjust : public Task {
public:
~Adjust() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
private:
int adjustDateTime(Exiv2::ExifData& exifData,
const std::string& key,
const std::string& path) const;
long adjustment_ {0};
long yearAdjustment_ {0};
long monthAdjustment_ {0};
long dayAdjustment_ {0};
}; // class Adjust
/// @brief %Erase the entire exif data or only the thumbnail section.
class Erase : public Task {
public:
~Erase() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
/// @brief Delete the thumbnail image, incl IFD1 metadata from the file.
static int eraseThumbnail(Exiv2::Image* image);
/// @brief Erase the complete Exif data block from the file.
static int eraseExifData(Exiv2::Image* image);
/// @brief Erase all Iptc data from the file.
static int eraseIptcData(Exiv2::Image* image);
/// @brief Erase Jpeg comment from the file.
static int eraseComment(Exiv2::Image* image);
/// @brief Erase XMP packet from the file.
static int eraseXmpData(Exiv2::Image* image);
/// @brief Erase ICCProfile from the file.
static int eraseIccProfile(Exiv2::Image* image);
private:
std::string path_;
};
/// @brief %Extract the entire exif data or only the thumbnail section.
class Extract : public Task {
public:
~Extract() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
/*!
@brief Write the thumbnail image to a file. The filename is composed by
removing the suffix from the image filename and appending
"-thumb" and the appropriate suffix (".jpg" or ".tif"), depending
on the format of the Exif thumbnail image.
*/
int writeThumbnail() const;
/// @brief Write preview images to files.
int writePreviews() const;
/// @brief Write one preview image to a file. The filename is composed by removing the suffix from the image
/// filename and appending "-preview<num>" and the appropriate suffix (".jpg" or ".tif"), depending on the
/// format of the Exif thumbnail image.
void writePreviewFile(const Exiv2::PreviewImage& pvImg, size_t num) const;
/// @brief Write embedded iccProfile files.
int writeIccProfile(const std::string& target) const;
private:
std::string path_;
};
/// @brief %Insert the Exif data from corresponding *.exv files.
class Insert : public Task {
public:
~Insert() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
/*!
@brief Insert a Jpeg thumbnail image from a file into file \em path.
The filename of the thumbnail is expected to be the image
filename (\em path) minus its suffix plus "-thumb.jpg".
*/
static int insertThumbnail(const std::string& path);
/// @brief Insert an XMP packet from a xmpPath into file \em path.
static int insertXmpPacket(const std::string& path,const std::string& xmpPath) ;
/// @brief Insert xmp from a DataBuf into file \em path.
static int insertXmpPacket(const std::string& path, const Exiv2::DataBuf& xmpBlob, bool usePacket = false);
/// @brief Insert an ICC profile from iccPath into file \em path.
static int insertIccProfile(const std::string& path,const std::string& iccPath) ;
/// @brief Insert an ICC profile from binary DataBuf into file \em path.
static int insertIccProfile(const std::string& path, Exiv2::DataBuf&& iccProfileBlob);
};
/// @brief %Modify the Exif data according to the commands in the modification table.
class Modify : public Task {
public:
Modify() = default;
~Modify() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
//! Apply modification commands to the \em pImage, return 0 if successful.
static int applyCommands(Exiv2::Image* pImage);
private:
//! Add a metadatum to \em pImage according to \em modifyCmd
static int addMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd);
//! Set a metadatum in \em pImage according to \em modifyCmd
static int setMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd);
//! Delete a metadatum from \em pImage according to \em modifyCmd
static void delMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd);
//! Register an XMP namespace according to \em modifyCmd
static void regNamespace(const ModifyCmd& modifyCmd);
};
/// @brief %Copy ISO settings from any of the Nikon makernotes to the regular Exif tag, Exif.Photo.ISOSpeedRatings.
class FixIso : public Task {
public:
~FixIso() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
private:
std::string path_;
};
/// @brief Fix the character encoding of Exif UNICODE user comments.
///
/// Decodes the comment using the auto-detected or specified character encoding and writes it back in UCS-2.
class FixCom : public Task {
public:
~FixCom() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
private:
std::string path_;
};
} // namespace Action
#endif // #ifndef ACTIONS_HPP_
/*!
@brief Abstract base class for all concrete actions.
Task provides a simple interface that actions must implement and a few
commonly used helpers.
*/
class Task {
public:
//! Shortcut for an auto pointer.
using UniquePtr = std::unique_ptr<Task>;
//! Virtual destructor.
virtual ~Task() = default;
//! Virtual copy construction.
virtual UniquePtr clone() const = 0;
/// @brief Application interface to perform a task.
/// @param path Path of the file to process.
/// @return 0 if successful.
virtual int run(const std::string& path) = 0;
bool setBinary(bool b) {
bool bResult = binary_;
binary_ = b;
return bResult;
}
bool binary() {
return binary_;
}
private:
//! copy binary_ from command-line params to task
bool binary_{false};
}; // class Task
/*!
@brief Task factory.
Creates an instance of the task of the requested type. The factory is
implemented as a singleton, which can be accessed only through the static
member function instance().
*/
class TaskFactory {
public:
/*!
@brief Get access to the task factory.
Clients access the task factory exclusively through this method. (SINGLETON)
*/
static TaskFactory& instance();
//! Prevent copy construction: not implemented.
TaskFactory(const TaskFactory& rhs) = delete;
//! Destructor
void cleanup();
/*!
@brief Create a task.
@param type Identifies the type of task to create.
@return An auto pointer that owns a task of the requested type. If
the task type is not supported, the pointer is 0.
@remark The caller of the function should check the content of the
returned auto pointer and take appropriate action (e.g., throw
an exception) if it is 0.
*/
Task::UniquePtr create(TaskType type);
private:
//! Prevent construction other than through instance().
TaskFactory();
//! List of task types and corresponding prototypes.
std::unordered_map<TaskType, Task::UniquePtr> registry_;
};
//! %Print the Exif (or other metadata) of a file to stdout
class Print : public Task {
public:
~Print() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
//! Print the Jpeg comment
int printComment();
//! Print list of available preview images
int printPreviewList();
//! Print Exif summary information
int printSummary();
//! Print Exif, IPTC and XMP metadata in user defined format
int printList();
//! Return true if key should be printed, else false
static bool grepTag(const std::string& key);
//! Return true if key should be printed, else false
static bool keyTag(const std::string& key);
//! Print all metadata in a user defined format
int printMetadata(const Exiv2::Image* image);
//! Print a metadatum in a user defined format, return true if something was printed
bool printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* image);
//! Print the label for a summary line
void printLabel(const std::string& label) const;
/*!
@brief Print one summary line with a label (if provided) and requested
data. A line break is printed only if a label is provided.
@return 1 if a line was written, 0 if the key was not found.
*/
int printTag(const Exiv2::ExifData& exifData, const std::string& key, const std::string& label = "") const;
//! Type for an Exiv2 Easy access function
using EasyAccessFct = Exiv2::ExifData::const_iterator (*)(const Exiv2::ExifData& ed);
/*!
@brief Print one summary line with a label (if provided) and requested
data. A line break is printed only if a label is provided.
@return 1 if a line was written, 0 if the information was not found.
*/
int printTag(const Exiv2::ExifData& exifData, EasyAccessFct easyAccessFct, const std::string& label = "",
EasyAccessFct easyAccessFctFallback = NULL) const;
private:
std::string path_;
int align_{0}; // for the alignment of the summary output
};
/// @brief %Rename a file to its metadata creation timestamp, in the specified format.
class Rename : public Task {
public:
~Rename() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
}; // class Rename
//! %Adjust the Exif (or other metadata) timestamps
class Adjust : public Task {
public:
~Adjust() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
private:
int adjustDateTime(Exiv2::ExifData& exifData, const std::string& key, const std::string& path) const;
long adjustment_{0};
long yearAdjustment_{0};
long monthAdjustment_{0};
long dayAdjustment_{0};
}; // class Adjust
/// @brief %Erase the entire exif data or only the thumbnail section.
class Erase : public Task {
public:
~Erase() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
/// @brief Delete the thumbnail image, incl IFD1 metadata from the file.
static int eraseThumbnail(Exiv2::Image* image);
/// @brief Erase the complete Exif data block from the file.
static int eraseExifData(Exiv2::Image* image);
/// @brief Erase all Iptc data from the file.
static int eraseIptcData(Exiv2::Image* image);
/// @brief Erase Jpeg comment from the file.
static int eraseComment(Exiv2::Image* image);
/// @brief Erase XMP packet from the file.
static int eraseXmpData(Exiv2::Image* image);
/// @brief Erase ICCProfile from the file.
static int eraseIccProfile(Exiv2::Image* image);
private:
std::string path_;
};
/// @brief %Extract the entire exif data or only the thumbnail section.
class Extract : public Task {
public:
~Extract() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
/*!
@brief Write the thumbnail image to a file. The filename is composed by
removing the suffix from the image filename and appending
"-thumb" and the appropriate suffix (".jpg" or ".tif"), depending
on the format of the Exif thumbnail image.
*/
int writeThumbnail() const;
/// @brief Write preview images to files.
int writePreviews() const;
/// @brief Write one preview image to a file. The filename is composed by removing the suffix from the image
/// filename and appending "-preview<num>" and the appropriate suffix (".jpg" or ".tif"), depending on the
/// format of the Exif thumbnail image.
void writePreviewFile(const Exiv2::PreviewImage& pvImg, size_t num) const;
/// @brief Write embedded iccProfile files.
int writeIccProfile(const std::string& target) const;
private:
std::string path_;
};
/// @brief %Insert the Exif data from corresponding *.exv files.
class Insert : public Task {
public:
~Insert() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
/*!
@brief Insert a Jpeg thumbnail image from a file into file \em path.
The filename of the thumbnail is expected to be the image
filename (\em path) minus its suffix plus "-thumb.jpg".
*/
static int insertThumbnail(const std::string& path);
/// @brief Insert an XMP packet from a xmpPath into file \em path.
static int insertXmpPacket(const std::string& path, const std::string& xmpPath);
/// @brief Insert xmp from a DataBuf into file \em path.
static int insertXmpPacket(const std::string& path, const Exiv2::DataBuf& xmpBlob, bool usePacket = false);
/// @brief Insert an ICC profile from iccPath into file \em path.
static int insertIccProfile(const std::string& path, const std::string& iccPath);
/// @brief Insert an ICC profile from binary DataBuf into file \em path.
static int insertIccProfile(const std::string& path, Exiv2::DataBuf&& iccProfileBlob);
};
/// @brief %Modify the Exif data according to the commands in the modification table.
class Modify : public Task {
public:
Modify() = default;
~Modify() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
//! Apply modification commands to the \em pImage, return 0 if successful.
static int applyCommands(Exiv2::Image* pImage);
private:
//! Add a metadatum to \em pImage according to \em modifyCmd
static int addMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd);
//! Set a metadatum in \em pImage according to \em modifyCmd
static int setMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd);
//! Delete a metadatum from \em pImage according to \em modifyCmd
static void delMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd);
//! Register an XMP namespace according to \em modifyCmd
static void regNamespace(const ModifyCmd& modifyCmd);
};
/// @brief %Copy ISO settings from any of the Nikon makernotes to the regular Exif tag, Exif.Photo.ISOSpeedRatings.
class FixIso : public Task {
public:
~FixIso() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
private:
std::string path_;
};
/// @brief Fix the character encoding of Exif UNICODE user comments.
///
/// Decodes the comment using the auto-detected or specified character encoding and writes it back in UCS-2.
class FixCom : public Task {
public:
~FixCom() override = default;
int run(const std::string& path) override;
Task::UniquePtr clone() const override;
private:
std::string path_;
};
} // namespace Action
#endif // #ifndef ACTIONS_HPP_

@ -1,22 +1,20 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cstdlib>
#include <climits>
#include <cstdlib>
namespace Util
{
bool strtol(const char* nptr, long& n)
{
if (!nptr || *nptr == '\0')
return false;
char* endptr = nullptr;
long tmp = std::strtol(nptr, &endptr, 10);
if (*endptr != '\0')
return false;
if (tmp == LONG_MAX || tmp == LONG_MIN)
return false;
n = tmp;
return true;
}
namespace Util {
bool strtol(const char* nptr, long& n) {
if (!nptr || *nptr == '\0')
return false;
char* endptr = nullptr;
long tmp = std::strtol(nptr, &endptr, 10);
if (*endptr != '\0')
return false;
if (tmp == LONG_MAX || tmp == LONG_MIN)
return false;
n = tmp;
return true;
}
} // namespace Util

@ -4,12 +4,12 @@
#define APP_UTILS_HPP_
namespace Util {
/*!
@brief Convert a C string to a long value, which is returned in n.
Returns true if the conversion is successful, else false.
n is not modified if the conversion is unsuccessful. See strtol(2).
*/
bool strtol(const char* nptr, long& n);
} // namespace Util
/*!
@brief Convert a C string to a long value, which is returned in n.
Returns true if the conversion is successful, else false.
n is not modified if the conversion is unsuccessful. See strtol(2).
*/
bool strtol(const char* nptr, long& n);
} // namespace Util
#endif // #ifndef UTILS_HPP_
#endif // #ifndef UTILS_HPP_

File diff suppressed because it is too large Load Diff

@ -12,13 +12,13 @@
// included header files
#include <exiv2/exiv2.hpp>
#include "types.hpp"
#include "getopt.hpp"
#include "types.hpp"
// + standard includes
#include <set>
#include <iostream>
#include <regex>
#include <set>
// *****************************************************************************
// class definitions
@ -29,32 +29,28 @@ enum CmdId { invalidCmdId, add, set, del, reg };
// enum MetadataId { invalidMetadataId, iptc, exif, xmp };
//! Metadata identifiers
// mdNone=0, mdExif=1, mdIptc=2, mdComment=4, mdXmp=8
enum MetadataId { invalidMetadataId = Exiv2::mdNone
, iptc = Exiv2::mdIptc
, exif = Exiv2::mdExif
, xmp = Exiv2::mdXmp
} ;
enum MetadataId { invalidMetadataId = Exiv2::mdNone, iptc = Exiv2::mdIptc, exif = Exiv2::mdExif, xmp = Exiv2::mdXmp };
//! Structure for one parsed modification command
struct ModifyCmd {
//! C'tor
ModifyCmd() :
cmdId_(invalidCmdId), metadataId_(invalidMetadataId),
typeId_(Exiv2::invalidTypeId), explicitType_(false) {}
CmdId cmdId_; //!< Command identifier
std::string key_; //!< Exiv2 key string
MetadataId metadataId_; //!< Metadata identifier
Exiv2::TypeId typeId_; //!< Exiv2 type identifier
//! Flag to indicate if the type was explicitly specified (true)
bool explicitType_;
std::string value_; //!< Data
//! C'tor
ModifyCmd() :
cmdId_(invalidCmdId), metadataId_(invalidMetadataId), typeId_(Exiv2::invalidTypeId), explicitType_(false) {
}
CmdId cmdId_; //!< Command identifier
std::string key_; //!< Exiv2 key string
MetadataId metadataId_; //!< Metadata identifier
Exiv2::TypeId typeId_; //!< Exiv2 type identifier
//! Flag to indicate if the type was explicitly specified (true)
bool explicitType_;
std::string value_; //!< Data
};
//! Container for modification commands
using ModifyCmds = std::vector<ModifyCmd>;
//! Structure to link command identifiers to strings
struct CmdIdAndString {
CmdId cmdId_; //!< Commands identifier
std::string cmdString_; //!< Command string
CmdId cmdId_; //!< Commands identifier
std::string cmdString_; //!< Command string
};
/*!
@ -93,180 +89,170 @@ struct CmdIdAndString {
*/
class Params : public Util::Getopt {
private:
std::string optstring_;
public:
//! Container for command files
using CmdFiles = std::vector<std::string>;
//! Container for commands from the command line
using CmdLines = std::vector<std::string>;
//! Container to store filenames.
using Files = std::vector<std::string>;
//! Container for preview image numbers
using PreviewNumbers = std::set<int>;
//! Container for keys
using Keys = std::vector<std::string>;
/*!
@brief Controls all access to the global Params instance.
@return Reference to the global Params instance.
*/
static Params& instance();
//! Prevent copy-construction: not implemented.
Params(const Params& rhs) = delete;
//! Enumerates print modes
enum PrintMode {
pmSummary,
pmList,
pmComment,
pmPreview,
pmStructure,
pmXMP,
pmIccProfile,
pmRecursive
};
//! Individual items to print, bitmap
enum PrintItem {
prTag = 1,
prGroup = 2,
prKey = 4,
prName = 8,
prLabel = 16,
prType = 32,
prCount = 64,
prSize = 128,
prValue = 256,
prTrans = 512,
prHex = 1024,
prSet = 2048
};
//! Enumerates common targets, bitmap
enum CommonTarget {
ctExif = 1,
ctIptc = 2,
ctComment = 4,
ctThumb = 8,
ctXmp = 16,
ctXmpSidecar = 32,
ctPreview = 64,
ctIccProfile = 128,
ctXmpRaw = 256,
ctStdInOut = 512,
ctIptcRaw =1024
};
//! Enumerates the policies to handle existing files in rename action
enum FileExistsPolicy { overwritePolicy, renamePolicy, askPolicy };
//! Enumerates year, month and day adjustments.
enum Yod { yodYear, yodMonth, yodDay };
//! Structure for year, month and day adjustment command line arguments.
struct YodAdjust {
bool flag_; //!< Adjustment flag.
const char* option_; //!< Adjustment option string.
long adjustment_; //!< Adjustment value.
};
bool help_; //!< Help option flag.
bool version_; //!< Version option flag.
bool verbose_; //!< Verbose (talkative) option flag.
bool force_; //!< Force overwrites flag.
bool binary_; //!< Suppress long binary values.
bool unknown_; //!< Suppress unknown tags.
bool preserve_; //!< Preserve timestamps flag.
bool timestamp_; //!< Rename also sets the file timestamp.
bool timestampOnly_; //!< Rename only sets the file timestamp.
FileExistsPolicy fileExistsPolicy_; //!< What to do if file to rename exists.
bool adjust_; //!< Adjustment flag.
PrintMode printMode_; //!< Print mode.
unsigned long printItems_; //!< Print items.
unsigned long printTags_; //!< Print tags (bitmap of MetadataId flags).
//! %Action (integer rather than TaskType to avoid dependency).
int action_;
int target_; //!< What common target to process.
long adjustment_; //!< Adjustment in seconds.
YodAdjust yodAdjust_[3]; //!< Year, month and day adjustment info.
std::string format_; //!< Filename format (-r option arg).
bool formatSet_; //!< Whether the format is set with -r
CmdFiles cmdFiles_; //!< Names of the modification command files
CmdLines cmdLines_; //!< Commands from the command line
ModifyCmds modifyCmds_; //!< Parsed modification commands
std::string jpegComment_; //!< Jpeg comment to set in the image
std::string directory_; //!< Location for files to extract/insert
std::string suffix_; //!< File extension of the file to insert
Files files_; //!< List of non-option arguments.
PreviewNumbers previewNumbers_; //!< List of preview numbers
std::vector<std::regex> greps_; //!< List of keys to 'grep' from the metadata
Keys keys_; //!< List of keys to match from the metadata
std::string charset_; //!< Charset to use for UNICODE Exif user comment
Exiv2::DataBuf stdinBuf; //!< DataBuf with the binary bytes from stdin
private:
bool first_;
Params();
private:
//! @name Helpers
//@{
int setLogLevel(const std::string& optarg);
int evalGrep( const std::string& optarg);
int evalKey( const std::string& optarg);
int evalRename(int opt, const std::string& optarg);
int evalAdjust(const std::string& optarg);
int evalYodAdjust(const Yod& yod, const std::string& optarg);
int evalPrint(const std::string& optarg);
int evalPrintFlags(const std::string& optarg);
int evalDelete(const std::string& optarg);
int evalExtract(const std::string& optarg);
int evalInsert(const std::string& optarg);
int evalModify(int opt, const std::string& optarg);
//@}
public:
/*!
@brief Call Getopt::getopt() with optstring, to initiate command line
argument parsing, perform consistency checks after all command line
arguments are parsed.
@param argc Argument count as passed to main() on program invocation.
@param argv Argument array as passed to main() on program invocation.
@return 0 if successful, >0 in case of errors.
*/
int getopt(int argc, char* const argv[]);
//! Handle options and their arguments.
int option(int opt, const std::string& optarg, int optopt) override;
//! Handle non-option parameters.
int nonoption(const std::string& argv) override;
//! Print a minimal usage note to an output stream.
void usage(std::ostream& os =std::cout) const;
//! Print further usage explanations to an output stream.
void help(std::ostream& os =std::cout) const;
//! Print version information to an output stream.
static void version(bool verbose = false, std::ostream& os = std::cout);
//! getStdin binary data read from stdin to DataBuf
/*
stdin can be used by multiple images in the exiv2 command line:
For example: $ cat foo.icc | exiv2 -iC- a.jpg b.jpg c.jpg will modify the ICC profile in several images.
*/
void getStdin(Exiv2::DataBuf& buf);
}; // class Params
#endif // #ifndef EXIV2APP_HPP_
private:
std::string optstring_;
public:
//! Container for command files
using CmdFiles = std::vector<std::string>;
//! Container for commands from the command line
using CmdLines = std::vector<std::string>;
//! Container to store filenames.
using Files = std::vector<std::string>;
//! Container for preview image numbers
using PreviewNumbers = std::set<int>;
//! Container for keys
using Keys = std::vector<std::string>;
/*!
@brief Controls all access to the global Params instance.
@return Reference to the global Params instance.
*/
static Params& instance();
//! Prevent copy-construction: not implemented.
Params(const Params& rhs) = delete;
//! Enumerates print modes
enum PrintMode { pmSummary, pmList, pmComment, pmPreview, pmStructure, pmXMP, pmIccProfile, pmRecursive };
//! Individual items to print, bitmap
enum PrintItem {
prTag = 1,
prGroup = 2,
prKey = 4,
prName = 8,
prLabel = 16,
prType = 32,
prCount = 64,
prSize = 128,
prValue = 256,
prTrans = 512,
prHex = 1024,
prSet = 2048
};
//! Enumerates common targets, bitmap
enum CommonTarget {
ctExif = 1,
ctIptc = 2,
ctComment = 4,
ctThumb = 8,
ctXmp = 16,
ctXmpSidecar = 32,
ctPreview = 64,
ctIccProfile = 128,
ctXmpRaw = 256,
ctStdInOut = 512,
ctIptcRaw = 1024
};
//! Enumerates the policies to handle existing files in rename action
enum FileExistsPolicy { overwritePolicy, renamePolicy, askPolicy };
//! Enumerates year, month and day adjustments.
enum Yod { yodYear, yodMonth, yodDay };
//! Structure for year, month and day adjustment command line arguments.
struct YodAdjust {
bool flag_; //!< Adjustment flag.
const char* option_; //!< Adjustment option string.
long adjustment_; //!< Adjustment value.
};
bool help_; //!< Help option flag.
bool version_; //!< Version option flag.
bool verbose_; //!< Verbose (talkative) option flag.
bool force_; //!< Force overwrites flag.
bool binary_; //!< Suppress long binary values.
bool unknown_; //!< Suppress unknown tags.
bool preserve_; //!< Preserve timestamps flag.
bool timestamp_; //!< Rename also sets the file timestamp.
bool timestampOnly_; //!< Rename only sets the file timestamp.
FileExistsPolicy fileExistsPolicy_; //!< What to do if file to rename exists.
bool adjust_; //!< Adjustment flag.
PrintMode printMode_; //!< Print mode.
unsigned long printItems_; //!< Print items.
unsigned long printTags_; //!< Print tags (bitmap of MetadataId flags).
//! %Action (integer rather than TaskType to avoid dependency).
int action_;
int target_; //!< What common target to process.
long adjustment_; //!< Adjustment in seconds.
YodAdjust yodAdjust_[3]; //!< Year, month and day adjustment info.
std::string format_; //!< Filename format (-r option arg).
bool formatSet_; //!< Whether the format is set with -r
CmdFiles cmdFiles_; //!< Names of the modification command files
CmdLines cmdLines_; //!< Commands from the command line
ModifyCmds modifyCmds_; //!< Parsed modification commands
std::string jpegComment_; //!< Jpeg comment to set in the image
std::string directory_; //!< Location for files to extract/insert
std::string suffix_; //!< File extension of the file to insert
Files files_; //!< List of non-option arguments.
PreviewNumbers previewNumbers_; //!< List of preview numbers
std::vector<std::regex> greps_; //!< List of keys to 'grep' from the metadata
Keys keys_; //!< List of keys to match from the metadata
std::string charset_; //!< Charset to use for UNICODE Exif user comment
Exiv2::DataBuf stdinBuf; //!< DataBuf with the binary bytes from stdin
private:
bool first_;
Params();
private:
//! @name Helpers
//@{
int setLogLevel(const std::string& optarg);
int evalGrep(const std::string& optarg);
int evalKey(const std::string& optarg);
int evalRename(int opt, const std::string& optarg);
int evalAdjust(const std::string& optarg);
int evalYodAdjust(const Yod& yod, const std::string& optarg);
int evalPrint(const std::string& optarg);
int evalPrintFlags(const std::string& optarg);
int evalDelete(const std::string& optarg);
int evalExtract(const std::string& optarg);
int evalInsert(const std::string& optarg);
int evalModify(int opt, const std::string& optarg);
//@}
public:
/*!
@brief Call Getopt::getopt() with optstring, to initiate command line
argument parsing, perform consistency checks after all command line
arguments are parsed.
@param argc Argument count as passed to main() on program invocation.
@param argv Argument array as passed to main() on program invocation.
@return 0 if successful, >0 in case of errors.
*/
int getopt(int argc, char* const argv[]);
//! Handle options and their arguments.
int option(int opt, const std::string& optarg, int optopt) override;
//! Handle non-option parameters.
int nonoption(const std::string& argv) override;
//! Print a minimal usage note to an output stream.
void usage(std::ostream& os = std::cout) const;
//! Print further usage explanations to an output stream.
void help(std::ostream& os = std::cout) const;
//! Print version information to an output stream.
static void version(bool verbose = false, std::ostream& os = std::cout);
//! getStdin binary data read from stdin to DataBuf
/*
stdin can be used by multiple images in the exiv2 command line:
For example: $ cat foo.icc | exiv2 -iC- a.jpg b.jpg c.jpg will modify the ICC profile in several images.
*/
void getStdin(Exiv2::DataBuf& buf);
}; // class Params
#endif // #ifndef EXIV2APP_HPP_

@ -10,107 +10,101 @@
namespace fs = std::filesystem;
namespace Util {
// https://raw.githubusercontent.com/skeeto/getopt/master/getopt.h
int optind = 0;
int opterr = 1;
int optopt;
int optpos = 1;
const char* optarg;
// https://raw.githubusercontent.com/skeeto/getopt/master/getopt.h
int optind = 0;
int opterr = 1;
int optopt;
int optpos = 1;
const char* optarg;
/* A minimal POSIX getopt() implementation in ANSI C
*
* This is free and unencumbered software released into the public domain.
*
* This implementation supports the convention of resetting the option
* parser by assigning optind to 0. This resets the internal state
* appropriately.
*
* Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html
*/
/* A minimal POSIX getopt() implementation in ANSI C
*
* This is free and unencumbered software released into the public domain.
*
* This implementation supports the convention of resetting the option
* parser by assigning optind to 0. This resets the internal state
* appropriately.
*
* Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html
*/
int getopt(int argc, char* const argv[], const char* optstring) {
const char* arg;
(void)argc;
int getopt(int argc, char * const argv[], const char *optstring)
{
const char *arg;
(void)argc;
/* Reset? */
if (optind == 0) {
optind = 1;
optpos = 1;
}
/* Reset? */
if (optind == 0) {
optind = 1;
optpos = 1;
}
arg = argv[optind];
if (arg && strcmp(arg, "--") == 0) {
optind++;
return -1;
}
if (!arg || arg[0] != '-' || !isalnum(arg[1])) {
return -1;
}
const char *opt = strchr(optstring, arg[optpos]);
optopt = arg[optpos];
if (!opt) {
if (opterr && *optstring != ':')
fprintf(stderr, "%s: illegal option: %c\n", argv[0], optopt);
return '?';
}
if (opt[1] == ':') {
if (arg[optpos + 1]) {
optarg = const_cast<char*>(arg) + optpos + 1;
optind++;
optpos = 1;
return optopt;
}
if (argv[optind + 1]) {
optarg = argv[optind + 1];
optind += 2;
optpos = 1;
return optopt;
}
if (opterr && *optstring != ':')
fprintf(stderr, "%s: option requires an argument: %c\n", argv[0], optopt);
return *optstring == ':' ? ':' : '?';
}
if (!arg[++optpos]) {
optind++;
optpos = 1;
}
return optopt;
arg = argv[optind];
if (arg && strcmp(arg, "--") == 0) {
optind++;
return -1;
}
if (!arg || arg[0] != '-' || !isalnum(arg[1])) {
return -1;
}
const char* opt = strchr(optstring, arg[optpos]);
optopt = arg[optpos];
if (!opt) {
if (opterr && *optstring != ':')
fprintf(stderr, "%s: illegal option: %c\n", argv[0], optopt);
return '?';
}
if (opt[1] == ':') {
if (arg[optpos + 1]) {
optarg = const_cast<char*>(arg) + optpos + 1;
optind++;
optpos = 1;
return optopt;
}
if (argv[optind + 1]) {
optarg = argv[optind + 1];
optind += 2;
optpos = 1;
return optopt;
}
if (opterr && *optstring != ':')
fprintf(stderr, "%s: option requires an argument: %c\n", argv[0], optopt);
return *optstring == ':' ? ':' : '?';
}
if (!arg[++optpos]) {
optind++;
optpos = 1;
}
return optopt;
}
// *****************************************************************************
// class Getopt
Getopt::Getopt()
: errcnt_(0)
{
}
int Getopt::getopt(int argc, char* const argv[], const std::string& optstring)
{
progname_ = fs::path(argv[0]).filename().string();
Util::optind = 0; // reset the Util::Getopt scanner
Getopt::Getopt() : errcnt_(0) {
}
for (;!errcnt_;) {
int c = Util::getopt(argc, argv, optstring.c_str());
if (c == -1) {
break;
}
errcnt_ += option(c, Util::optarg ? Util::optarg : "", Util::optopt);
if (c == '?' ) {
break;
}
}
for (int i = Util::optind; i < argc; i++) {
errcnt_ += nonoption(argv[i]);
}
int Getopt::getopt(int argc, char* const argv[], const std::string& optstring) {
progname_ = fs::path(argv[0]).filename().string();
Util::optind = 0; // reset the Util::Getopt scanner
return errcnt_;
for (; !errcnt_;) {
int c = Util::getopt(argc, argv, optstring.c_str());
if (c == -1) {
break;
}
int Getopt::nonoption(const std::string& /*argv*/)
{
return 0;
errcnt_ += option(c, Util::optarg ? Util::optarg : "", Util::optopt);
if (c == '?') {
break;
}
}
for (int i = Util::optind; i < argc; i++) {
errcnt_ += nonoption(argv[i]);
}
return errcnt_;
}
int Getopt::nonoption(const std::string& /*argv*/) {
return 0;
}
} // namespace Util
} // namespace Util

@ -6,96 +6,99 @@
#include <string>
namespace Util {
extern int optind ;
extern int opterr ;
extern int optopt ;
extern int optpos ;
extern const char* optarg;
int getopt(int argc, char * const argv[], const char *optstring);
// *********************************************************************
// class definitions
/*!
@brief Parse the command line options of a program.
A wrapper around the POSIX %getopt(3) function. Parses the command line
options and passes each option to virtual option(). A derived class
implements this method to handle options as needed. Similarly,
remaining non-option parameters are passed to the virtual nonoption()
method.
*/
class Getopt {
public:
//! Default constructor.
Getopt();
//! Destructor.
virtual ~Getopt() = default;
/*!
@brief Parse command line arguments.
Parses the command line arguments. Calls option() with the
character value of the option and its argument (if any) for each
recognized option and with ':' or '?' for unrecognized options.
See the manual pages for %getopt(3) for details. In addition,
nonoption() is invoked for each remaining non-option parameter on
the command line.
@param argc Argument count as passed to main() on program invocation.
@param argv Argument array as passed to main() on program invocation.
@param optstring String containing the legitimate option characters.
@return Number of errors (the sum of the return values from option()
and nonoption()).
*/
int getopt(int argc, char* const argv[], const std::string& optstring);
/*!
@brief Callback used by getopt() to pass on each option and its
argument (if any).
Implement this method in a derived class to handle the options as
needed. See the manual pages for %getopt(3) for further details, in
particular, the semantics of optarg and optopt.
@param opt Value of the option character as returned by %getopt(3).
@param optarg The corresponding option argument.
@param optopt The actual option character in case of an unrecognized
option or a missing option argument (opt is '?' or ':').
@return 0 if successful, 1 in case of an error.
*/
virtual int option(int opt, const std::string& optarg, int optopt) = 0;
/*!
@brief Callback used by getopt() to pass on each non-option parameter
found on the command line.
Implement this method in a derived class to handle the non-option
parameters as needed. The default implementation ignores all non-option
parameters.
@param argv The non-option parameter from the command line.
@return 0 if successful, 1 in case of an error.
*/
virtual int nonoption(const std::string& argv);
//! Program name (argv[0])
const std::string& progname() const { return progname_; }
//! Total number of errors returned by calls to option()
int errcnt() const { return errcnt_; }
private:
std::string progname_;
int errcnt_;
};
}; // namespace Util
extern int optind;
extern int opterr;
extern int optopt;
extern int optpos;
extern const char* optarg;
int getopt(int argc, char* const argv[], const char* optstring);
// *********************************************************************
// class definitions
/*!
@brief Parse the command line options of a program.
A wrapper around the POSIX %getopt(3) function. Parses the command line
options and passes each option to virtual option(). A derived class
implements this method to handle options as needed. Similarly,
remaining non-option parameters are passed to the virtual nonoption()
method.
*/
class Getopt {
public:
//! Default constructor.
Getopt();
//! Destructor.
virtual ~Getopt() = default;
/*!
@brief Parse command line arguments.
Parses the command line arguments. Calls option() with the
character value of the option and its argument (if any) for each
recognized option and with ':' or '?' for unrecognized options.
See the manual pages for %getopt(3) for details. In addition,
nonoption() is invoked for each remaining non-option parameter on
the command line.
@param argc Argument count as passed to main() on program invocation.
@param argv Argument array as passed to main() on program invocation.
@param optstring String containing the legitimate option characters.
@return Number of errors (the sum of the return values from option()
and nonoption()).
*/
int getopt(int argc, char* const argv[], const std::string& optstring);
/*!
@brief Callback used by getopt() to pass on each option and its
argument (if any).
Implement this method in a derived class to handle the options as
needed. See the manual pages for %getopt(3) for further details, in
particular, the semantics of optarg and optopt.
@param opt Value of the option character as returned by %getopt(3).
@param optarg The corresponding option argument.
@param optopt The actual option character in case of an unrecognized
option or a missing option argument (opt is '?' or ':').
@return 0 if successful, 1 in case of an error.
*/
virtual int option(int opt, const std::string& optarg, int optopt) = 0;
/*!
@brief Callback used by getopt() to pass on each non-option parameter
found on the command line.
Implement this method in a derived class to handle the non-option
parameters as needed. The default implementation ignores all non-option
parameters.
@param argv The non-option parameter from the command line.
@return 0 if successful, 1 in case of an error.
*/
virtual int nonoption(const std::string& argv);
//! Program name (argv[0])
const std::string& progname() const {
return progname_;
}
//! Total number of errors returned by calls to option()
int errcnt() const {
return errcnt_;
}
private:
std::string progname_;
int errcnt_;
};
}; // namespace Util
#endif

@ -4,39 +4,37 @@
extern int __cdecl main();
int wmain(int argc, wchar_t* argv[])
{
char** args;
int nbytes = (int)(sizeof(char*) * (argc + 1));
HANDLE heap = GetProcessHeap();
for (int i = 0; i < argc; ++i)
nbytes += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL);
args = HeapAlloc(heap, 0, nbytes);
args[0] = (char*)(args + argc + 1);
for (int i = 0; i < argc; ++i)
args[i+1] = args[i] + WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, args[i], nbytes, NULL, NULL);
args[argc] = NULL;
argc = main(argc, args);
HeapFree(heap, 0, args);
return argc;
int wmain(int argc, wchar_t* argv[]) {
char** args;
int nbytes = (int)(sizeof(char*) * (argc + 1));
HANDLE heap = GetProcessHeap();
for (int i = 0; i < argc; ++i)
nbytes += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL);
args = HeapAlloc(heap, 0, nbytes);
args[0] = (char*)(args + argc + 1);
for (int i = 0; i < argc; ++i)
args[i + 1] = args[i] + WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, args[i], nbytes, NULL, NULL);
args[argc] = NULL;
argc = main(argc, args);
HeapFree(heap, 0, args);
return argc;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
(void) hInstance;
(void) hPrevInstance;
(void) lpCmdLine;
(void) nCmdShow;
int argc;
wchar_t** argv;
argv = CommandLineToArgvW(GetCommandLineW(), &argc);
argc = wmain(argc, argv);
LocalFree(argv);
return argc;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) {
(void)hInstance;
(void)hPrevInstance;
(void)lpCmdLine;
(void)nCmdShow;
int argc;
wchar_t** argv;
argv = CommandLineToArgvW(GetCommandLineW(), &argc);
argc = wmain(argc, argv);
LocalFree(argv);
return argc;
}

@ -1,10 +1,10 @@
#include <exiv2/exiv2.hpp>
#include <iostream>
#include <iomanip>
#include <cassert>
#include <iomanip>
#include <iostream>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Invalid files generate a lot of warnings, so switch off logging.
Exiv2::LogMsg::setLevel(Exiv2::LogMsg::mute);
@ -16,8 +16,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) {
try {
Exiv2::DataBuf data_copy(data, size);
Exiv2::Image::UniquePtr image =
Exiv2::ImageFactory::open(data_copy.c_data(), size);
Exiv2::Image::UniquePtr image = Exiv2::ImageFactory::open(data_copy.c_data(), size);
assert(image.get() != 0);
image->readMetadata();
@ -43,7 +42,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) {
image->writeMetadata();
} catch(...) {
} catch (...) {
// Exiv2 throws an exception if the metadata is invalid.
}

File diff suppressed because it is too large Load Diff

@ -12,168 +12,155 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2
{
EXIV2API bool enableBMFF(bool enable = true);
namespace Exiv2 {
EXIV2API bool enableBMFF(bool enable = true);
}
#ifdef EXV_ENABLE_BMFF
namespace Exiv2
{
struct Iloc
{
explicit Iloc(uint32_t ID = 0, uint32_t start = 0, uint32_t length = 0)
: ID_(ID), start_(start), length_(length){};
virtual ~Iloc() = default;
uint32_t ID_;
uint32_t start_;
uint32_t length_;
std::string toString() const;
}; // class Iloc
// *****************************************************************************
// class definitions
/*!
@brief Class to access BMFF images.
*/
class EXIV2API BmffImage : public Image
{
public:
//! @name Creators
//@{
/*!
@brief Constructor to open a BMFF image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
BmffImage(BasicIo::UniquePtr io, bool create);
//@}
//@{
/*!
@brief parse embedded tiff file (Exif metadata)
@param root_tag root of parse tree Tag::root, Tag::cmt2 etc.
@param length tiff block length
@param start offset in file (default, io_->tell())
@
*/
void parseTiff(uint32_t root_tag, uint64_t length);
void parseTiff(uint32_t root_tag, uint64_t length,uint64_t start);
//@}
//@{
/*!
@brief parse embedded xmp/xml
@param length xmp block length
@param start offset in file
@
*/
void parseXmp(uint64_t length,uint64_t start);
//@}
//@{
/*!
@brief Parse a Canon PRVW or THMB box and add an entry to the set
of native previews.
@param data Buffer containing the box
@param out Logging stream
@param bTrace Controls logging
@param width_offset Index of image width field in data
@param height_offset Index of image height field in data
@param size_offset Index of image size field in data
@param relative_position Location of the start of image data in the file,
relative to the current file position indicator.
*/
void parseCr3Preview(DataBuf &data,
std::ostream &out,
bool bTrace,
uint8_t version,
size_t width_offset,
size_t height_offset,
size_t size_offset,
size_t relative_position);
//@}
//! @name Manipulators
//@{
void readMetadata() override /* override */;
void writeMetadata() override /* override */;
void setComment(std::string_view comment) override /* override */;
void printStructure(std::ostream& out, Exiv2::PrintStructureOption option, int depth) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override /* override */;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
Exiv2::ByteOrder endian_{Exiv2::bigEndian};
private:
void openOrThrow();
/*!
@brief recursiveBoxHandler
@throw Error if we visit a box more than once
@param pbox_end The end location of the parent box. Boxes are
nested, so we must not read beyond this.
@return address of next box
@warning This function should only be called by readMetadata()
*/
long boxHandler(std::ostream& out, Exiv2::PrintStructureOption option,
const long pbox_end, int depth);
std::string indent(int i)
{
return std::string(2*i,' ');
}
uint32_t fileType_{0};
std::set<uint64_t> visits_;
uint64_t visits_max_{0};
uint16_t unknownID_{0xffff};
uint16_t exifID_{0xffff};
uint16_t xmpID_{0};
std::map<uint32_t, Iloc> ilocs_;
bool bReadMetadata_{false};
//@}
/*!
@brief box utilities
*/
static std::string toAscii(long n);
std::string boxName(uint32_t box);
static bool superBox(uint32_t box);
static bool fullBox(uint32_t box);
static std::string uuidName(Exiv2::DataBuf& uuid);
}; // class BmffImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new BMFF instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newBmffInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a BMFF image.
EXIV2API bool isBmffType(BasicIo& iIo, bool advance);
namespace Exiv2 {
struct Iloc {
explicit Iloc(uint32_t ID = 0, uint32_t start = 0, uint32_t length = 0) : ID_(ID), start_(start), length_(length){};
virtual ~Iloc() = default;
uint32_t ID_;
uint32_t start_;
uint32_t length_;
std::string toString() const;
}; // class Iloc
// *****************************************************************************
// class definitions
/*!
@brief Class to access BMFF images.
*/
class EXIV2API BmffImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor to open a BMFF image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
BmffImage(BasicIo::UniquePtr io, bool create);
//@}
//@{
/*!
@brief parse embedded tiff file (Exif metadata)
@param root_tag root of parse tree Tag::root, Tag::cmt2 etc.
@param length tiff block length
@param start offset in file (default, io_->tell())
@
*/
void parseTiff(uint32_t root_tag, uint64_t length);
void parseTiff(uint32_t root_tag, uint64_t length, uint64_t start);
//@}
//@{
/*!
@brief parse embedded xmp/xml
@param length xmp block length
@param start offset in file
@
*/
void parseXmp(uint64_t length, uint64_t start);
//@}
//@{
/*!
@brief Parse a Canon PRVW or THMB box and add an entry to the set
of native previews.
@param data Buffer containing the box
@param out Logging stream
@param bTrace Controls logging
@param width_offset Index of image width field in data
@param height_offset Index of image height field in data
@param size_offset Index of image size field in data
@param relative_position Location of the start of image data in the file,
relative to the current file position indicator.
*/
void parseCr3Preview(DataBuf& data, std::ostream& out, bool bTrace, uint8_t version, size_t width_offset,
size_t height_offset, size_t size_offset, size_t relative_position);
//@}
//! @name Manipulators
//@{
void readMetadata() override /* override */;
void writeMetadata() override /* override */;
void setComment(std::string_view comment) override /* override */;
void printStructure(std::ostream& out, Exiv2::PrintStructureOption option, int depth) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override /* override */;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
Exiv2::ByteOrder endian_{Exiv2::bigEndian};
private:
void openOrThrow();
/*!
@brief recursiveBoxHandler
@throw Error if we visit a box more than once
@param pbox_end The end location of the parent box. Boxes are
nested, so we must not read beyond this.
@return address of next box
@warning This function should only be called by readMetadata()
*/
long boxHandler(std::ostream& out, Exiv2::PrintStructureOption option, const long pbox_end, int depth);
std::string indent(int i) {
return std::string(2 * i, ' ');
}
uint32_t fileType_{0};
std::set<uint64_t> visits_;
uint64_t visits_max_{0};
uint16_t unknownID_{0xffff};
uint16_t exifID_{0xffff};
uint16_t xmpID_{0};
std::map<uint32_t, Iloc> ilocs_;
bool bReadMetadata_{false};
//@}
/*!
@brief box utilities
*/
static std::string toAscii(long n);
std::string boxName(uint32_t box);
static bool superBox(uint32_t box);
static bool fullBox(uint32_t box);
static std::string uuidName(Exiv2::DataBuf& uuid);
}; // class BmffImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new BMFF instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newBmffInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a BMFF image.
EXIV2API bool isBmffType(BasicIo& iIo, bool advance);
} // namespace Exiv2
#endif // EXV_ENABLE_BMFF
#endif // EXV_ENABLE_BMFF

@ -17,79 +17,78 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access Windows bitmaps. This is just a stub - we only
read width and height.
*/
class EXIV2API BmpImage : public Image {
public:
//! @name NOT Implemented
//@{
//! Copy constructor
BmpImage(const BmpImage& rhs) = delete;
//! Assignment operator
BmpImage& operator=(const BmpImage& rhs) = delete;
//@}
//! @name Creators
//@{
/*!
@brief Constructor to open a Windows bitmap image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
explicit BmpImage(BasicIo::UniquePtr io);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
/// @throws Error(ErrorCode::kerWritingImageFormatUnsupported).
void writeMetadata() override;
/// @throws Error(ErrorCode::kerInvalidSettingForImage)
void setExifData(const ExifData& exifData) override;
/// @throws Error(ErrorCode::kerInvalidSettingForImage)
void setIptcData(const IptcData& iptcData) override;
/// @throws Error(ErrorCode::kerInvalidSettingForImage)
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
}; // class BmpImage
/*!
@brief Class to access Windows bitmaps. This is just a stub - we only
read width and height.
*/
class EXIV2API BmpImage : public Image {
public:
//! @name NOT Implemented
//@{
//! Copy constructor
BmpImage(const BmpImage& rhs) = delete;
//! Assignment operator
BmpImage& operator=(const BmpImage& rhs) = delete;
//@}
//! @name Creators
//@{
/*!
@brief Constructor to open a Windows bitmap image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
explicit BmpImage(BasicIo::UniquePtr io);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
/// @throws Error(ErrorCode::kerWritingImageFormatUnsupported).
void writeMetadata() override;
/// @throws Error(ErrorCode::kerInvalidSettingForImage)
void setExifData(const ExifData& exifData) override;
/// @throws Error(ErrorCode::kerInvalidSettingForImage)
void setIptcData(const IptcData& iptcData) override;
/// @throws Error(ErrorCode::kerInvalidSettingForImage)
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
}; // class BmpImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new BmpImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newBmpInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new BmpImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newBmpInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a Windows Bitmap image.
EXIV2API bool isBmpType(BasicIo& iIo, bool advance);
//! Check if the file iIo is a Windows Bitmap image.
EXIV2API bool isBmpType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef BMPIMAGE_HPP_
#endif // #ifndef BMPIMAGE_HPP_

@ -4,12 +4,12 @@
#define _CONFIG_H_
///// Start of Visual Studio Support /////
#ifdef _MSC_VER
#ifdef _MSC_VER
#pragma warning(disable : 4996) // Disable warnings about 'deprecated' standard functions
#pragma warning(disable : 4251) // Disable warnings from std templates about exporting interfaces
#pragma warning(disable : 4996) // Disable warnings about 'deprecated' standard functions
#pragma warning(disable : 4251) // Disable warnings from std templates about exporting interfaces
#endif // _MSC_VER
#endif // _MSC_VER
///// End of Visual Studio Support /////
#include "exv_conf.h"
@ -17,32 +17,32 @@
///// Start of platform macros /////////
#if defined(__MINGW32__) || defined(__MINGW64__)
# ifndef __MING__
# define __MING__ 1
# endif
# ifndef __MINGW__
# define __MINGW__ 1
# endif
#ifndef __MING__
#define __MING__ 1
#endif
#ifndef __MINGW__
#define __MINGW__ 1
#endif
#endif
#ifndef __CYGWIN__
# if defined(__CYGWIN32__) || defined(__CYGWIN64__)
# define __CYGWIN__ 1
# endif
#if defined(__CYGWIN32__) || defined(__CYGWIN64__)
#define __CYGWIN__ 1
#endif
#endif
#ifndef __LITTLE_ENDIAN__
# if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define __LITTLE_ENDIAN__ 1
# endif
# endif
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define __LITTLE_ENDIAN__ 1
#endif
#endif
#endif
#ifndef __LITTLE_ENDIAN__
# if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW__)
# define __LITTLE_ENDIAN__ 1
# endif
#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW__)
#define __LITTLE_ENDIAN__ 1
#endif
#endif
/*
@ -50,26 +50,26 @@
you must -library=stdcxx4 along with these inclusions below
*/
#if defined(OS_SOLARIS)
# include <string.h>
# include <strings.h>
# include <math.h>
# if defined(__cplusplus)
# include <ios>
# include <fstream>
# endif
#include <math.h>
#include <string.h>
#include <strings.h>
#if defined(__cplusplus)
#include <fstream>
#include <ios>
#endif
#endif
///// End of platform macros /////////
///// Path separator macros /////
#ifndef EXV_SEPARATOR_STR
# if defined(WIN32) && !defined(__CYGWIN__)
# define EXV_SEPARATOR_STR "\\"
# define EXV_SEPARATOR_CHR '\\'
# else
# define EXV_SEPARATOR_STR "/"
# define EXV_SEPARATOR_CHR '/'
# endif
#if defined(WIN32) && !defined(__CYGWIN__)
#define EXV_SEPARATOR_STR "\\"
#define EXV_SEPARATOR_CHR '\\'
#else
#define EXV_SEPARATOR_STR "/"
#define EXV_SEPARATOR_CHR '/'
#endif
#endif
//////////////////////////////////////
#endif // _CONFIG_H_
#endif // _CONFIG_H_

@ -24,75 +24,74 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class ExifData;
class IptcData;
class XmpData;
class ExifData;
class IptcData;
class XmpData;
// *****************************************************************************
// free functions, template and inline definitions
//! Convert (copy) Exif tags to XMP properties.
EXIV2API void copyExifToXmp(const ExifData& exifData, XmpData& xmpData);
//! Convert (move) Exif tags to XMP properties, remove converted Exif tags.
EXIV2API void moveExifToXmp(ExifData& exifData, XmpData& xmpData);
//! Convert (copy) XMP properties to Exif tags.
EXIV2API void copyXmpToExif(const XmpData& xmpData, ExifData& exifData);
//! Convert (move) XMP properties to Exif tags, remove converted XMP properties.
EXIV2API void moveXmpToExif(XmpData& xmpData, ExifData& exifData);
//! Detect which metadata are newer and perform a copy in appropriate direction.
EXIV2API void syncExifWithXmp(ExifData& exifData, XmpData& xmpData);
//! Convert (copy) IPTC datasets to XMP properties.
EXIV2API void copyIptcToXmp(const IptcData& iptcData, XmpData& xmpData, const char* iptcCharset = nullptr);
//! Convert (move) IPTC datasets to XMP properties, remove converted IPTC datasets.
EXIV2API void moveIptcToXmp(IptcData& iptcData, XmpData& xmpData, const char* iptcCharset = nullptr);
//! Convert (copy) XMP properties to IPTC datasets.
EXIV2API void copyXmpToIptc(const XmpData& xmpData, IptcData& iptcData);
//! Convert (move) XMP properties to IPTC tags, remove converted XMP properties.
EXIV2API void moveXmpToIptc(XmpData& xmpData, IptcData& iptcData);
/*!
@brief Convert character encoding of \em str from \em from to \em to.
If the function succeeds, \em str contains the result string.
This function uses the iconv library, if the %Exiv2 library was compiled
with iconv support. Otherwise, on Windows, it uses Windows functions to
support a limited number of conversions and fails with a warning if an
unsupported conversion is attempted. If the function is called but %Exiv2
was not compiled with iconv support and can't use Windows functions, it
fails with a warning.
The conversions supported on Windows without iconv are:
<TABLE>
<TR><TD><B>from</B></TD><TD><B>to</B></TD></TR>
<TR><TD>UTF-8</TD> <TD>UCS-2BE</TD></TR>
<TR><TD>UTF-8</TD> <TD>UCS-2LE</TD></TR>
<TR><TD>UCS-2BE</TD> <TD>UTF-8</TD></TR>
<TR><TD>UCS-2BE</TD> <TD>UCS-2LE</TD></TR>
<TR><TD>UCS-2LE</TD> <TD>UTF-8</TD></TR>
<TR><TD>UCS-2LE</TD> <TD>UCS-2BE</TD></TR>
<TR><TD>ISO-8859-1</TD><TD>UTF-8</TD></TR>
<TR><TD>ASCII</TD> <TD>UTF-8</TD></TR>
</TABLE>
@param str The string to convert. It is updated to the converted string,
which may have a different size. If the function call fails,
the string is not modified.
@param from Charset in which the input string is encoded as a name
understood by \c iconv_open(3).
@param to Charset to convert the string to as a name
understood by \c iconv_open(3).
@return Return \c true if the conversion was successful, else \c false.
*/
EXIV2API bool convertStringCharset(std::string& str, const char* from, const char* to);
} // namespace Exiv2
#endif // #ifndef CONVERT_HPP_
//! Convert (copy) Exif tags to XMP properties.
EXIV2API void copyExifToXmp(const ExifData& exifData, XmpData& xmpData);
//! Convert (move) Exif tags to XMP properties, remove converted Exif tags.
EXIV2API void moveExifToXmp(ExifData& exifData, XmpData& xmpData);
//! Convert (copy) XMP properties to Exif tags.
EXIV2API void copyXmpToExif(const XmpData& xmpData, ExifData& exifData);
//! Convert (move) XMP properties to Exif tags, remove converted XMP properties.
EXIV2API void moveXmpToExif(XmpData& xmpData, ExifData& exifData);
//! Detect which metadata are newer and perform a copy in appropriate direction.
EXIV2API void syncExifWithXmp(ExifData& exifData, XmpData& xmpData);
//! Convert (copy) IPTC datasets to XMP properties.
EXIV2API void copyIptcToXmp(const IptcData& iptcData, XmpData& xmpData, const char* iptcCharset = nullptr);
//! Convert (move) IPTC datasets to XMP properties, remove converted IPTC datasets.
EXIV2API void moveIptcToXmp(IptcData& iptcData, XmpData& xmpData, const char* iptcCharset = nullptr);
//! Convert (copy) XMP properties to IPTC datasets.
EXIV2API void copyXmpToIptc(const XmpData& xmpData, IptcData& iptcData);
//! Convert (move) XMP properties to IPTC tags, remove converted XMP properties.
EXIV2API void moveXmpToIptc(XmpData& xmpData, IptcData& iptcData);
/*!
@brief Convert character encoding of \em str from \em from to \em to.
If the function succeeds, \em str contains the result string.
This function uses the iconv library, if the %Exiv2 library was compiled
with iconv support. Otherwise, on Windows, it uses Windows functions to
support a limited number of conversions and fails with a warning if an
unsupported conversion is attempted. If the function is called but %Exiv2
was not compiled with iconv support and can't use Windows functions, it
fails with a warning.
The conversions supported on Windows without iconv are:
<TABLE>
<TR><TD><B>from</B></TD><TD><B>to</B></TD></TR>
<TR><TD>UTF-8</TD> <TD>UCS-2BE</TD></TR>
<TR><TD>UTF-8</TD> <TD>UCS-2LE</TD></TR>
<TR><TD>UCS-2BE</TD> <TD>UTF-8</TD></TR>
<TR><TD>UCS-2BE</TD> <TD>UCS-2LE</TD></TR>
<TR><TD>UCS-2LE</TD> <TD>UTF-8</TD></TR>
<TR><TD>UCS-2LE</TD> <TD>UCS-2BE</TD></TR>
<TR><TD>ISO-8859-1</TD><TD>UTF-8</TD></TR>
<TR><TD>ASCII</TD> <TD>UTF-8</TD></TR>
</TABLE>
@param str The string to convert. It is updated to the converted string,
which may have a different size. If the function call fails,
the string is not modified.
@param from Charset in which the input string is encoded as a name
understood by \c iconv_open(3).
@param to Charset to convert the string to as a name
understood by \c iconv_open(3).
@return Return \c true if the conversion was successful, else \c false.
*/
EXIV2API bool convertStringCharset(std::string& str, const char* from, const char* to);
} // namespace Exiv2
#endif // #ifndef CONVERT_HPP_

@ -17,120 +17,107 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access raw Canon CR2 images. Exif metadata
is supported directly, IPTC is read from the Exif data, if present.
*/
class EXIV2API Cr2Image : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing CR2 image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
Cr2Image(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Print out the structure of image file.
@throw Error if reading of the file fails or the image data is
not valid (does not look like data of the specific image type).
@warning This function is not thread safe and intended for exiv2 -pS for debugging.
*/
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
/*!
@brief Not supported. CR2 format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
//! @name NOT implemented
//@{
//! Copy constructor
Cr2Image(const Cr2Image& rhs) = delete;
//! Assignment operator
Cr2Image& operator=(const Cr2Image& rhs) = delete;
//@}
}; // class Cr2Image
/*!
@brief Stateless parser class for data in CR2 format. Images use this
class to decode and encode CR2 data.
See class TiffParser for details.
*/
class EXIV2API Cr2Parser {
public:
/*!
@brief Decode metadata from a buffer \em pData of length \em size
with data in CR2 format to the provided metadata containers.
See TiffParser::decode().
*/
static ByteOrder decode(
ExifData& exifData,
IptcData& iptcData,
XmpData& xmpData,
const byte* pData,
size_t size
);
/*!
@brief Encode metadata from the provided metadata to CR2 format.
See TiffParser::encode().
*/
static WriteMethod encode(BasicIo& io,
const byte* pData,
size_t size,
ByteOrder byteOrder,
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData
);
}; // class Cr2Parser
/*!
@brief Class to access raw Canon CR2 images. Exif metadata
is supported directly, IPTC is read from the Exif data, if present.
*/
class EXIV2API Cr2Image : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing CR2 image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
Cr2Image(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Print out the structure of image file.
@throw Error if reading of the file fails or the image data is
not valid (does not look like data of the specific image type).
@warning This function is not thread safe and intended for exiv2 -pS for debugging.
*/
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
/*!
@brief Not supported. CR2 format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
//! @name NOT implemented
//@{
//! Copy constructor
Cr2Image(const Cr2Image& rhs) = delete;
//! Assignment operator
Cr2Image& operator=(const Cr2Image& rhs) = delete;
//@}
}; // class Cr2Image
/*!
@brief Stateless parser class for data in CR2 format. Images use this
class to decode and encode CR2 data.
See class TiffParser for details.
*/
class EXIV2API Cr2Parser {
public:
/*!
@brief Decode metadata from a buffer \em pData of length \em size
with data in CR2 format to the provided metadata containers.
See TiffParser::decode().
*/
static ByteOrder decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, size_t size);
/*!
@brief Encode metadata from the provided metadata to CR2 format.
See TiffParser::encode().
*/
static WriteMethod encode(BasicIo& io, const byte* pData, size_t size, ByteOrder byteOrder, const ExifData& exifData,
const IptcData& iptcData, const XmpData& xmpData);
}; // class Cr2Parser
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new Cr2Image instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newCr2Instance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new Cr2Image instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newCr2Instance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a CR2 image.
EXIV2API bool isCr2Type(BasicIo& iIo, bool advance);
//! Check if the file iIo is a CR2 image.
EXIV2API bool isCr2Type(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef CR2IMAGE_HPP_
#endif // #ifndef CR2IMAGE_HPP_

@ -3,7 +3,8 @@
/*!
@brief Class CrwImage to access Canon CRW images.<BR>
References:<BR>
<a href="http://www.sno.phy.queensu.ca/~phil/exiftool/canon_raw.html">The Canon RAW (CRW) File Format</a> by Phil Harvey
<a href="http://www.sno.phy.queensu.ca/~phil/exiftool/canon_raw.html">The Canon RAW (CRW) File Format</a> by
Phil Harvey
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 28-Aug-05, ahu: created
@ -20,127 +21,122 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class ExifData;
class IptcData;
class ExifData;
class IptcData;
// *****************************************************************************
// class definitions
/*!
@brief Class to access raw Canon CRW images. Only Exif metadata and a
comment are supported. CRW format does not contain IPTC metadata.
*/
class EXIV2API CrwImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing CRW image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
CrwImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Not supported. CRW format does not contain IPTC metadata.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setIptcData(const IptcData& iptcData) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
//! @name NOT Implemented
//@{
//! Copy constructor
CrwImage(const CrwImage& rhs) = delete;
//! Assignment operator
CrwImage& operator=(const CrwImage& rhs) = delete;
//@}
}; // class CrwImage
/*!
Stateless parser class for Canon CRW images (Ciff format).
*/
class EXIV2API CrwParser {
public:
/*!
@brief Decode metadata from a Canon CRW image in data buffer \em pData
of length \em size into \em crwImage.
This is the entry point to access image data in Ciff format. The
parser uses classes CiffHeader, CiffEntry, CiffDirectory.
@param pCrwImage Pointer to the %Exiv2 CRW image to hold the metadata
read from the buffer.
@param pData Pointer to the data buffer. Must point to the data of
a CRW image; no checks are performed.
@param size Length of the data buffer.
@throw Error If the data buffer cannot be parsed.
*/
static void decode(CrwImage* pCrwImage, const byte* pData, size_t size);
/*!
@brief Encode metadata from the CRW image into a data buffer (the
binary CRW image).
@param blob Data buffer for the binary image (target).
@param pData Pointer to the binary image data buffer. Must
point to data in CRW format; no checks are
performed.
@param size Length of the data buffer.
@param pCrwImage Pointer to the %Exiv2 CRW image with the metadata to
encode.
@throw Error If the metadata from the CRW image cannot be encoded.
*/
static void encode(Blob& blob,
const byte* pData,
size_t size,
const CrwImage* pCrwImage
);
}; // class CrwParser
/*!
@brief Class to access raw Canon CRW images. Only Exif metadata and a
comment are supported. CRW format does not contain IPTC metadata.
*/
class EXIV2API CrwImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing CRW image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
CrwImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Not supported. CRW format does not contain IPTC metadata.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setIptcData(const IptcData& iptcData) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
//! @name NOT Implemented
//@{
//! Copy constructor
CrwImage(const CrwImage& rhs) = delete;
//! Assignment operator
CrwImage& operator=(const CrwImage& rhs) = delete;
//@}
}; // class CrwImage
/*!
Stateless parser class for Canon CRW images (Ciff format).
*/
class EXIV2API CrwParser {
public:
/*!
@brief Decode metadata from a Canon CRW image in data buffer \em pData
of length \em size into \em crwImage.
This is the entry point to access image data in Ciff format. The
parser uses classes CiffHeader, CiffEntry, CiffDirectory.
@param pCrwImage Pointer to the %Exiv2 CRW image to hold the metadata
read from the buffer.
@param pData Pointer to the data buffer. Must point to the data of
a CRW image; no checks are performed.
@param size Length of the data buffer.
@throw Error If the data buffer cannot be parsed.
*/
static void decode(CrwImage* pCrwImage, const byte* pData, size_t size);
/*!
@brief Encode metadata from the CRW image into a data buffer (the
binary CRW image).
@param blob Data buffer for the binary image (target).
@param pData Pointer to the binary image data buffer. Must
point to data in CRW format; no checks are
performed.
@param size Length of the data buffer.
@param pCrwImage Pointer to the %Exiv2 CRW image with the metadata to
encode.
@throw Error If the metadata from the CRW image cannot be encoded.
*/
static void encode(Blob& blob, const byte* pData, size_t size, const CrwImage* pCrwImage);
}; // class CrwParser
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new CrwImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newCrwInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new CrwImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newCrwInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a CRW image.
EXIV2API bool isCrwType(BasicIo& iIo, bool advance);
//! Check if the file iIo is a CRW image.
EXIV2API bool isCrwType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef CRWIMAGE_HPP_
#endif // #ifndef CRWIMAGE_HPP_

@ -16,320 +16,318 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
//! Details of an IPTC record.
struct EXIV2API RecordInfo {
uint16_t recordId_; //!< Record id
const char* name_; //!< Record name (one word)
const char* desc_; //!< Record description
};
//! Details of an IPTC dataset.
struct EXIV2API DataSet {
uint16_t number_; //!< Dataset number
const char* name_; //!< Dataset name
const char* title_; //!< Dataset title or label
const char* desc_; //!< Dataset description
bool mandatory_; //!< True if dataset is mandatory
bool repeatable_; //!< True if dataset is repeatable
uint32_t minbytes_; //!< Minimum number of bytes
uint32_t maxbytes_; //!< Maximum number of bytes
TypeId type_; //!< Exiv2 default type
uint16_t recordId_; //!< Record id
const char* photoshop_; //!< Photoshop string
}; // struct DataSet
//! IPTC dataset reference, implemented as a static class.
class EXIV2API IptcDataSets {
public:
/*!
@name Record identifiers
@brief Record identifiers to logically group dataSets. There are other
possible record types, but they are not standardized by the IPTC
IIM4 standard (and not commonly used in images).
*/
//@{
static constexpr uint16_t invalidRecord = 0;
static constexpr uint16_t envelope = 1;
static constexpr uint16_t application2 = 2;
//@}
//! @name Dataset identifiers
//@{
static constexpr uint16_t ModelVersion = 0;
static constexpr uint16_t Destination = 5;
static constexpr uint16_t FileFormat = 20;
static constexpr uint16_t FileVersion = 22;
static constexpr uint16_t ServiceId = 30;
static constexpr uint16_t EnvelopeNumber = 40;
static constexpr uint16_t ProductId = 50;
static constexpr uint16_t EnvelopePriority = 60;
static constexpr uint16_t DateSent = 70;
static constexpr uint16_t TimeSent = 80;
static constexpr uint16_t CharacterSet = 90;
static constexpr uint16_t UNO = 100;
static constexpr uint16_t ARMId = 120;
static constexpr uint16_t ARMVersion = 122;
static constexpr uint16_t RecordVersion = 0;
static constexpr uint16_t ObjectType = 3;
static constexpr uint16_t ObjectAttribute = 4;
static constexpr uint16_t ObjectName = 5;
static constexpr uint16_t EditStatus = 7;
static constexpr uint16_t EditorialUpdate = 8;
static constexpr uint16_t Urgency = 10;
static constexpr uint16_t Subject = 12;
static constexpr uint16_t Category = 15;
static constexpr uint16_t SuppCategory = 20;
static constexpr uint16_t FixtureId = 22;
static constexpr uint16_t Keywords = 25;
static constexpr uint16_t LocationCode = 26;
static constexpr uint16_t LocationName = 27;
static constexpr uint16_t ReleaseDate = 30;
static constexpr uint16_t ReleaseTime = 35;
static constexpr uint16_t ExpirationDate = 37;
static constexpr uint16_t ExpirationTime = 38;
static constexpr uint16_t SpecialInstructions = 40;
static constexpr uint16_t ActionAdvised = 42;
static constexpr uint16_t ReferenceService = 45;
static constexpr uint16_t ReferenceDate = 47;
static constexpr uint16_t ReferenceNumber = 50;
static constexpr uint16_t DateCreated = 55;
static constexpr uint16_t TimeCreated = 60;
static constexpr uint16_t DigitizationDate = 62;
static constexpr uint16_t DigitizationTime = 63;
static constexpr uint16_t Program = 65;
static constexpr uint16_t ProgramVersion = 70;
static constexpr uint16_t ObjectCycle = 75;
static constexpr uint16_t Byline = 80;
static constexpr uint16_t BylineTitle = 85;
static constexpr uint16_t City = 90;
static constexpr uint16_t SubLocation = 92;
static constexpr uint16_t ProvinceState = 95;
static constexpr uint16_t CountryCode = 100;
static constexpr uint16_t CountryName = 101;
static constexpr uint16_t TransmissionReference = 103;
static constexpr uint16_t Headline = 105;
static constexpr uint16_t Credit = 110;
static constexpr uint16_t Source = 115;
static constexpr uint16_t Copyright = 116;
static constexpr uint16_t Contact = 118;
static constexpr uint16_t Caption = 120;
static constexpr uint16_t Writer = 122;
static constexpr uint16_t RasterizedCaption = 125;
static constexpr uint16_t ImageType = 130;
static constexpr uint16_t ImageOrientation = 131;
static constexpr uint16_t Language = 135;
static constexpr uint16_t AudioType = 150;
static constexpr uint16_t AudioRate = 151;
static constexpr uint16_t AudioResolution = 152;
static constexpr uint16_t AudioDuration = 153;
static constexpr uint16_t AudioOutcue = 154;
static constexpr uint16_t PreviewFormat = 200;
static constexpr uint16_t PreviewVersion = 201;
static constexpr uint16_t Preview = 202;
//@}
//! Prevent construction: not implemented.
IptcDataSets() = delete;
//! Prevent copy-construction: not implemented.
IptcDataSets(const IptcDataSets& rhs) = delete;
//! Prevent assignment: not implemented.
IptcDataSets& operator=(const IptcDataSets& rhs) = delete;
/*!
@brief Return the name of the dataset.
@param number The dataset number
@param recordId The IPTC record Id
@return The name of the dataset or a string containing the hexadecimal
value of the dataset in the form "0x01ff", if this is an unknown
dataset.
*/
static std::string dataSetName(uint16_t number, uint16_t recordId);
/*!
@brief Return the title (label) of the dataset.
@param number The dataset number
@param recordId The IPTC record Id
@return The title (label) of the dataset
*/
static const char* dataSetTitle(uint16_t number, uint16_t recordId);
/*!
@brief Return the description of the dataset.
@param number The dataset number
@param recordId The IPTC record Id
@return The description of the dataset
*/
static const char* dataSetDesc(uint16_t number, uint16_t recordId);
/*!
@brief Return the Photoshop name of a given dataset.
@param number The dataset number
@param recordId The IPTC record Id
@return The name used by Photoshop for a dataset or an empty
string if Photoshop does not use the dataset.
*/
static const char* dataSetPsName(uint16_t number, uint16_t recordId);
/*!
@brief Check if a given dataset is repeatable
@param number The dataset number
@param recordId The IPTC record Id
@return true if the given dataset is repeatable otherwise false
*/
static bool dataSetRepeatable(uint16_t number, uint16_t recordId);
/*!
@brief Return the dataSet number for dataset name and record id
@param dataSetName dataSet name
@param recordId recordId
@return dataSet number
@throw Error if the \em dataSetName or \em recordId are invalid
*/
static uint16_t dataSet(const std::string& dataSetName, uint16_t recordId);
//! Return the type for dataSet number and Record id
static TypeId dataSetType(uint16_t number, uint16_t recordId);
/*!
@brief Return the name of the Record
@param recordId The record id
@return The name of the record or a string containing the hexadecimal
value of the record in the form "0x01ff", if this is an
unknown record.
*/
static std::string recordName(uint16_t recordId);
/*!
@brief Return the description of a record
@param recordId Record Id number
@return the description of the Record
*/
static const char* recordDesc(uint16_t recordId);
/*!
@brief Return the Id number of a record
@param recordName Name of a record type
@return the Id number of a Record
@throw Error if the record is not known;
*/
static uint16_t recordId(const std::string& recordName);
//! Return read-only list of built-in Envelope Record datasets
static const DataSet* envelopeRecordList();
//! Return read-only list of built-in Application2 Record datasets
static const DataSet* application2RecordList();
//! Print a list of all dataSets to output stream
static void dataSetList(std::ostream& os);
private:
static int dataSetIdx(uint16_t number, uint16_t recordId);
static int dataSetIdx(const std::string& dataSetName, uint16_t recordId);
static const DataSet* const records_[];
}; // class IptcDataSets
/*!
@brief Concrete keys for IPTC metadata.
*/
class EXIV2API IptcKey : public Key {
public:
//! Shortcut for an %IptcKey auto pointer.
using UniquePtr = std::unique_ptr<IptcKey>;
//! @name Creators
//@{
/*!
@brief Constructor to create an IPTC key from a key string.
@param key The key string.
@throw Error if the first part of the key is not '<b>Iptc</b>' or
the remaining parts of the key cannot be parsed and
converted to a record name and a dataset name.
*/
explicit IptcKey(std::string key);
/*!
@brief Constructor to create an IPTC key from dataset and record ids.
@param tag Dataset id
@param record Record id
*/
IptcKey(uint16_t tag, uint16_t record);
//! Copy constructor
IptcKey(const IptcKey& rhs);
IptcKey& operator=(const IptcKey& rhs) = delete;
//! Destructor
~IptcKey() override = default;
//@}
//! @name Accessors
//@{
std::string key() const override;
const char* familyName() const override;
/*!
@brief Return the name of the group (the second part of the key).
For IPTC keys, the group name is the record name.
*/
std::string groupName() const override;
std::string tagName() const override;
std::string tagLabel() const override;
uint16_t tag() const override;
UniquePtr clone() const;
//! Return the name of the record
std::string recordName() const;
//! Return the record id
uint16_t record() const;
//@}
protected:
//! @name Manipulators
//@{
/*!
@brief Set the key corresponding to the dataset and record id.
The key is of the form '<b>Iptc</b>.recordName.dataSetName'.
*/
void makeKey();
/*!
@brief Parse and convert the key string into dataset and record id.
Updates data members if the string can be decomposed, or throws
\em Error.
@throw Error if the key cannot be decomposed.
*/
void decomposeKey();
//@}
private:
//! Internal virtual copy constructor.
IptcKey* clone_() const override;
uint16_t tag_; //!< Tag value
uint16_t record_; //!< Record value
std::string key_; //!< Key
}; // class IptcKey
/*!
@brief typedef for string:string map
*/
using Dictionary = std::map<std::string, std::string>;
// *****************************************************************************
// free functions
//! Output operator for dataSet
EXIV2API std::ostream& operator<<(std::ostream& os, const DataSet& dataSet);
} // namespace Exiv2
#endif // #ifndef DATASETS_HPP_
//! Details of an IPTC record.
struct EXIV2API RecordInfo {
uint16_t recordId_; //!< Record id
const char* name_; //!< Record name (one word)
const char* desc_; //!< Record description
};
//! Details of an IPTC dataset.
struct EXIV2API DataSet {
uint16_t number_; //!< Dataset number
const char* name_; //!< Dataset name
const char* title_; //!< Dataset title or label
const char* desc_; //!< Dataset description
bool mandatory_; //!< True if dataset is mandatory
bool repeatable_; //!< True if dataset is repeatable
uint32_t minbytes_; //!< Minimum number of bytes
uint32_t maxbytes_; //!< Maximum number of bytes
TypeId type_; //!< Exiv2 default type
uint16_t recordId_; //!< Record id
const char* photoshop_; //!< Photoshop string
}; // struct DataSet
//! IPTC dataset reference, implemented as a static class.
class EXIV2API IptcDataSets {
public:
/*!
@name Record identifiers
@brief Record identifiers to logically group dataSets. There are other
possible record types, but they are not standardized by the IPTC
IIM4 standard (and not commonly used in images).
*/
//@{
static constexpr uint16_t invalidRecord = 0;
static constexpr uint16_t envelope = 1;
static constexpr uint16_t application2 = 2;
//@}
//! @name Dataset identifiers
//@{
static constexpr uint16_t ModelVersion = 0;
static constexpr uint16_t Destination = 5;
static constexpr uint16_t FileFormat = 20;
static constexpr uint16_t FileVersion = 22;
static constexpr uint16_t ServiceId = 30;
static constexpr uint16_t EnvelopeNumber = 40;
static constexpr uint16_t ProductId = 50;
static constexpr uint16_t EnvelopePriority = 60;
static constexpr uint16_t DateSent = 70;
static constexpr uint16_t TimeSent = 80;
static constexpr uint16_t CharacterSet = 90;
static constexpr uint16_t UNO = 100;
static constexpr uint16_t ARMId = 120;
static constexpr uint16_t ARMVersion = 122;
static constexpr uint16_t RecordVersion = 0;
static constexpr uint16_t ObjectType = 3;
static constexpr uint16_t ObjectAttribute = 4;
static constexpr uint16_t ObjectName = 5;
static constexpr uint16_t EditStatus = 7;
static constexpr uint16_t EditorialUpdate = 8;
static constexpr uint16_t Urgency = 10;
static constexpr uint16_t Subject = 12;
static constexpr uint16_t Category = 15;
static constexpr uint16_t SuppCategory = 20;
static constexpr uint16_t FixtureId = 22;
static constexpr uint16_t Keywords = 25;
static constexpr uint16_t LocationCode = 26;
static constexpr uint16_t LocationName = 27;
static constexpr uint16_t ReleaseDate = 30;
static constexpr uint16_t ReleaseTime = 35;
static constexpr uint16_t ExpirationDate = 37;
static constexpr uint16_t ExpirationTime = 38;
static constexpr uint16_t SpecialInstructions = 40;
static constexpr uint16_t ActionAdvised = 42;
static constexpr uint16_t ReferenceService = 45;
static constexpr uint16_t ReferenceDate = 47;
static constexpr uint16_t ReferenceNumber = 50;
static constexpr uint16_t DateCreated = 55;
static constexpr uint16_t TimeCreated = 60;
static constexpr uint16_t DigitizationDate = 62;
static constexpr uint16_t DigitizationTime = 63;
static constexpr uint16_t Program = 65;
static constexpr uint16_t ProgramVersion = 70;
static constexpr uint16_t ObjectCycle = 75;
static constexpr uint16_t Byline = 80;
static constexpr uint16_t BylineTitle = 85;
static constexpr uint16_t City = 90;
static constexpr uint16_t SubLocation = 92;
static constexpr uint16_t ProvinceState = 95;
static constexpr uint16_t CountryCode = 100;
static constexpr uint16_t CountryName = 101;
static constexpr uint16_t TransmissionReference = 103;
static constexpr uint16_t Headline = 105;
static constexpr uint16_t Credit = 110;
static constexpr uint16_t Source = 115;
static constexpr uint16_t Copyright = 116;
static constexpr uint16_t Contact = 118;
static constexpr uint16_t Caption = 120;
static constexpr uint16_t Writer = 122;
static constexpr uint16_t RasterizedCaption = 125;
static constexpr uint16_t ImageType = 130;
static constexpr uint16_t ImageOrientation = 131;
static constexpr uint16_t Language = 135;
static constexpr uint16_t AudioType = 150;
static constexpr uint16_t AudioRate = 151;
static constexpr uint16_t AudioResolution = 152;
static constexpr uint16_t AudioDuration = 153;
static constexpr uint16_t AudioOutcue = 154;
static constexpr uint16_t PreviewFormat = 200;
static constexpr uint16_t PreviewVersion = 201;
static constexpr uint16_t Preview = 202;
//@}
//! Prevent construction: not implemented.
IptcDataSets() = delete;
//! Prevent copy-construction: not implemented.
IptcDataSets(const IptcDataSets& rhs) = delete;
//! Prevent assignment: not implemented.
IptcDataSets& operator=(const IptcDataSets& rhs) = delete;
/*!
@brief Return the name of the dataset.
@param number The dataset number
@param recordId The IPTC record Id
@return The name of the dataset or a string containing the hexadecimal
value of the dataset in the form "0x01ff", if this is an unknown
dataset.
*/
static std::string dataSetName(uint16_t number, uint16_t recordId);
/*!
@brief Return the title (label) of the dataset.
@param number The dataset number
@param recordId The IPTC record Id
@return The title (label) of the dataset
*/
static const char* dataSetTitle(uint16_t number, uint16_t recordId);
/*!
@brief Return the description of the dataset.
@param number The dataset number
@param recordId The IPTC record Id
@return The description of the dataset
*/
static const char* dataSetDesc(uint16_t number, uint16_t recordId);
/*!
@brief Return the Photoshop name of a given dataset.
@param number The dataset number
@param recordId The IPTC record Id
@return The name used by Photoshop for a dataset or an empty
string if Photoshop does not use the dataset.
*/
static const char* dataSetPsName(uint16_t number, uint16_t recordId);
/*!
@brief Check if a given dataset is repeatable
@param number The dataset number
@param recordId The IPTC record Id
@return true if the given dataset is repeatable otherwise false
*/
static bool dataSetRepeatable(uint16_t number, uint16_t recordId);
/*!
@brief Return the dataSet number for dataset name and record id
@param dataSetName dataSet name
@param recordId recordId
@return dataSet number
@throw Error if the \em dataSetName or \em recordId are invalid
*/
static uint16_t dataSet(const std::string& dataSetName, uint16_t recordId);
//! Return the type for dataSet number and Record id
static TypeId dataSetType(uint16_t number, uint16_t recordId);
/*!
@brief Return the name of the Record
@param recordId The record id
@return The name of the record or a string containing the hexadecimal
value of the record in the form "0x01ff", if this is an
unknown record.
*/
static std::string recordName(uint16_t recordId);
/*!
@brief Return the description of a record
@param recordId Record Id number
@return the description of the Record
*/
static const char* recordDesc(uint16_t recordId);
/*!
@brief Return the Id number of a record
@param recordName Name of a record type
@return the Id number of a Record
@throw Error if the record is not known;
*/
static uint16_t recordId(const std::string& recordName);
//! Return read-only list of built-in Envelope Record datasets
static const DataSet* envelopeRecordList();
//! Return read-only list of built-in Application2 Record datasets
static const DataSet* application2RecordList();
//! Print a list of all dataSets to output stream
static void dataSetList(std::ostream& os);
private:
static int dataSetIdx(uint16_t number, uint16_t recordId);
static int dataSetIdx(const std::string& dataSetName, uint16_t recordId);
static const DataSet* const records_[];
}; // class IptcDataSets
/*!
@brief Concrete keys for IPTC metadata.
*/
class EXIV2API IptcKey : public Key {
public:
//! Shortcut for an %IptcKey auto pointer.
using UniquePtr = std::unique_ptr<IptcKey>;
//! @name Creators
//@{
/*!
@brief Constructor to create an IPTC key from a key string.
@param key The key string.
@throw Error if the first part of the key is not '<b>Iptc</b>' or
the remaining parts of the key cannot be parsed and
converted to a record name and a dataset name.
*/
explicit IptcKey(std::string key);
/*!
@brief Constructor to create an IPTC key from dataset and record ids.
@param tag Dataset id
@param record Record id
*/
IptcKey(uint16_t tag, uint16_t record);
//! Copy constructor
IptcKey(const IptcKey& rhs);
IptcKey& operator=(const IptcKey& rhs) = delete;
//! Destructor
~IptcKey() override = default;
//@}
//! @name Accessors
//@{
std::string key() const override;
const char* familyName() const override;
/*!
@brief Return the name of the group (the second part of the key).
For IPTC keys, the group name is the record name.
*/
std::string groupName() const override;
std::string tagName() const override;
std::string tagLabel() const override;
uint16_t tag() const override;
UniquePtr clone() const;
//! Return the name of the record
std::string recordName() const;
//! Return the record id
uint16_t record() const;
//@}
protected:
//! @name Manipulators
//@{
/*!
@brief Set the key corresponding to the dataset and record id.
The key is of the form '<b>Iptc</b>.recordName.dataSetName'.
*/
void makeKey();
/*!
@brief Parse and convert the key string into dataset and record id.
Updates data members if the string can be decomposed, or throws
\em Error.
@throw Error if the key cannot be decomposed.
*/
void decomposeKey();
//@}
private:
//! Internal virtual copy constructor.
IptcKey* clone_() const override;
uint16_t tag_; //!< Tag value
uint16_t record_; //!< Record value
std::string key_; //!< Key
}; // class IptcKey
/*!
@brief typedef for string:string map
*/
using Dictionary = std::map<std::string, std::string>;
// *****************************************************************************
// free functions
//! Output operator for dataSet
EXIV2API std::ostream& operator<<(std::ostream& os, const DataSet& dataSet);
} // namespace Exiv2
#endif // #ifndef DATASETS_HPP_

@ -15,80 +15,79 @@
#include "exif.hpp"
namespace Exiv2 {
// *****************************************************************************
// class declarations
class ExifData;
class ExifData;
//! Return the orientation of the image
EXIV2API ExifData::const_iterator orientation(const ExifData& ed);
//! Return the ISO speed used to shoot the image
EXIV2API ExifData::const_iterator isoSpeed(const ExifData& ed);
//! Return the date and time when the original image data was generated
EXIV2API ExifData::const_iterator dateTimeOriginal(const ExifData& ed);
//! Return the flash bias value
EXIV2API ExifData::const_iterator flashBias(const ExifData& ed);
//! Return the exposure mode setting
EXIV2API ExifData::const_iterator exposureMode(const ExifData& ed);
//! Return the scene mode setting
EXIV2API ExifData::const_iterator sceneMode(const ExifData& ed);
//! Return the macro mode setting
EXIV2API ExifData::const_iterator macroMode(const ExifData& ed);
//! Return the image quality setting
EXIV2API ExifData::const_iterator imageQuality(const ExifData& ed);
//! Return the white balance setting
EXIV2API ExifData::const_iterator whiteBalance(const ExifData& ed);
//! Return the name of the lens used
EXIV2API ExifData::const_iterator lensName(const ExifData& ed);
//! Return the saturation level
EXIV2API ExifData::const_iterator saturation(const ExifData& ed);
//! Return the sharpness level
EXIV2API ExifData::const_iterator sharpness(const ExifData& ed);
//! Return the contrast level
EXIV2API ExifData::const_iterator contrast(const ExifData& ed);
//! Return the scene capture type
EXIV2API ExifData::const_iterator sceneCaptureType(const ExifData& ed);
//! Return the metering mode setting
EXIV2API ExifData::const_iterator meteringMode(const ExifData& ed);
//! Return the camera make
EXIV2API ExifData::const_iterator make(const ExifData& ed);
//! Return the camera model
EXIV2API ExifData::const_iterator model(const ExifData& ed);
//! Return the exposure time
EXIV2API ExifData::const_iterator exposureTime(const ExifData& ed);
//! Return the F number
EXIV2API ExifData::const_iterator fNumber(const ExifData& ed);
//! Return the shutter speed value
EXIV2API ExifData::const_iterator shutterSpeedValue(const ExifData& ed);
//! Return the aperture value
EXIV2API ExifData::const_iterator apertureValue(const ExifData& ed);
//! Return the brightness value
EXIV2API ExifData::const_iterator brightnessValue(const ExifData& ed);
//! Return the exposure bias value
EXIV2API ExifData::const_iterator exposureBiasValue(const ExifData& ed);
//! Return the max aperture value
EXIV2API ExifData::const_iterator maxApertureValue(const ExifData& ed);
//! Return the subject distance
EXIV2API ExifData::const_iterator subjectDistance(const ExifData& ed);
//! Return the kind of light source
EXIV2API ExifData::const_iterator lightSource(const ExifData& ed);
//! Return the status of flash
EXIV2API ExifData::const_iterator flash(const ExifData& ed);
//! Return the camera serial number
EXIV2API ExifData::const_iterator serialNumber(const ExifData& ed);
//! Return the focal length setting
EXIV2API ExifData::const_iterator focalLength(const ExifData& ed);
//! Return the subject location and area
EXIV2API ExifData::const_iterator subjectArea(const ExifData& ed);
//! Return the flash energy
EXIV2API ExifData::const_iterator flashEnergy(const ExifData& ed);
//! Return the exposure index
EXIV2API ExifData::const_iterator exposureIndex(const ExifData& ed);
//! Return the image sensor type
EXIV2API ExifData::const_iterator sensingMethod(const ExifData& ed);
//! Return the AF point
EXIV2API ExifData::const_iterator afPoint(const ExifData& ed);
//! Return the orientation of the image
EXIV2API ExifData::const_iterator orientation(const ExifData& ed);
//! Return the ISO speed used to shoot the image
EXIV2API ExifData::const_iterator isoSpeed(const ExifData& ed);
//! Return the date and time when the original image data was generated
EXIV2API ExifData::const_iterator dateTimeOriginal(const ExifData& ed);
//! Return the flash bias value
EXIV2API ExifData::const_iterator flashBias(const ExifData& ed);
//! Return the exposure mode setting
EXIV2API ExifData::const_iterator exposureMode(const ExifData& ed);
//! Return the scene mode setting
EXIV2API ExifData::const_iterator sceneMode(const ExifData& ed);
//! Return the macro mode setting
EXIV2API ExifData::const_iterator macroMode(const ExifData& ed);
//! Return the image quality setting
EXIV2API ExifData::const_iterator imageQuality(const ExifData& ed);
//! Return the white balance setting
EXIV2API ExifData::const_iterator whiteBalance(const ExifData& ed);
//! Return the name of the lens used
EXIV2API ExifData::const_iterator lensName(const ExifData& ed);
//! Return the saturation level
EXIV2API ExifData::const_iterator saturation(const ExifData& ed);
//! Return the sharpness level
EXIV2API ExifData::const_iterator sharpness(const ExifData& ed);
//! Return the contrast level
EXIV2API ExifData::const_iterator contrast(const ExifData& ed);
//! Return the scene capture type
EXIV2API ExifData::const_iterator sceneCaptureType(const ExifData& ed);
//! Return the metering mode setting
EXIV2API ExifData::const_iterator meteringMode(const ExifData& ed);
//! Return the camera make
EXIV2API ExifData::const_iterator make(const ExifData& ed);
//! Return the camera model
EXIV2API ExifData::const_iterator model(const ExifData& ed);
//! Return the exposure time
EXIV2API ExifData::const_iterator exposureTime(const ExifData& ed);
//! Return the F number
EXIV2API ExifData::const_iterator fNumber(const ExifData& ed);
//! Return the shutter speed value
EXIV2API ExifData::const_iterator shutterSpeedValue(const ExifData& ed);
//! Return the aperture value
EXIV2API ExifData::const_iterator apertureValue(const ExifData& ed);
//! Return the brightness value
EXIV2API ExifData::const_iterator brightnessValue(const ExifData& ed);
//! Return the exposure bias value
EXIV2API ExifData::const_iterator exposureBiasValue(const ExifData& ed);
//! Return the max aperture value
EXIV2API ExifData::const_iterator maxApertureValue(const ExifData& ed);
//! Return the subject distance
EXIV2API ExifData::const_iterator subjectDistance(const ExifData& ed);
//! Return the kind of light source
EXIV2API ExifData::const_iterator lightSource(const ExifData& ed);
//! Return the status of flash
EXIV2API ExifData::const_iterator flash(const ExifData& ed);
//! Return the camera serial number
EXIV2API ExifData::const_iterator serialNumber(const ExifData& ed);
//! Return the focal length setting
EXIV2API ExifData::const_iterator focalLength(const ExifData& ed);
//! Return the subject location and area
EXIV2API ExifData::const_iterator subjectArea(const ExifData& ed);
//! Return the flash energy
EXIV2API ExifData::const_iterator flashEnergy(const ExifData& ed);
//! Return the exposure index
EXIV2API ExifData::const_iterator exposureIndex(const ExifData& ed);
//! Return the image sensor type
EXIV2API ExifData::const_iterator sensingMethod(const ExifData& ed);
//! Return the AF point
EXIV2API ExifData::const_iterator afPoint(const ExifData& ed);
} // namespace Exiv2
} // namespace Exiv2
#endif // EASYACCESS_HPP_
#endif // EASYACCESS_HPP_

@ -4,10 +4,14 @@
@file epsimage.hpp
@brief EPS image.
<br>References:
<br>[1] <a href="http://partners.adobe.com/public/developer/en/ps/5001.DSC_Spec.pdf">Adobe PostScript Language Document Structuring Conventions Specification, Version 3.0</a>, September 1992
<br>[2] <a href="http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf">Adobe Encapsulated PostScript File Format Specification, Version 3.0</a>, May 1992
<br>[3] <a href="http://www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf">Adobe XMP Specification Part 3: Storage in Files</a>, July 2010
<br>[4] <a href="http://groups.google.com/group/adobe.illustrator.windows/msg/0a9d7b1244b59062">Re: Thumbnail data format in ai file</a>, Dec 2003
<br>[1] <a href="http://partners.adobe.com/public/developer/en/ps/5001.DSC_Spec.pdf">Adobe PostScript
Language Document Structuring Conventions Specification, Version 3.0</a>, September 1992 <br>[2] <a
href="http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf">Adobe Encapsulated PostScript File Format
Specification, Version 3.0</a>, May 1992 <br>[3] <a
href="http://www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf">Adobe XMP Specification
Part 3: Storage in Files</a>, July 2010 <br>[4] <a
href="http://groups.google.com/group/adobe.illustrator.windows/msg/0a9d7b1244b59062">Re: Thumbnail data format in ai
file</a>, Dec 2003
@author Michael Ulbrich (mul)
<a href="mailto:mul@rentapacs.de">mul@rentapacs.de</a>
@author Volker Grabsch (vog)
@ -25,77 +29,75 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2
{
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access EPS images.
*/
class EXIV2API EpsImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor to open a EPS image. Since the
constructor can't return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
EpsImage(BasicIo::UniquePtr io, bool create);
//@}
/*!
@brief Class to access EPS images.
*/
class EXIV2API EpsImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor to open a EPS image. Since the
constructor can't return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
EpsImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Not supported.
Calling this function will throw an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Not supported.
Calling this function will throw an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
//! @name NOT Implemented
//@{
//! Copy constructor
EpsImage(const EpsImage& rhs) = delete;
//! Assignment operator
EpsImage& operator=(const EpsImage& rhs) = delete;
//@}
//! @name NOT Implemented
//@{
//! Copy constructor
EpsImage(const EpsImage& rhs) = delete;
//! Assignment operator
EpsImage& operator=(const EpsImage& rhs) = delete;
//@}
}; // class EpsImage
}; // class EpsImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new EpsImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newEpsInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new EpsImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newEpsInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a EPS image.
EXIV2API bool isEpsType(BasicIo& iIo, bool advance);
//! Check if the file iIo is a EPS image.
EXIV2API bool isEpsType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef EPSIMAGE_HPP_
#endif // #ifndef EPSIMAGE_HPP_

@ -16,136 +16,127 @@
#include "config.h"
#include <exception> // for exception
#include <sstream> // for operator<<, ostream, ostringstream, bas...
#include <string> // for basic_string, string
#include <exception> // for exception
#include <sstream> // for operator<<, ostream, ostringstream, bas...
#include <string> // for basic_string, string
// *****************************************************************************
// namespace extensions
namespace Exiv2
{
// *****************************************************************************
// class definitions
/*!
@brief Class for a log message, used by the library. Applications can set
the log level and provide a customer log message handler (callback
function).
This class is meant to be used as a temporary object with the
related macro-magic like this:
<code>
EXV_WARNING << "Warning! Something looks fishy.\n";
</code>
which translates to
<code>
if (LogMsg::warn >= LogMsg::level() && LogMsg::handler())
LogMsg(LogMsg::warn).os() << "Warning! Something looks fishy.\n";
</code>
The macros EXV_DEBUG, EXV_INFO, EXV_WARNING and EXV_ERROR are
shorthands and ensure efficient use of the logging facility: If a
log message doesn't need to be generated because of the log level
setting, the temp object is not even created.
Caveat: The entire log message is not processed in this case. So don't
make that call any logic that always needs to be executed.
*/
class EXIV2API LogMsg
{
public:
//! Prevent copy-construction: not implemented.
LogMsg(const LogMsg&) = delete;
//! Prevent assignment: not implemented.
LogMsg& operator=(const LogMsg&) = delete;
/*!
@brief Defined log levels. To suppress all log messages, either set the
log level to \c mute or set the log message handler to 0.
*/
enum Level
{
debug = 0,
info = 1,
warn = 2,
error = 3,
mute = 4
};
/*!
@brief Type for a log message handler function. The function receives
the log level and message and can process it in an application
specific way. The default handler sends the log message to
standard error.
*/
using Handler = void (*)(int, const char*);
//! @name Creators
//@{
//! Constructor, takes the log message type as an argument
explicit LogMsg(Level msgType);
//! Destructor, passes the log message to the message handler depending on the log level
~LogMsg();
//@}
//! @name Manipulators
//@{
//! Return a reference to the ostringstream which holds the log message
std::ostringstream& os();
//@}
/*!
@brief Set the log level. Only log messages with a level greater or
equal \em level are sent to the log message handler. Default
log level is \c warn. To suppress all log messages, set the log
level to \c mute (or set the log message handler to 0).
*/
static void setLevel(Level level);
/*!
@brief Set the log message handler. The default handler writes log
messages to standard error. To suppress all log messages, set
the log message handler to 0 (or set the log level to \c mute).
*/
static void setHandler(Handler handler);
//! Return the current log level
static Level level();
//! Return the current log message handler
static Handler handler();
//! The default log handler. Sends the log message to standard error.
static void defaultHandler(int level, const char* s);
private:
// DATA
// The output level. Only messages with type >= level_ will be written
static Level level_;
// The log handler in use
static Handler handler_;
// The type of this log message
const Level msgType_;
// Holds the log message until it is passed to the message handler
std::ostringstream os_;
}; // class LogMsg
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class for a log message, used by the library. Applications can set
the log level and provide a customer log message handler (callback
function).
This class is meant to be used as a temporary object with the
related macro-magic like this:
<code>
EXV_WARNING << "Warning! Something looks fishy.\n";
</code>
which translates to
<code>
if (LogMsg::warn >= LogMsg::level() && LogMsg::handler())
LogMsg(LogMsg::warn).os() << "Warning! Something looks fishy.\n";
</code>
The macros EXV_DEBUG, EXV_INFO, EXV_WARNING and EXV_ERROR are
shorthands and ensure efficient use of the logging facility: If a
log message doesn't need to be generated because of the log level
setting, the temp object is not even created.
Caveat: The entire log message is not processed in this case. So don't
make that call any logic that always needs to be executed.
*/
class EXIV2API LogMsg {
public:
//! Prevent copy-construction: not implemented.
LogMsg(const LogMsg&) = delete;
//! Prevent assignment: not implemented.
LogMsg& operator=(const LogMsg&) = delete;
/*!
@brief Defined log levels. To suppress all log messages, either set the
log level to \c mute or set the log message handler to 0.
*/
enum Level { debug = 0, info = 1, warn = 2, error = 3, mute = 4 };
/*!
@brief Type for a log message handler function. The function receives
the log level and message and can process it in an application
specific way. The default handler sends the log message to
standard error.
*/
using Handler = void (*)(int, const char*);
//! @name Creators
//@{
//! Constructor, takes the log message type as an argument
explicit LogMsg(Level msgType);
//! Destructor, passes the log message to the message handler depending on the log level
~LogMsg();
//@}
//! @name Manipulators
//@{
//! Return a reference to the ostringstream which holds the log message
std::ostringstream& os();
//@}
/*!
@brief Set the log level. Only log messages with a level greater or
equal \em level are sent to the log message handler. Default
log level is \c warn. To suppress all log messages, set the log
level to \c mute (or set the log message handler to 0).
*/
static void setLevel(Level level);
/*!
@brief Set the log message handler. The default handler writes log
messages to standard error. To suppress all log messages, set
the log message handler to 0 (or set the log level to \c mute).
*/
static void setHandler(Handler handler);
//! Return the current log level
static Level level();
//! Return the current log message handler
static Handler handler();
//! The default log handler. Sends the log message to standard error.
static void defaultHandler(int level, const char* s);
private:
// DATA
// The output level. Only messages with type >= level_ will be written
static Level level_;
// The log handler in use
static Handler handler_;
// The type of this log message
const Level msgType_;
// Holds the log message until it is passed to the message handler
std::ostringstream os_;
}; // class LogMsg
// Macros for simple access
//! Shorthand to create a temp debug log message object and return its ostringstream
#define EXV_DEBUG \
if (LogMsg::debug >= LogMsg::level() && LogMsg::handler()) \
LogMsg(LogMsg::debug).os()
#define EXV_DEBUG \
if (LogMsg::debug >= LogMsg::level() && LogMsg::handler()) \
LogMsg(LogMsg::debug).os()
//! Shorthand for a temp info log message object and return its ostringstream
#define EXV_INFO \
if (LogMsg::info >= LogMsg::level() && LogMsg::handler()) \
LogMsg(LogMsg::info).os()
#define EXV_INFO \
if (LogMsg::info >= LogMsg::level() && LogMsg::handler()) \
LogMsg(LogMsg::info).os()
//! Shorthand for a temp warning log message object and return its ostringstream
#define EXV_WARNING \
if (LogMsg::warn >= LogMsg::level() && LogMsg::handler()) \
LogMsg(LogMsg::warn).os()
#define EXV_WARNING \
if (LogMsg::warn >= LogMsg::level() && LogMsg::handler()) \
LogMsg(LogMsg::warn).os()
//! Shorthand for a temp error log message object and return its ostringstream
#define EXV_ERROR \
if (LogMsg::error >= LogMsg::level() && LogMsg::handler()) \
LogMsg(LogMsg::error).os()
#define EXV_ERROR \
if (LogMsg::error >= LogMsg::level() && LogMsg::handler()) \
LogMsg(LogMsg::error).os()
#ifdef _MSC_VER
// Disable MSVC warnings "non - DLL-interface classkey 'identifier' used as base
@ -153,157 +144,150 @@ namespace Exiv2
#pragma warning(disable : 4275)
#endif
//! Generalised toString function
template <typename charT, typename T>
std::basic_string<charT> toBasicString(const T& arg)
{
std::basic_ostringstream<charT> os;
os << arg;
return os.str();
}
//! Complete list of all Exiv2 error codes
enum class ErrorCode
{
kerSuccess = 0,
kerGeneralError,
kerErrorMessage,
kerCallFailed,
kerNotAnImage,
kerInvalidDataset,
kerInvalidRecord,
kerInvalidKey,
kerInvalidTag,
kerValueNotSet,
kerDataSourceOpenFailed,
kerFileOpenFailed,
kerFileContainsUnknownImageType,
kerMemoryContainsUnknownImageType,
kerUnsupportedImageType,
kerFailedToReadImageData,
kerNotAJpeg,
kerFailedToMapFileForReadWrite,
kerFileRenameFailed,
kerTransferFailed,
kerMemoryTransferFailed,
kerInputDataReadFailed,
kerImageWriteFailed,
kerNoImageInInputData,
kerInvalidIfdId,
kerValueTooLarge,
kerDataAreaValueTooLarge,
kerOffsetOutOfRange,
kerUnsupportedDataAreaOffsetType,
kerInvalidCharset,
kerUnsupportedDateFormat,
kerUnsupportedTimeFormat,
kerWritingImageFormatUnsupported,
kerInvalidSettingForImage,
kerNotACrwImage,
kerFunctionNotSupported,
kerNoNamespaceInfoForXmpPrefix,
kerNoPrefixForNamespace,
kerTooLargeJpegSegment,
kerUnhandledXmpdatum,
kerUnhandledXmpNode,
kerXMPToolkitError,
kerDecodeLangAltPropertyFailed,
kerDecodeLangAltQualifierFailed,
kerEncodeLangAltPropertyFailed,
kerPropertyNameIdentificationFailed,
kerSchemaNamespaceNotRegistered,
kerNoNamespaceForPrefix,
kerAliasesNotSupported,
kerInvalidXmpText,
kerTooManyTiffDirectoryEntries,
kerMultipleTiffArrayElementTagsInDirectory,
kerWrongTiffArrayElementTagType,
kerInvalidKeyXmpValue,
kerInvalidIccProfile,
kerInvalidXMP,
kerTiffDirectoryTooLarge,
kerInvalidTypeValue,
kerInvalidLangAltValue,
kerInvalidMalloc,
kerCorruptedMetadata,
kerArithmeticOverflow,
kerMallocFailed,
kerErrorCount,
};
/*!
@brief Simple error class used for exceptions. An output operator is
provided to print errors to a stream.
*/
class EXIV2API Error : public std::exception
{
public:
//! @name Creators
//@{
//! Constructor taking only an error code
explicit Error(ErrorCode code);
//! Constructor taking an error code and one argument
template <typename A>
Error(ErrorCode code, const A& arg1) : code_(code), arg1_(toBasicString<char>(arg1))
{
setMsg(1);
}
//! Constructor taking an error code and two arguments
template <typename A, typename B>
Error(ErrorCode code, const A& arg1, const B& arg2)
: code_(code), arg1_(toBasicString<char>(arg1)), arg2_(toBasicString<char>(arg2))
{
setMsg(2);
}
//! Constructor taking an error code and three arguments
template <typename A, typename B, typename C>
Error(ErrorCode code, const A& arg1, const B& arg2, const C& arg3)
: code_(code),
arg1_(toBasicString<char>(arg1)),
arg2_(toBasicString<char>(arg2)),
arg3_(toBasicString<char>(arg3))
{
setMsg(3);
}
//! Virtual destructor. (Needed because of throw())
virtual ~Error() noexcept;
//@}
//! @name Accessors
//@{
ErrorCode code() const noexcept;
/*!
@brief Return the error message as a C-string. The pointer returned by what()
is valid only as long as the BasicError object exists.
*/
const char* what() const noexcept override;
//@}
private:
//! @name Manipulators
//@{
//! Assemble the error message from the arguments
void setMsg(int count);
//@}
// DATA
const ErrorCode code_; //!< Error code
const std::string arg1_; //!< First argument
const std::string arg2_; //!< Second argument
const std::string arg3_; //!< Third argument
std::string msg_; //!< Complete error message
}; // class BasicError
//! %Error output operator
inline std::ostream& operator<<(std::ostream& os, const Error& error)
{
return os << error.what();
}
//! Generalised toString function
template <typename charT, typename T>
std::basic_string<charT> toBasicString(const T& arg) {
std::basic_ostringstream<charT> os;
os << arg;
return os.str();
}
//! Complete list of all Exiv2 error codes
enum class ErrorCode {
kerSuccess = 0,
kerGeneralError,
kerErrorMessage,
kerCallFailed,
kerNotAnImage,
kerInvalidDataset,
kerInvalidRecord,
kerInvalidKey,
kerInvalidTag,
kerValueNotSet,
kerDataSourceOpenFailed,
kerFileOpenFailed,
kerFileContainsUnknownImageType,
kerMemoryContainsUnknownImageType,
kerUnsupportedImageType,
kerFailedToReadImageData,
kerNotAJpeg,
kerFailedToMapFileForReadWrite,
kerFileRenameFailed,
kerTransferFailed,
kerMemoryTransferFailed,
kerInputDataReadFailed,
kerImageWriteFailed,
kerNoImageInInputData,
kerInvalidIfdId,
kerValueTooLarge,
kerDataAreaValueTooLarge,
kerOffsetOutOfRange,
kerUnsupportedDataAreaOffsetType,
kerInvalidCharset,
kerUnsupportedDateFormat,
kerUnsupportedTimeFormat,
kerWritingImageFormatUnsupported,
kerInvalidSettingForImage,
kerNotACrwImage,
kerFunctionNotSupported,
kerNoNamespaceInfoForXmpPrefix,
kerNoPrefixForNamespace,
kerTooLargeJpegSegment,
kerUnhandledXmpdatum,
kerUnhandledXmpNode,
kerXMPToolkitError,
kerDecodeLangAltPropertyFailed,
kerDecodeLangAltQualifierFailed,
kerEncodeLangAltPropertyFailed,
kerPropertyNameIdentificationFailed,
kerSchemaNamespaceNotRegistered,
kerNoNamespaceForPrefix,
kerAliasesNotSupported,
kerInvalidXmpText,
kerTooManyTiffDirectoryEntries,
kerMultipleTiffArrayElementTagsInDirectory,
kerWrongTiffArrayElementTagType,
kerInvalidKeyXmpValue,
kerInvalidIccProfile,
kerInvalidXMP,
kerTiffDirectoryTooLarge,
kerInvalidTypeValue,
kerInvalidLangAltValue,
kerInvalidMalloc,
kerCorruptedMetadata,
kerArithmeticOverflow,
kerMallocFailed,
kerErrorCount,
};
/*!
@brief Simple error class used for exceptions. An output operator is
provided to print errors to a stream.
*/
class EXIV2API Error : public std::exception {
public:
//! @name Creators
//@{
//! Constructor taking only an error code
explicit Error(ErrorCode code);
//! Constructor taking an error code and one argument
template <typename A>
Error(ErrorCode code, const A& arg1) : code_(code), arg1_(toBasicString<char>(arg1)) {
setMsg(1);
}
//! Constructor taking an error code and two arguments
template <typename A, typename B>
Error(ErrorCode code, const A& arg1, const B& arg2) :
code_(code), arg1_(toBasicString<char>(arg1)), arg2_(toBasicString<char>(arg2)) {
setMsg(2);
}
//! Constructor taking an error code and three arguments
template <typename A, typename B, typename C>
Error(ErrorCode code, const A& arg1, const B& arg2, const C& arg3) :
code_(code),
arg1_(toBasicString<char>(arg1)),
arg2_(toBasicString<char>(arg2)),
arg3_(toBasicString<char>(arg3)) {
setMsg(3);
}
//! Virtual destructor. (Needed because of throw())
virtual ~Error() noexcept;
//@}
//! @name Accessors
//@{
ErrorCode code() const noexcept;
/*!
@brief Return the error message as a C-string. The pointer returned by what()
is valid only as long as the BasicError object exists.
*/
const char* what() const noexcept override;
//@}
private:
//! @name Manipulators
//@{
//! Assemble the error message from the arguments
void setMsg(int count);
//@}
// DATA
const ErrorCode code_; //!< Error code
const std::string arg1_; //!< First argument
const std::string arg2_; //!< Second argument
const std::string arg3_; //!< Third argument
std::string msg_; //!< Complete error message
}; // class BasicError
//! %Error output operator
inline std::ostream& operator<<(std::ostream& os, const Error& error) {
return os << error.what();
}
#ifdef _MSC_VER
#pragma warning(default : 4275)

File diff suppressed because it is too large Load Diff

@ -5,14 +5,14 @@
// *****************************************************************************
// included header files
#include "exiv2/config.h"
#include "exiv2/datasets.hpp"
#include "exiv2/basicio.hpp"
#include "exiv2/bmffimage.hpp"
#include "exiv2/bmpimage.hpp"
#include "exiv2/config.h"
#include "exiv2/convert.hpp"
#include "exiv2/cr2image.hpp"
#include "exiv2/crwimage.hpp"
#include "exiv2/datasets.hpp"
#include "exiv2/easyaccess.hpp"
#include "exiv2/epsimage.hpp"
#include "exiv2/error.hpp"
@ -49,4 +49,4 @@
#include "exiv2/xmp_exiv2.hpp"
#include "exiv2/xmpsidecar.hpp"
#endif//ifndef EXIV2_HPP_
#endif // ifndef EXIV2_HPP_

@ -3,138 +3,122 @@
#ifndef FUTILS_HPP_
#define FUTILS_HPP_
#include "exiv2lib_export.h"
#include "config.h"
#include "exiv2lib_export.h"
#include <string>
// namespace extensions
namespace Exiv2
{
//! the name of environmental variables.
enum EnVar
{
envHTTPPOST = 0,
envTIMEOUT = 1
};
//! the collection of protocols.
enum Protocol
{
pFile = 0,
pHttp,
pFtp,
pHttps,
pSftp,
pFileUri,
pDataUri,
pStdin
};
// *********************************************************************
// free functions
/*!
@brief Return the value of environmental variable.
@param[in] var The name of environmental variable. Must be a member of the enumeration @ref EnVar.
@return the value of environmental variable. If it's empty, the default value is returned.
@throws std::out_of_range when an unexpected EnVar is given as input.
*/
EXIV2API std::string getEnv(int env_var);
/*!
@brief Encode the input url.
@param str The url needs encoding.
@return the url-encoded version of str.
@note Source: http://www.geekhideout.com/urlcode.shtml
@todo This function can probably be hidden into the implementation details
*/
EXIV2API std::string urlencode(std::string_view str);
/*!
@brief Like urlencode(char* str) but accept the input url in the std::string and modify it.
@todo This function can probably be hidden into the implementation details
*/
EXIV2API void urldecode(std::string& str);
/*!
@brief Encode in base64 the data in data_buf and put the resulting string in result.
@param data_buf The data need to encode
@param dataLength Size in bytes of the in buffer
@param result The container for the result, NULL if it fails
@param resultSize Size in bytes of the out string, it should be at least
((dataLength + 2) / 3) * 4 + 1
@return 1 indicate success
@note Source: http://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64
*/
EXIV2API int base64encode(const void* data_buf, size_t dataLength, char* result, size_t resultSize);
/*!
@brief Decode base64 data and put the resulting string in out.
@param in The data need to decode.
@param out The container for the result, it should be large enough to contain the result.
@param out_size The size of out in bytes.
@return the size of the resulting string. If it fails, return -1.
@note Source: https://github.com/davidgaleano/libwebsockets/blob/master/lib/base64-decode.c
*/
EXIV2API size_t base64decode(const char* in, char* out, size_t out_size);
/*!
@brief Return the protocol of the path.
@param path The path of file to extract the protocol.
@return the protocol of the path.
*/
EXIV2API Protocol fileProtocol(const std::string& path);
/*!
@brief Test if a file exists.
@param path Name of file to verify.
@param ct Flag to check if <i>path</i> is a regular file.
@return true if <i>path</i> exists and, if <i>ct</i> is set,
is a regular file, else false.
@note The function calls <b>stat()</b> test for <i>path</i>
and its type, see stat(2). <b>errno</b> is left unchanged
in case of an error.
*/
EXIV2API bool fileExists(const std::string& path);
/*!
@brief Return a system error message and the error code (errno).
See %strerror(3).
*/
EXIV2API std::string strError();
//! @brief Return the path of the current process.
EXIV2API std::string getProcessPath();
/*!
@brief A container for URL components. It also provides the method to parse a
URL to get the protocol, host, path, port, querystring, username, password.
Source: http://stackoverflow.com/questions/2616011/easy-way-to-parse-a-url-in-c-cross-platform
@todo This class can probably be hidden from the API
*/
class Uri
{
public:
// DATA
std::string QueryString; //!< URL query string
std::string Path; //!< URL file path
std::string Protocol; //!< URL protocol
std::string Host; //!< URL host
std::string Port; //!< URL port
std::string Username; //!< URL username
std::string Password; //!< URL password
/// @brief Parse the input URL to the protocol, host, path, username, password
static Uri EXIV2API Parse(const std::string& uri);
/// @brief Decode the url components.
static void EXIV2API Decode(Uri& uri);
};
namespace Exiv2 {
//! the name of environmental variables.
enum EnVar { envHTTPPOST = 0, envTIMEOUT = 1 };
//! the collection of protocols.
enum Protocol { pFile = 0, pHttp, pFtp, pHttps, pSftp, pFileUri, pDataUri, pStdin };
// *********************************************************************
// free functions
/*!
@brief Return the value of environmental variable.
@param[in] var The name of environmental variable. Must be a member of the enumeration @ref EnVar.
@return the value of environmental variable. If it's empty, the default value is returned.
@throws std::out_of_range when an unexpected EnVar is given as input.
*/
EXIV2API std::string getEnv(int env_var);
/*!
@brief Encode the input url.
@param str The url needs encoding.
@return the url-encoded version of str.
@note Source: http://www.geekhideout.com/urlcode.shtml
@todo This function can probably be hidden into the implementation details
*/
EXIV2API std::string urlencode(std::string_view str);
/*!
@brief Like urlencode(char* str) but accept the input url in the std::string and modify it.
@todo This function can probably be hidden into the implementation details
*/
EXIV2API void urldecode(std::string& str);
/*!
@brief Encode in base64 the data in data_buf and put the resulting string in result.
@param data_buf The data need to encode
@param dataLength Size in bytes of the in buffer
@param result The container for the result, NULL if it fails
@param resultSize Size in bytes of the out string, it should be at least
((dataLength + 2) / 3) * 4 + 1
@return 1 indicate success
@note Source: http://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64
*/
EXIV2API int base64encode(const void* data_buf, size_t dataLength, char* result, size_t resultSize);
/*!
@brief Decode base64 data and put the resulting string in out.
@param in The data need to decode.
@param out The container for the result, it should be large enough to contain the result.
@param out_size The size of out in bytes.
@return the size of the resulting string. If it fails, return -1.
@note Source: https://github.com/davidgaleano/libwebsockets/blob/master/lib/base64-decode.c
*/
EXIV2API size_t base64decode(const char* in, char* out, size_t out_size);
/*!
@brief Return the protocol of the path.
@param path The path of file to extract the protocol.
@return the protocol of the path.
*/
EXIV2API Protocol fileProtocol(const std::string& path);
/*!
@brief Test if a file exists.
@param path Name of file to verify.
@param ct Flag to check if <i>path</i> is a regular file.
@return true if <i>path</i> exists and, if <i>ct</i> is set,
is a regular file, else false.
@note The function calls <b>stat()</b> test for <i>path</i>
and its type, see stat(2). <b>errno</b> is left unchanged
in case of an error.
*/
EXIV2API bool fileExists(const std::string& path);
/*!
@brief Return a system error message and the error code (errno).
See %strerror(3).
*/
EXIV2API std::string strError();
//! @brief Return the path of the current process.
EXIV2API std::string getProcessPath();
/*!
@brief A container for URL components. It also provides the method to parse a
URL to get the protocol, host, path, port, querystring, username, password.
Source: http://stackoverflow.com/questions/2616011/easy-way-to-parse-a-url-in-c-cross-platform
@todo This class can probably be hidden from the API
*/
class Uri {
public:
// DATA
std::string QueryString; //!< URL query string
std::string Path; //!< URL file path
std::string Protocol; //!< URL protocol
std::string Host; //!< URL host
std::string Port; //!< URL port
std::string Username; //!< URL username
std::string Password; //!< URL password
/// @brief Parse the input URL to the protocol, host, path, username, password
static Uri EXIV2API Parse(const std::string& uri);
/// @brief Decode the url components.
static void EXIV2API Decode(Uri& uri);
};
} // namespace Exiv2
#endif // #ifndef FUTILS_HPP_
#endif // #ifndef FUTILS_HPP_

@ -12,88 +12,87 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access raw GIF images. Exif/IPTC metadata are supported
directly.
*/
class EXIV2API GifImage : public Image {
public:
//! @name NOT Implemented
//@{
//! Copy constructor
GifImage(const GifImage& rhs) = delete;
//! Assignment operator
GifImage& operator=(const GifImage& rhs) = delete;
//@}
/*!
@brief Class to access raw GIF images. Exif/IPTC metadata are supported
directly.
*/
class EXIV2API GifImage : public Image {
public:
//! @name NOT Implemented
//@{
//! Copy constructor
GifImage(const GifImage& rhs) = delete;
//! Assignment operator
GifImage& operator=(const GifImage& rhs) = delete;
//@}
//! @name Creators
//@{
/*!
@brief Constructor to open a GIF image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
explicit GifImage(BasicIo::UniquePtr io);
//@}
//! @name Creators
//@{
/*!
@brief Constructor to open a GIF image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
explicit GifImage(BasicIo::UniquePtr io);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
/*!
@brief Todo: Write metadata back to the image. This method is not
yet(?) implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported).
*/
void writeMetadata() override;
/*!
@brief Todo: Not supported yet(?). Calling this function will throw
an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setExifData(const ExifData& exifData) override;
/*!
@brief Todo: Not supported yet(?). Calling this function will throw
an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setIptcData(const IptcData& iptcData) override;
/*!
@brief Not supported. Calling this function will throw an instance
of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Manipulators
//@{
void readMetadata() override;
/*!
@brief Todo: Write metadata back to the image. This method is not
yet(?) implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported).
*/
void writeMetadata() override;
/*!
@brief Todo: Not supported yet(?). Calling this function will throw
an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setExifData(const ExifData& exifData) override;
/*!
@brief Todo: Not supported yet(?). Calling this function will throw
an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setIptcData(const IptcData& iptcData) override;
/*!
@brief Not supported. Calling this function will throw an instance
of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
}; // class GifImage
}; // class GifImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new GifImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newGifInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new GifImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newGifInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a GIF image.
EXIV2API bool isGifType(BasicIo& iIo, bool advance);
//! Check if the file iIo is a GIF image.
EXIV2API bool isGifType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef GIFIMAGE_HPP_
#endif // #ifndef GIFIMAGE_HPP_

@ -7,16 +7,15 @@
#include "datasets.hpp"
namespace Exiv2 {
/*!
@brief execute an HTTP request
@param request - a Dictionary of headers to send to server
@param response - a Dictionary of response headers (dictionary is filled by the response)
@param errors - a String with an error
@return Server response 200 = OK, 404 = Not Found etc...
*/
EXIV2API int http(Exiv2::Dictionary& request,Exiv2::Dictionary& response,std::string& errors);
}
/*!
@brief execute an HTTP request
@param request - a Dictionary of headers to send to server
@param response - a Dictionary of response headers (dictionary is filled by the response)
@param errors - a String with an error
@return Server response 200 = OK, 404 = Not Found etc...
*/
EXIV2API int http(Exiv2::Dictionary& request, Exiv2::Dictionary& response, std::string& errors);
} // namespace Exiv2
#endif

File diff suppressed because it is too large Load Diff

@ -3,40 +3,38 @@
#ifndef IMAGE_TYPES_H
#define IMAGE_TYPES_H
namespace Exiv2
{
/// Supported Image Formats
enum class ImageType
{
none,
arw,
bigtiff,
bmff,
bmp, ///< Windows bitmap
cr2,
crw,
dng,
eps,
exv,
gif, ///< GIF
jp2, ///< JPEG-2000
jpeg,
mrw,
nef,
orf,
pef,
png,
pgf,
psd, ///< Photoshop (PSD)
raf,
rw2,
sr2,
srw,
tga,
tiff,
webp,
xmp, ///< XMP sidecar files
};
namespace Exiv2 {
/// Supported Image Formats
enum class ImageType {
none,
arw,
bigtiff,
bmff,
bmp, ///< Windows bitmap
cr2,
crw,
dng,
eps,
exv,
gif, ///< GIF
jp2, ///< JPEG-2000
jpeg,
mrw,
nef,
orf,
pef,
png,
pgf,
psd, ///< Photoshop (PSD)
raf,
rw2,
sr2,
srw,
tga,
tiff,
webp,
xmp, ///< XMP sidecar files
};
} // namespace Exiv2
#endif // IMAGE_TYPES_H

@ -17,7 +17,6 @@
#include <string>
namespace Exiv2 {
#ifndef __INI_H__
#define __INI_H__
@ -72,8 +71,7 @@ int ini_parse_file(FILE* file, ini_handler handler, void* user);
@return 0 on success
*/
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
void* user);
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, void* user);
/*! @brief Nonzero to allow multi-line value parsing, in the style of Python's
configparser. If allowed, ini_parse() will call the handler with the same
@ -122,76 +120,74 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
#endif /* __INI_H__ */
/*! @brief Read an INI file into easy-to-access name/value pairs. (Note that I've gone
for simplicity here rather than speed, but it should be pretty decent.)
*/
class EXIV2API INIReader
{
public:
/*! @brief Construct INIReader and parse given filename. See ini.h for more info
about the parsing.
*/
explicit INIReader(const std::string& filename);
/*! @brief Return the result of ini_parse(), i.e., 0 on success, line number of
first error on parse error, or -1 on file open error.
*/
int ParseError() const;
/*! @brief Get a string value from INI file, returning default_value if not found.
@param section name of section
@param name name of key
@param default_value default if not found
@return value
*/
std::string Get(const std::string& section, const std::string& name, const std::string& default_value);
/*! @brief Get an integer (long) value from INI file, returning default_value if
not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2").
@param section name of section
@param name name of key
@param default_value default if not found
@return value
*/
long GetInteger(const std::string& section, const std::string& name, long default_value);
/*! @brief Get a real (floating point double) value from INI file, returning
default_value if not found or not a valid floating point value
according to strtod().
@param section name of section
@param name name of key
@param default_value default if not found
@return value
*/
double GetReal(const std::string& section, const std::string& name, double default_value);
/*! @brief Get a boolean value from INI file, returning default_value if not found or if
not a valid true/false value. Valid true values are "true", "yes", "on", "1",
and valid false values are "false", "no", "off", "0" (not case sensitive).
@param section name of section
@param name name of key
@param default_value default if not found
@return value
*/
bool GetBoolean(const std::string& section, const std::string& name, bool default_value);
private:
int _error; //!< status
std::map<std::string, std::string> _values; //!< values from file
static std::string MakeKey(const std::string& section,
const std::string& name); //!< return key encoded from section/name
static int ValueHandler(void* user, const char* section, const char* name,
const char* value); //!< value handler
class EXIV2API INIReader {
public:
/*! @brief Construct INIReader and parse given filename. See ini.h for more info
about the parsing.
*/
explicit INIReader(const std::string& filename);
/*! @brief Return the result of ini_parse(), i.e., 0 on success, line number of
first error on parse error, or -1 on file open error.
*/
int ParseError() const;
/*! @brief Get a string value from INI file, returning default_value if not found.
@param section name of section
@param name name of key
@param default_value default if not found
@return value
*/
std::string Get(const std::string& section, const std::string& name, const std::string& default_value);
/*! @brief Get an integer (long) value from INI file, returning default_value if
not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2").
@param section name of section
@param name name of key
@param default_value default if not found
@return value
*/
long GetInteger(const std::string& section, const std::string& name, long default_value);
/*! @brief Get a real (floating point double) value from INI file, returning
default_value if not found or not a valid floating point value
according to strtod().
@param section name of section
@param name name of key
@param default_value default if not found
@return value
*/
double GetReal(const std::string& section, const std::string& name, double default_value);
/*! @brief Get a boolean value from INI file, returning default_value if not found or if
not a valid true/false value. Valid true values are "true", "yes", "on", "1",
and valid false values are "false", "no", "off", "0" (not case sensitive).
@param section name of section
@param name name of key
@param default_value default if not found
@return value
*/
bool GetBoolean(const std::string& section, const std::string& name, bool default_value);
private:
int _error; //!< status
std::map<std::string, std::string> _values; //!< values from file
static std::string MakeKey(const std::string& section,
const std::string& name); //!< return key encoded from section/name
static int ValueHandler(void* user, const char* section, const char* name,
const char* value); //!< value handler
};
} // namespace Exiv2
} // namespace Exiv2
#endif // __INIREADER_H__

@ -11,285 +11,296 @@
#include "exiv2lib_export.h"
// included header files
#include "metadatum.hpp"
#include "datasets.hpp"
#include "metadatum.hpp"
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class ExifData;
class ExifData;
// *****************************************************************************
// class definitions
/*!
@brief An IPTC metadatum ("dataset"), consisting of an IptcKey and a
Value and methods to manipulate these.
This is referred in the standard as a property.
*/
class EXIV2API Iptcdatum : public Metadatum {
public:
//! @name Creators
//@{
/*!
@brief Constructor for new tags created by an application. The
%Iptcdatum is created from a key / value pair. %Iptcdatum
copies (clones) the value if one is provided. Alternatively, a
program can create an 'empty' %Iptcdatum with only a key and
set the value using setValue().
@param key The key of the %Iptcdatum.
@param pValue Pointer to a %Iptcdatum value.
@throw Error if the key cannot be parsed and converted
to a tag number and record id.
*/
explicit Iptcdatum(const IptcKey& key, const Value* pValue = nullptr);
//! Copy constructor
Iptcdatum(const Iptcdatum& rhs);
//! Destructor
~Iptcdatum() override = default;
//@}
//! @name Manipulators
//@{
//! Assignment operator
Iptcdatum& operator=(const Iptcdatum& rhs);
/*!
@brief Assign \em value to the %Iptcdatum. The type of the new Value
is set to UShortValue.
*/
Iptcdatum& operator=(const uint16_t& value);
/*!
@brief Assign \em value to the %Iptcdatum.
Calls setValue(const std::string&).
*/
Iptcdatum& operator=(const std::string& value);
/*!
@brief Assign \em value to the %Iptcdatum.
Calls setValue(const Value*).
*/
Iptcdatum& operator=(const Value& value);
void setValue(const Value* pValue) override;
/*!
@brief Set the value to the string \em value, using
Value::read(const std::string&).
If the %Iptcdatum does not have a Value yet, then a %Value of
the correct type for this %Iptcdatum is created. If that
fails (because of an unknown dataset), a StringValue is
created. Return 0 if the value was read successfully.
*/
int setValue(const std::string& value) override;
//@}
//! @name Accessors
//@{
size_t copy(byte* buf, ByteOrder byteOrder) const override;
std::ostream& write(std::ostream& os, const ExifData* pMetadata = nullptr) const override;
/*!
@brief Return the key of the Iptcdatum. The key is of the form
'<b>Iptc</b>.recordName.datasetName'. Note however that the key
is not necessarily unique, i.e., an IptcData object may contain
multiple metadata with the same key.
*/
std::string key() const override;
/*!
@brief Return the name of the record (deprecated)
@return record name
*/
std::string recordName() const;
/*!
@brief Return the record id
@return record id
*/
uint16_t record() const;
const char* familyName() const override;
std::string groupName() const override;
/*!
@brief Return the name of the tag (aka dataset)
@return tag name
*/
std::string tagName() const override;
std::string tagLabel() const override;
//! Return the tag (aka dataset) number
uint16_t tag() const override;
TypeId typeId() const override;
const char* typeName() const override;
size_t typeSize() const override;
size_t count() const override;
size_t size() const override;
std::string toString() const override;
std::string toString(size_t n) const override;
int64_t toInt64(size_t n = 0) const override;
float toFloat(size_t n = 0) const override;
Rational toRational(size_t n = 0) const override;
Value::UniquePtr getValue() const override;
const Value& value() const override;
//@}
private:
// DATA
IptcKey::UniquePtr key_; //!< Key
Value::UniquePtr value_; //!< Value
}; // class Iptcdatum
//! Container type to hold all metadata
using IptcMetadata = std::vector<Iptcdatum>;
/*!
@brief A container for IPTC data. This is a top-level class of the %Exiv2 library.
Provide high-level access to the IPTC data of an image:
- read IPTC information from JPEG files
- access metadata through keys and standard C++ iterators
- add, modify and delete metadata
- write IPTC data to JPEG files
- extract IPTC metadata to files, insert from these files
*/
class EXIV2API IptcData {
public:
//! IptcMetadata iterator type
using iterator = IptcMetadata::iterator;
//! IptcMetadata const iterator type
using const_iterator = IptcMetadata::const_iterator;
// Use the compiler generated constructors and assignment operator
//! @name Manipulators
//@{
/*!
@brief Returns a reference to the %Iptcdatum that is associated with a
particular \em key. If %IptcData does not already contain such
an %Iptcdatum, operator[] adds object \em Iptcdatum(key).
@note Since operator[] might insert a new element, it can't be a const
member function.
*/
Iptcdatum& operator[](const std::string& key);
/*!
@brief Add an %Iptcdatum from the supplied key and value pair. This
method copies (clones) the value. A check for non-repeatable
datasets is performed.
@return 0 if successful;<BR>
6 if the dataset already exists and is not repeatable
*/
int add(const IptcKey& key, Value* value);
/*!
@brief Add a copy of the Iptcdatum to the IPTC metadata. A check
for non-repeatable datasets is performed.
@return 0 if successful;<BR>
6 if the dataset already exists and is not repeatable;<BR>
*/
int add(const Iptcdatum& iptcdatum);
/*!
@brief Delete the Iptcdatum at iterator position pos, return the
position of the next Iptcdatum. Note that iterators into
the metadata, including pos, are potentially invalidated
by this call.
*/
iterator erase(iterator pos);
/*!
@brief Delete all Iptcdatum instances resulting in an empty container.
*/
void clear() { iptcMetadata_.clear(); }
//! Sort metadata by key
void sortByKey();
//! Sort metadata by tag (aka dataset)
void sortByTag();
//! Begin of the metadata
iterator begin() { return iptcMetadata_.begin(); }
//! End of the metadata
iterator end() { return iptcMetadata_.end(); }
/*!
@brief Find the first Iptcdatum with the given key, return an iterator
to it.
*/
iterator findKey(const IptcKey& key);
/*!
@brief Find the first Iptcdatum with the given record and dataset it,
return a const iterator to it.
*/
iterator findId(uint16_t dataset,
uint16_t record = IptcDataSets::application2);
//@}
//! @name Accessors
//@{
//! Begin of the metadata
const_iterator begin() const { return iptcMetadata_.begin(); }
//! End of the metadata
const_iterator end() const { return iptcMetadata_.end(); }
/*!
@brief Find the first Iptcdatum with the given key, return a const
iterator to it.
*/
const_iterator findKey(const IptcKey& key) const;
/*!
@brief Find the first Iptcdatum with the given record and dataset
number, return a const iterator to it.
*/
const_iterator findId(uint16_t dataset,
uint16_t record = IptcDataSets::application2) const;
//! Return true if there is no IPTC metadata
bool empty() const { return count() == 0; }
//! Get the number of metadata entries
size_t count() const { return iptcMetadata_.size(); }
//! @brief Return the exact size of all contained IPTC metadata
size_t size() const;
//! @brief Return the metadata charset name or 0
const char *detectCharset() const;
//! @brief dump iptc formatted binary data (used by printStructure kpsRecursive)
static void printStructure(std::ostream& out, const Slice<byte*>& bytes,uint32_t depth);
//@}
private:
// DATA
IptcMetadata iptcMetadata_;
}; // class IptcData
/*!
@brief Stateless parser class for IPTC data. Images use this class to
decode and encode binary IPTC data.
*/
class EXIV2API IptcParser {
public:
/*!
@brief Decode binary IPTC data in IPTC IIM4 format from a buffer \em pData
of length \em size to the provided metadata container.
@param iptcData Metadata container to add the decoded IPTC datasets to.
@param pData Pointer to the data buffer to read from.
@param size Number of bytes in the data buffer.
@return 0 if successful;<BR>
5 if the binary IPTC data is invalid or corrupt
*/
static int decode(IptcData& iptcData, const byte* pData, size_t size);
/*!
@brief Encode the IPTC datasets from \em iptcData to a binary representation in IPTC IIM4 format.
Convert the IPTC datasets to binary format and return it. Caller owns
the returned buffer. The copied data follows the IPTC IIM4 standard.
@return Data buffer containing the binary IPTC data in IPTC IIM4 format.
*/
static DataBuf encode(const IptcData& iptcData);
private:
// Constant data
static const byte marker_; // Dataset marker
}; // class IptcParser
} // namespace Exiv2
#endif // #ifndef IPTC_HPP_
/*!
@brief An IPTC metadatum ("dataset"), consisting of an IptcKey and a
Value and methods to manipulate these.
This is referred in the standard as a property.
*/
class EXIV2API Iptcdatum : public Metadatum {
public:
//! @name Creators
//@{
/*!
@brief Constructor for new tags created by an application. The
%Iptcdatum is created from a key / value pair. %Iptcdatum
copies (clones) the value if one is provided. Alternatively, a
program can create an 'empty' %Iptcdatum with only a key and
set the value using setValue().
@param key The key of the %Iptcdatum.
@param pValue Pointer to a %Iptcdatum value.
@throw Error if the key cannot be parsed and converted
to a tag number and record id.
*/
explicit Iptcdatum(const IptcKey& key, const Value* pValue = nullptr);
//! Copy constructor
Iptcdatum(const Iptcdatum& rhs);
//! Destructor
~Iptcdatum() override = default;
//@}
//! @name Manipulators
//@{
//! Assignment operator
Iptcdatum& operator=(const Iptcdatum& rhs);
/*!
@brief Assign \em value to the %Iptcdatum. The type of the new Value
is set to UShortValue.
*/
Iptcdatum& operator=(const uint16_t& value);
/*!
@brief Assign \em value to the %Iptcdatum.
Calls setValue(const std::string&).
*/
Iptcdatum& operator=(const std::string& value);
/*!
@brief Assign \em value to the %Iptcdatum.
Calls setValue(const Value*).
*/
Iptcdatum& operator=(const Value& value);
void setValue(const Value* pValue) override;
/*!
@brief Set the value to the string \em value, using
Value::read(const std::string&).
If the %Iptcdatum does not have a Value yet, then a %Value of
the correct type for this %Iptcdatum is created. If that
fails (because of an unknown dataset), a StringValue is
created. Return 0 if the value was read successfully.
*/
int setValue(const std::string& value) override;
//@}
//! @name Accessors
//@{
size_t copy(byte* buf, ByteOrder byteOrder) const override;
std::ostream& write(std::ostream& os, const ExifData* pMetadata = nullptr) const override;
/*!
@brief Return the key of the Iptcdatum. The key is of the form
'<b>Iptc</b>.recordName.datasetName'. Note however that the key
is not necessarily unique, i.e., an IptcData object may contain
multiple metadata with the same key.
*/
std::string key() const override;
/*!
@brief Return the name of the record (deprecated)
@return record name
*/
std::string recordName() const;
/*!
@brief Return the record id
@return record id
*/
uint16_t record() const;
const char* familyName() const override;
std::string groupName() const override;
/*!
@brief Return the name of the tag (aka dataset)
@return tag name
*/
std::string tagName() const override;
std::string tagLabel() const override;
//! Return the tag (aka dataset) number
uint16_t tag() const override;
TypeId typeId() const override;
const char* typeName() const override;
size_t typeSize() const override;
size_t count() const override;
size_t size() const override;
std::string toString() const override;
std::string toString(size_t n) const override;
int64_t toInt64(size_t n = 0) const override;
float toFloat(size_t n = 0) const override;
Rational toRational(size_t n = 0) const override;
Value::UniquePtr getValue() const override;
const Value& value() const override;
//@}
private:
// DATA
IptcKey::UniquePtr key_; //!< Key
Value::UniquePtr value_; //!< Value
}; // class Iptcdatum
//! Container type to hold all metadata
using IptcMetadata = std::vector<Iptcdatum>;
/*!
@brief A container for IPTC data. This is a top-level class of the %Exiv2 library.
Provide high-level access to the IPTC data of an image:
- read IPTC information from JPEG files
- access metadata through keys and standard C++ iterators
- add, modify and delete metadata
- write IPTC data to JPEG files
- extract IPTC metadata to files, insert from these files
*/
class EXIV2API IptcData {
public:
//! IptcMetadata iterator type
using iterator = IptcMetadata::iterator;
//! IptcMetadata const iterator type
using const_iterator = IptcMetadata::const_iterator;
// Use the compiler generated constructors and assignment operator
//! @name Manipulators
//@{
/*!
@brief Returns a reference to the %Iptcdatum that is associated with a
particular \em key. If %IptcData does not already contain such
an %Iptcdatum, operator[] adds object \em Iptcdatum(key).
@note Since operator[] might insert a new element, it can't be a const
member function.
*/
Iptcdatum& operator[](const std::string& key);
/*!
@brief Add an %Iptcdatum from the supplied key and value pair. This
method copies (clones) the value. A check for non-repeatable
datasets is performed.
@return 0 if successful;<BR>
6 if the dataset already exists and is not repeatable
*/
int add(const IptcKey& key, Value* value);
/*!
@brief Add a copy of the Iptcdatum to the IPTC metadata. A check
for non-repeatable datasets is performed.
@return 0 if successful;<BR>
6 if the dataset already exists and is not repeatable;<BR>
*/
int add(const Iptcdatum& iptcdatum);
/*!
@brief Delete the Iptcdatum at iterator position pos, return the
position of the next Iptcdatum. Note that iterators into
the metadata, including pos, are potentially invalidated
by this call.
*/
iterator erase(iterator pos);
/*!
@brief Delete all Iptcdatum instances resulting in an empty container.
*/
void clear() {
iptcMetadata_.clear();
}
//! Sort metadata by key
void sortByKey();
//! Sort metadata by tag (aka dataset)
void sortByTag();
//! Begin of the metadata
iterator begin() {
return iptcMetadata_.begin();
}
//! End of the metadata
iterator end() {
return iptcMetadata_.end();
}
/*!
@brief Find the first Iptcdatum with the given key, return an iterator
to it.
*/
iterator findKey(const IptcKey& key);
/*!
@brief Find the first Iptcdatum with the given record and dataset it,
return a const iterator to it.
*/
iterator findId(uint16_t dataset, uint16_t record = IptcDataSets::application2);
//@}
//! @name Accessors
//@{
//! Begin of the metadata
const_iterator begin() const {
return iptcMetadata_.begin();
}
//! End of the metadata
const_iterator end() const {
return iptcMetadata_.end();
}
/*!
@brief Find the first Iptcdatum with the given key, return a const
iterator to it.
*/
const_iterator findKey(const IptcKey& key) const;
/*!
@brief Find the first Iptcdatum with the given record and dataset
number, return a const iterator to it.
*/
const_iterator findId(uint16_t dataset, uint16_t record = IptcDataSets::application2) const;
//! Return true if there is no IPTC metadata
bool empty() const {
return count() == 0;
}
//! Get the number of metadata entries
size_t count() const {
return iptcMetadata_.size();
}
//! @brief Return the exact size of all contained IPTC metadata
size_t size() const;
//! @brief Return the metadata charset name or 0
const char* detectCharset() const;
//! @brief dump iptc formatted binary data (used by printStructure kpsRecursive)
static void printStructure(std::ostream& out, const Slice<byte*>& bytes, uint32_t depth);
//@}
private:
// DATA
IptcMetadata iptcMetadata_;
}; // class IptcData
/*!
@brief Stateless parser class for IPTC data. Images use this class to
decode and encode binary IPTC data.
*/
class EXIV2API IptcParser {
public:
/*!
@brief Decode binary IPTC data in IPTC IIM4 format from a buffer \em pData
of length \em size to the provided metadata container.
@param iptcData Metadata container to add the decoded IPTC datasets to.
@param pData Pointer to the data buffer to read from.
@param size Number of bytes in the data buffer.
@return 0 if successful;<BR>
5 if the binary IPTC data is invalid or corrupt
*/
static int decode(IptcData& iptcData, const byte* pData, size_t size);
/*!
@brief Encode the IPTC datasets from \em iptcData to a binary representation in IPTC IIM4 format.
Convert the IPTC datasets to binary format and return it. Caller owns
the returned buffer. The copied data follows the IPTC IIM4 standard.
@return Data buffer containing the binary IPTC data in IPTC IIM4 format.
*/
static DataBuf encode(const IptcData& iptcData);
private:
// Constant data
static const byte marker_; // Dataset marker
}; // class IptcParser
} // namespace Exiv2
#endif // #ifndef IPTC_HPP_

@ -11,103 +11,101 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2
{
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access JPEG-2000 images.
*/
class EXIV2API Jp2Image : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor to open a JPEG-2000 image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
Jp2Image(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Print out the structure of image file.
@throw Error if reading of the file fails or the image data is
not valid (does not look like data of the specific image type).
@warning This function is not thread safe and intended for exiv2 -pS for debugging.
*/
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
/*!
@brief Todo: Not supported yet(?). Calling this function will throw
an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
//! @name NOT Implemented
//@{
//! Copy constructor
Jp2Image(const Jp2Image& rhs) = delete;
//! Assignment operator
Jp2Image& operator=(const Jp2Image& rhs) = delete;
private:
/*!
@brief Provides the main implementation of writeMetadata() by
writing all buffered metadata to the provided BasicIo.
@param oIo BasicIo instance to write to (a temporary location).
@return 4 if opening or writing to the associated BasicIo fails
*/
void doWriteMetadata(BasicIo& outIo);
/*!
@brief reformats the Jp2Header to store iccProfile
@param oldData DataBufRef to data in the file.
@param newData DataBufRef with updated data
*/
void encodeJp2Header(const DataBuf& boxBuf, DataBuf& outBuf);
//@}
}; // class Jp2Image
/*!
@brief Class to access JPEG-2000 images.
*/
class EXIV2API Jp2Image : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor to open a JPEG-2000 image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
Jp2Image(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Print out the structure of image file.
@throw Error if reading of the file fails or the image data is
not valid (does not look like data of the specific image type).
@warning This function is not thread safe and intended for exiv2 -pS for debugging.
*/
void printStructure(std::ostream &out, PrintStructureOption option, int depth) override;
/*!
@brief Todo: Not supported yet(?). Calling this function will throw
an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
//! @name NOT Implemented
//@{
//! Copy constructor
Jp2Image(const Jp2Image &rhs) = delete;
//! Assignment operator
Jp2Image &operator=(const Jp2Image &rhs) = delete;
private:
/*!
@brief Provides the main implementation of writeMetadata() by
writing all buffered metadata to the provided BasicIo.
@param oIo BasicIo instance to write to (a temporary location).
@return 4 if opening or writing to the associated BasicIo fails
*/
void doWriteMetadata(BasicIo &outIo);
/*!
@brief reformats the Jp2Header to store iccProfile
@param oldData DataBufRef to data in the file.
@param newData DataBufRef with updated data
*/
void encodeJp2Header(const DataBuf &boxBuf, DataBuf &outBuf);
//@}
}; // class Jp2Image
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new Jp2Image instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newJp2Instance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new Jp2Image instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newJp2Instance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a JPEG-2000 image.
EXIV2API bool isJp2Type(BasicIo& iIo, bool advance);
//! Check if the file iIo is a JPEG-2000 image.
EXIV2API bool isJp2Type(BasicIo &iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef JP2IMAGE_HPP_
#endif // #ifndef JP2IMAGE_HPP_

@ -9,403 +9,390 @@
#include <array>
// included header files
#include "image.hpp"
#include "error.hpp"
#include "image.hpp"
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Helper class, has methods to deal with %Photoshop "Information
Resource Blocks" (IRBs).
*/
struct EXIV2API Photoshop {
// Todo: Public for now
static constexpr std::array<const char*, 4> irbId_{"8BIM", "AgHg", "DCSR", "PHUT"}; //!< %Photoshop IRB markers
inline static const char* ps3Id_ = "Photoshop 3.0\0"; //!< %Photoshop marker
inline static const char* bimId_ = "8BIM"; //!< %Photoshop IRB marker (deprecated)
inline static const uint16_t iptc_ = 0x0404; //!< %Photoshop IPTC marker
inline static const uint16_t preview_ = 0x040c; //!< %Photoshop preview marker
/*!
@brief Checks an IRB
@param pPsData Existing IRB buffer
@param sizePsData Size of the IRB buffer
@return true if the IRB marker is known and the buffer is big enough to check this;<BR>
false otherwise
*/
static bool isIrb(const byte* pPsData, size_t sizePsData);
/*!
@brief Validates all IRBs
@param pPsData Existing IRB buffer
@param sizePsData Size of the IRB buffer, may be 0
@return true if all IRBs are valid;<BR>
false otherwise
*/
static bool valid(const byte* pPsData, size_t sizePsData);
/*!
@brief Locates the data for a %Photoshop tag in a %Photoshop formated memory
buffer. Operates on raw data to simplify reuse.
@param pPsData Pointer to buffer containing entire payload of
%Photoshop formated data, e.g., from APP13 Jpeg segment.
@param sizePsData Size in bytes of pPsData.
@param psTag %Tag number of the block to look for.
@param record Output value that is set to the start of the
data block within pPsData (may not be null).
@param sizeHdr Output value that is set to the size of the header
within the data block pointed to by record (may not be null).
@param sizeData Output value that is set to the size of the actual
data within the data block pointed to by record (may not be null).
@return 0 if successful;<BR>
3 if no data for psTag was found in pPsData;<BR>
-2 if the pPsData buffer does not contain valid data.
*/
static int locateIrb(const byte *pPsData,
size_t sizePsData,
uint16_t psTag,
const byte **record,
uint32_t *const sizeHdr,
uint32_t *const sizeData);
/*!
@brief Forwards to locateIrb() with \em psTag = \em iptc_
*/
static int locateIptcIrb(const byte *pPsData,
size_t sizePsData,
const byte **record,
uint32_t *const sizeHdr,
uint32_t *const sizeData);
/*!
@brief Forwards to locatePreviewIrb() with \em psTag = \em preview_
*/
static int locatePreviewIrb(const byte *pPsData,
size_t sizePsData,
const byte **record,
uint32_t *const sizeHdr,
uint32_t *const sizeData);
/*!
@brief Set the new IPTC IRB, keeps existing IRBs but removes the
IPTC block if there is no new IPTC data to write.
@param pPsData Existing IRB buffer
@param sizePsData Size of the IRB buffer, may be 0
@param iptcData Iptc data to embed, may be empty
@return A data buffer containing the new IRB buffer, may have 0 size
*/
static DataBuf setIptcIrb(const byte* pPsData, size_t sizePsData, const IptcData& iptcData);
}; // class Photoshop
/*!
@brief Abstract helper base class to access JPEG images.
*/
class EXIV2API JpegBase : public Image {
public:
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
//@}
//! @name NOT implemented
//@{
//! Default constructor.
JpegBase() = delete;
//! Copy constructor
JpegBase(const JpegBase& rhs) = delete;
//! Assignment operator
JpegBase& operator=(const JpegBase& rhs) = delete;
//@}
protected:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten.
@param type Image type.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new image should be created (true).
@param initData Data to initialize newly created images. Only used
when \em create is true. Should contain data for the smallest
valid image of the calling subclass.
@param dataSize Size of initData in bytes.
*/
JpegBase(ImageType type,
BasicIo::UniquePtr io,
bool create,
const byte initData[],
size_t dataSize);
//@}
//! @name Accessors
//@{
/*!
@brief Determine if the content of the BasicIo instance is of the
type supported by this class.
The advance flag determines if the read position in the stream is
moved (see below). This applies only if the type matches and the
function returns true. If the type does not match, the stream
position is not changed. However, if reading from the stream fails,
the stream position is undefined. Consult the stream state to obtain
more information in this case.
@param iIo BasicIo instance to read from.
@param advance Flag indicating whether the position of the io
should be advanced by the number of characters read to
analyse the data (true) or left at its original
position (false). This applies only if the type matches.
@return true if the data matches the type of this class;<BR>
false if the data does not match
*/
virtual bool isThisType(BasicIo& iIo, bool advance) const =0;
//@}
//! @name Manipulators
//@{
/*!
@brief Writes the image header (aka signature) to the BasicIo instance.
@param oIo BasicIo instance that the header is written to.
@return 0 if successful;<BR>
4 if the output file can not be written to
*/
virtual int writeHeader(BasicIo& oIo) const =0;
//@}
// Constant Data
static constexpr byte dht_ = 0xc4; //!< JPEG DHT marker
static constexpr byte dqt_ = 0xdb; //!< JPEG DQT marker
static constexpr byte dri_ = 0xdd; //!< JPEG DRI marker
static constexpr byte sos_ = 0xda; //!< JPEG SOS marker
static constexpr byte eoi_ = 0xd9; //!< JPEG EOI marker
static constexpr byte app0_ = 0xe0; //!< JPEG APP0 marker
static constexpr byte app1_ = 0xe1; //!< JPEG APP1 marker
static constexpr byte app2_ = 0xe2; //!< JPEG APP2 marker
static constexpr byte app13_ = 0xed; //!< JPEG APP13 marker
static constexpr byte com_ = 0xfe; //!< JPEG Comment marker
// Start of Frame markers, nondifferential Huffman-coding frames
static constexpr byte sof0_ = 0xc0; //!< JPEG Start-Of-Frame marker
static constexpr byte sof1_ = 0xc1; //!< JPEG Start-Of-Frame marker
static constexpr byte sof2_ = 0xc2; //!< JPEG Start-Of-Frame marker
static constexpr byte sof3_ = 0xc3; //!< JPEG Start-Of-Frame marker
// Start of Frame markers, differential Huffman-coding frames
static constexpr byte sof5_ = 0xc5; //!< JPEG Start-Of-Frame marker
static constexpr byte sof6_ = 0xc6; //!< JPEG Start-Of-Frame marker
static constexpr byte sof7_ = 0xc7; //!< JPEG Start-Of-Frame marker
// Start of Frame markers, nondifferential arithmetic-coding frames
static constexpr byte sof9_ = 0xc9; //!< JPEG Start-Of-Frame marker
static constexpr byte sof10_ = 0xca; //!< JPEG Start-Of-Frame marker
static constexpr byte sof11_ = 0xcb; //!< JPEG Start-Of-Frame marker
// Start of Frame markers, differential arithmetic-coding frames
static constexpr byte sof13_ = 0xcd; //!< JPEG Start-Of-Frame marker
static constexpr byte sof14_ = 0xce; //!< JPEG Start-Of-Frame marker
static constexpr byte sof15_ = 0xcf; //!< JPEG Start-Of-Frame marker
static constexpr auto exifId_ = "Exif\0\0"; //!< Exif identifier
static constexpr auto jfifId_ = "JFIF\0"; //!< JFIF identifier
static constexpr auto xmpId_ = "http://ns.adobe.com/xap/1.0/\0"; //!< XMP packet identifier
static constexpr auto iccId_ = "ICC_PROFILE\0"; //!< ICC profile identifier
private:
//! @name Manipulators
//@{
/*!
@brief Initialize the image with the provided data.
@param initData Data to be written to the associated BasicIo
@param dataSize Size in bytes of data to be written
@return 0 if successful;<BR>
4 if the image can not be written to.
*/
int initImage(const byte initData[], size_t dataSize);
/*!
@brief Provides the main implementation of writeMetadata() by
writing all buffered metadata to the provided BasicIo.
@param oIo BasicIo instance to write to (a temporary location).
@return 4 if opening or writing to the associated BasicIo fails
*/
void doWriteMetadata(BasicIo& outIo);
//@}
//! @name Accessors
//@{
/*!
@brief Advances associated io instance to one byte past the next
Jpeg marker and returns the marker. This method should be called
when the BasicIo instance is positioned one byte past the end of a
Jpeg segment.
@param err the error code to throw if no marker is found
@return the next Jpeg segment marker if successful;<BR>
throws an Error if not successful
*/
byte advanceToMarker(ErrorCode err) const;
//@}
DataBuf readNextSegment(byte marker);
/*!
@brief Is the marker followed by a non-zero payload?
@param marker The marker at the start of a segment
@return true if the marker is followed by a non-zero payload
*/
static bool markerHasLength(byte marker);
}; // class JpegBase
/*!
@brief Class to access JPEG images
*/
class EXIV2API JpegImage : public JpegBase {
friend EXIV2API bool isJpegType(BasicIo& iIo, bool advance);
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing Jpeg image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
JpegImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
// NOT Implemented
//! Default constructor
JpegImage() = delete;
//! Copy constructor
JpegImage(const JpegImage& rhs) = delete;
//! Assignment operator
JpegImage& operator=(const JpegImage& rhs) = delete;
protected:
//! @name Accessors
//@{
bool isThisType(BasicIo& iIo, bool advance) const override;
//@}
//! @name Manipulators
//@{
/*!
@brief Writes a Jpeg header (aka signature) to the BasicIo instance.
@param oIo BasicIo instance that the header is written to.
@return 0 if successful;<BR>
2 if the input image is invalid or can not be read;<BR>
4 if the temporary image can not be written to;<BR>
-3 other temporary errors
*/
int writeHeader(BasicIo& outIo) const override;
//@}
private:
// Constant data
static const byte soi_; // SOI marker
static const byte blank_[]; // Minimal Jpeg image
}; // class JpegImage
//! Helper class to access %Exiv2 files
class EXIV2API ExvImage : public JpegBase {
friend EXIV2API bool isExvType(BasicIo& iIo, bool advance);
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing EXV image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
ExvImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
// NOT Implemented
//! Default constructor
ExvImage() = delete;
//! Copy constructor
ExvImage(const ExvImage& rhs) = delete;
//! Assignment operator
ExvImage& operator=(const ExvImage& rhs) = delete;
protected:
//! @name Accessors
//@{
bool isThisType(BasicIo& iIo, bool advance) const override;
//@}
//! @name Manipulators
//@{
int writeHeader(BasicIo& outIo) const override;
//@}
private:
// Constant data
static constexpr char exiv2Id_[] = "Exiv2"; // EXV identifier
static constexpr byte blank_[] = {0xff, 0x01, 'E', 'x', 'i', 'v', '2', 0xff, 0xd9}; // Minimal exiv2 file
}; // class ExvImage
/*!
@brief Helper class, has methods to deal with %Photoshop "Information
Resource Blocks" (IRBs).
*/
struct EXIV2API Photoshop {
// Todo: Public for now
static constexpr std::array<const char*, 4> irbId_{"8BIM", "AgHg", "DCSR", "PHUT"}; //!< %Photoshop IRB markers
inline static const char* ps3Id_ = "Photoshop 3.0\0"; //!< %Photoshop marker
inline static const char* bimId_ = "8BIM"; //!< %Photoshop IRB marker (deprecated)
inline static const uint16_t iptc_ = 0x0404; //!< %Photoshop IPTC marker
inline static const uint16_t preview_ = 0x040c; //!< %Photoshop preview marker
/*!
@brief Checks an IRB
@param pPsData Existing IRB buffer
@param sizePsData Size of the IRB buffer
@return true if the IRB marker is known and the buffer is big enough to check this;<BR>
false otherwise
*/
static bool isIrb(const byte* pPsData, size_t sizePsData);
/*!
@brief Validates all IRBs
@param pPsData Existing IRB buffer
@param sizePsData Size of the IRB buffer, may be 0
@return true if all IRBs are valid;<BR>
false otherwise
*/
static bool valid(const byte* pPsData, size_t sizePsData);
/*!
@brief Locates the data for a %Photoshop tag in a %Photoshop formated memory
buffer. Operates on raw data to simplify reuse.
@param pPsData Pointer to buffer containing entire payload of
%Photoshop formated data, e.g., from APP13 Jpeg segment.
@param sizePsData Size in bytes of pPsData.
@param psTag %Tag number of the block to look for.
@param record Output value that is set to the start of the
data block within pPsData (may not be null).
@param sizeHdr Output value that is set to the size of the header
within the data block pointed to by record (may not be null).
@param sizeData Output value that is set to the size of the actual
data within the data block pointed to by record (may not be null).
@return 0 if successful;<BR>
3 if no data for psTag was found in pPsData;<BR>
-2 if the pPsData buffer does not contain valid data.
*/
static int locateIrb(const byte* pPsData, size_t sizePsData, uint16_t psTag, const byte** record,
uint32_t* const sizeHdr, uint32_t* const sizeData);
/*!
@brief Forwards to locateIrb() with \em psTag = \em iptc_
*/
static int locateIptcIrb(const byte* pPsData, size_t sizePsData, const byte** record, uint32_t* const sizeHdr,
uint32_t* const sizeData);
/*!
@brief Forwards to locatePreviewIrb() with \em psTag = \em preview_
*/
static int locatePreviewIrb(const byte* pPsData, size_t sizePsData, const byte** record, uint32_t* const sizeHdr,
uint32_t* const sizeData);
/*!
@brief Set the new IPTC IRB, keeps existing IRBs but removes the
IPTC block if there is no new IPTC data to write.
@param pPsData Existing IRB buffer
@param sizePsData Size of the IRB buffer, may be 0
@param iptcData Iptc data to embed, may be empty
@return A data buffer containing the new IRB buffer, may have 0 size
*/
static DataBuf setIptcIrb(const byte* pPsData, size_t sizePsData, const IptcData& iptcData);
}; // class Photoshop
/*!
@brief Abstract helper base class to access JPEG images.
*/
class EXIV2API JpegBase : public Image {
public:
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
//@}
//! @name NOT implemented
//@{
//! Default constructor.
JpegBase() = delete;
//! Copy constructor
JpegBase(const JpegBase& rhs) = delete;
//! Assignment operator
JpegBase& operator=(const JpegBase& rhs) = delete;
//@}
protected:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten.
@param type Image type.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new image should be created (true).
@param initData Data to initialize newly created images. Only used
when \em create is true. Should contain data for the smallest
valid image of the calling subclass.
@param dataSize Size of initData in bytes.
*/
JpegBase(ImageType type, BasicIo::UniquePtr io, bool create, const byte initData[], size_t dataSize);
//@}
//! @name Accessors
//@{
/*!
@brief Determine if the content of the BasicIo instance is of the
type supported by this class.
The advance flag determines if the read position in the stream is
moved (see below). This applies only if the type matches and the
function returns true. If the type does not match, the stream
position is not changed. However, if reading from the stream fails,
the stream position is undefined. Consult the stream state to obtain
more information in this case.
@param iIo BasicIo instance to read from.
@param advance Flag indicating whether the position of the io
should be advanced by the number of characters read to
analyse the data (true) or left at its original
position (false). This applies only if the type matches.
@return true if the data matches the type of this class;<BR>
false if the data does not match
*/
virtual bool isThisType(BasicIo& iIo, bool advance) const = 0;
//@}
//! @name Manipulators
//@{
/*!
@brief Writes the image header (aka signature) to the BasicIo instance.
@param oIo BasicIo instance that the header is written to.
@return 0 if successful;<BR>
4 if the output file can not be written to
*/
virtual int writeHeader(BasicIo& oIo) const = 0;
//@}
// Constant Data
static constexpr byte dht_ = 0xc4; //!< JPEG DHT marker
static constexpr byte dqt_ = 0xdb; //!< JPEG DQT marker
static constexpr byte dri_ = 0xdd; //!< JPEG DRI marker
static constexpr byte sos_ = 0xda; //!< JPEG SOS marker
static constexpr byte eoi_ = 0xd9; //!< JPEG EOI marker
static constexpr byte app0_ = 0xe0; //!< JPEG APP0 marker
static constexpr byte app1_ = 0xe1; //!< JPEG APP1 marker
static constexpr byte app2_ = 0xe2; //!< JPEG APP2 marker
static constexpr byte app13_ = 0xed; //!< JPEG APP13 marker
static constexpr byte com_ = 0xfe; //!< JPEG Comment marker
// Start of Frame markers, nondifferential Huffman-coding frames
static constexpr byte sof0_ = 0xc0; //!< JPEG Start-Of-Frame marker
static constexpr byte sof1_ = 0xc1; //!< JPEG Start-Of-Frame marker
static constexpr byte sof2_ = 0xc2; //!< JPEG Start-Of-Frame marker
static constexpr byte sof3_ = 0xc3; //!< JPEG Start-Of-Frame marker
// Start of Frame markers, differential Huffman-coding frames
static constexpr byte sof5_ = 0xc5; //!< JPEG Start-Of-Frame marker
static constexpr byte sof6_ = 0xc6; //!< JPEG Start-Of-Frame marker
static constexpr byte sof7_ = 0xc7; //!< JPEG Start-Of-Frame marker
// Start of Frame markers, nondifferential arithmetic-coding frames
static constexpr byte sof9_ = 0xc9; //!< JPEG Start-Of-Frame marker
static constexpr byte sof10_ = 0xca; //!< JPEG Start-Of-Frame marker
static constexpr byte sof11_ = 0xcb; //!< JPEG Start-Of-Frame marker
// Start of Frame markers, differential arithmetic-coding frames
static constexpr byte sof13_ = 0xcd; //!< JPEG Start-Of-Frame marker
static constexpr byte sof14_ = 0xce; //!< JPEG Start-Of-Frame marker
static constexpr byte sof15_ = 0xcf; //!< JPEG Start-Of-Frame marker
static constexpr auto exifId_ = "Exif\0\0"; //!< Exif identifier
static constexpr auto jfifId_ = "JFIF\0"; //!< JFIF identifier
static constexpr auto xmpId_ = "http://ns.adobe.com/xap/1.0/\0"; //!< XMP packet identifier
static constexpr auto iccId_ = "ICC_PROFILE\0"; //!< ICC profile identifier
private:
//! @name Manipulators
//@{
/*!
@brief Initialize the image with the provided data.
@param initData Data to be written to the associated BasicIo
@param dataSize Size in bytes of data to be written
@return 0 if successful;<BR>
4 if the image can not be written to.
*/
int initImage(const byte initData[], size_t dataSize);
/*!
@brief Provides the main implementation of writeMetadata() by
writing all buffered metadata to the provided BasicIo.
@param oIo BasicIo instance to write to (a temporary location).
@return 4 if opening or writing to the associated BasicIo fails
*/
void doWriteMetadata(BasicIo& outIo);
//@}
//! @name Accessors
//@{
/*!
@brief Advances associated io instance to one byte past the next
Jpeg marker and returns the marker. This method should be called
when the BasicIo instance is positioned one byte past the end of a
Jpeg segment.
@param err the error code to throw if no marker is found
@return the next Jpeg segment marker if successful;<BR>
throws an Error if not successful
*/
byte advanceToMarker(ErrorCode err) const;
//@}
DataBuf readNextSegment(byte marker);
/*!
@brief Is the marker followed by a non-zero payload?
@param marker The marker at the start of a segment
@return true if the marker is followed by a non-zero payload
*/
static bool markerHasLength(byte marker);
}; // class JpegBase
/*!
@brief Class to access JPEG images
*/
class EXIV2API JpegImage : public JpegBase {
friend EXIV2API bool isJpegType(BasicIo& iIo, bool advance);
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing Jpeg image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
JpegImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
// NOT Implemented
//! Default constructor
JpegImage() = delete;
//! Copy constructor
JpegImage(const JpegImage& rhs) = delete;
//! Assignment operator
JpegImage& operator=(const JpegImage& rhs) = delete;
protected:
//! @name Accessors
//@{
bool isThisType(BasicIo& iIo, bool advance) const override;
//@}
//! @name Manipulators
//@{
/*!
@brief Writes a Jpeg header (aka signature) to the BasicIo instance.
@param oIo BasicIo instance that the header is written to.
@return 0 if successful;<BR>
2 if the input image is invalid or can not be read;<BR>
4 if the temporary image can not be written to;<BR>
-3 other temporary errors
*/
int writeHeader(BasicIo& outIo) const override;
//@}
private:
// Constant data
static const byte soi_; // SOI marker
static const byte blank_[]; // Minimal Jpeg image
}; // class JpegImage
//! Helper class to access %Exiv2 files
class EXIV2API ExvImage : public JpegBase {
friend EXIV2API bool isExvType(BasicIo& iIo, bool advance);
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing EXV image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
ExvImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
// NOT Implemented
//! Default constructor
ExvImage() = delete;
//! Copy constructor
ExvImage(const ExvImage& rhs) = delete;
//! Assignment operator
ExvImage& operator=(const ExvImage& rhs) = delete;
protected:
//! @name Accessors
//@{
bool isThisType(BasicIo& iIo, bool advance) const override;
//@}
//! @name Manipulators
//@{
int writeHeader(BasicIo& outIo) const override;
//@}
private:
// Constant data
static constexpr char exiv2Id_[] = "Exiv2"; // EXV identifier
static constexpr byte blank_[] = {0xff, 0x01, 'E', 'x', 'i', 'v', '2', 0xff, 0xd9}; // Minimal exiv2 file
}; // class ExvImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new JpegImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newJpegInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a JPEG image.
EXIV2API bool isJpegType(BasicIo& iIo, bool advance);
/*!
@brief Create a new ExvImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newExvInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is an EXV file
EXIV2API bool isExvType(BasicIo& iIo, bool advance);
} // namespace Exiv2
#endif // #ifndef JPGIMAGE_HPP_
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new JpegImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newJpegInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a JPEG image.
EXIV2API bool isJpegType(BasicIo& iIo, bool advance);
/*!
@brief Create a new ExvImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newExvInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is an EXV file
EXIV2API bool isExvType(BasicIo& iIo, bool advance);
} // namespace Exiv2
#endif // #ifndef JPGIMAGE_HPP_

@ -12,278 +12,277 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class ExifData;
class ExifData;
// *****************************************************************************
// class definitions
/*!
@brief Abstract base class defining the %Key of a metadatum.
Keys are used to identify and group metadata.
*/
class EXIV2API Key {
public:
//! Shortcut for a %Key auto pointer.
using UniquePtr = std::unique_ptr<Key>;
//! @name Creators
//@{
//! Destructor
virtual ~Key() = default;
//@}
//! @name Accessors
//@{
/*!
@brief Return the key of the metadatum as a string. The key is of the
form 'familyName.groupName.tagName'. Note however that the
key is not necessarily unique, e.g., an ExifData may contain
multiple metadata with the same key.
*/
virtual std::string key() const =0;
//! Return an identifier for the type of metadata (the first part of the key)
virtual const char* familyName() const =0;
//! Return the name of the group (the second part of the key)
virtual std::string groupName() const =0;
//! Return the name of the tag (which is also the third part of the key)
virtual std::string tagName() const =0;
//! Return a label for the tag
virtual std::string tagLabel() const =0;
//! Return the tag number
virtual uint16_t tag() const =0;
/*!
@brief Return an auto-pointer to a copy of itself (deep copy).
The caller owns this copy and the auto-pointer ensures that it
will be deleted.
*/
UniquePtr clone() const;
/*!
@brief Write the key to an output stream. You do not usually have
to use this function; it is used for the implementation of
the output operator for %Key,
operator<<(std::ostream &os, const Key &key).
*/
std::ostream& write(std::ostream& os) const { return os << key(); }
//@}
protected:
//! @name Manipulators
//@{
/*!
@brief Assignment operator. Protected so that it can only be used
by subclasses but not directly.
*/
Key& operator=(const Key& rhs) = default;
//@}
private:
//! Internal virtual copy constructor.
virtual Key* clone_() const =0;
}; // class Key
//! Output operator for Key types
inline std::ostream& operator<<(std::ostream& os, const Key& key)
{
return key.write(os);
}
/*!
@brief Abstract base class defining the interface to access information
related to one metadata tag.
*/
class EXIV2API Metadatum {
public:
//! @name Creators
//@{
//! Default Constructor
Metadatum() = default;
//! Copy constructor
Metadatum(const Metadatum& rhs) = default;
//! Destructor
virtual ~Metadatum() = default;
//@}
//! @name Manipulators
//@{
/*!
@brief Set the value. This method copies (clones) the value pointed
to by pValue.
*/
virtual void setValue(const Value* pValue) =0;
/*!
@brief Set the value to the string buf.
Uses Value::read(const std::string& buf). If the metadatum does
not have a value yet, then one is created. See subclasses for
more details. Return 0 if the value was read successfully.
*/
virtual int setValue(const std::string& buf) =0;
//@}
//! @name Accessors
//@{
/*!
@brief Write the interpreted value to a string.
Implemented in terms of write(), see there.
*/
std::string print(const ExifData* pMetadata = nullptr) const;
/*!
@brief Write value to a data buffer and return the number
of bytes written.
The user must ensure that the buffer has enough memory. Otherwise
the call results in undefined behaviour.
@param buf Data buffer to write to.
@param byteOrder Applicable byte order (little or big endian).
@return Number of characters written.
*/
virtual size_t copy(byte* buf, ByteOrder byteOrder) const =0;
/*!
@brief Write the interpreted value to an output stream, return
the stream.
The method takes an optional pointer to a metadata container.
Pretty-print functions may use that to refer to other metadata as it
is sometimes not sufficient to know only the value of the metadatum
that should be interpreted. Thus, it is advisable to always call this
method with a pointer to the metadata container if possible.
This functionality is currently only implemented for Exif tags.
The pointer is ignored when used to write IPTC datasets or XMP
properties.
Without the optional metadata pointer, you do not usually have to use
this function; it is used for the implementation of the output
operator for %Metadatum,
operator<<(std::ostream &os, const Metadatum &md).
See also print(), which prints the interpreted value to a string.
*/
virtual std::ostream& write(std::ostream& os, const ExifData* pMetadata = nullptr) const = 0;
/*!
@brief Return the key of the metadatum. The key is of the form
'familyName.groupName.tagName'. Note however that the key
is not necessarily unique, e.g., an ExifData object may
contain multiple metadata with the same key.
*/
virtual std::string key() const =0;
//! Return the name of the metadata family (which is also the first part of the key)
virtual const char* familyName() const =0;
//! Return the name of the metadata group (which is also the second part of the key)
virtual std::string groupName() const =0;
//! Return the name of the tag (which is also the third part of the key)
virtual std::string tagName() const =0;
//! Return a label for the tag
virtual std::string tagLabel() const =0;
//! Return the tag
virtual uint16_t tag() const =0;
//! Return the type id of the value
virtual TypeId typeId() const =0;
//! Return the name of the type
virtual const char* typeName() const =0;
//! Return the size in bytes of one component of this type
virtual size_t typeSize() const =0;
//! Return the number of components in the value
virtual size_t count() const =0;
//! Return the size of the value in bytes
virtual size_t size() const =0;
//! Return the value as a string.
virtual std::string toString() const =0;
/*!
@brief Return the <EM>n</EM>-th component of the value converted to
a string. The behaviour of the method is undefined if there
is no <EM>n</EM>-th component.
*/
virtual std::string toString(size_t n) const =0;
/*!
@brief Return the <EM>n</EM>-th component of the value converted to int64_t.
The return value is -1 if the value is not set and the behaviour
of the method is undefined if there is no <EM>n</EM>-th component.
*/
virtual int64_t toInt64(size_t n =0) const =0;
/*!
@brief Return the <EM>n</EM>-th component of the value converted to uint32_t.
*/
uint32_t toUint32(size_t n =0) const;
/*!
@brief Return the <EM>n</EM>-th component of the value converted to float.
The return value is -1 if the value is not set and the behaviour
of the method is undefined if there is no <EM>n</EM>-th component.
*/
virtual float toFloat(size_t n =0) const =0;
/*!
@brief Return the <EM>n</EM>-th component of the value converted to Rational.
The return value is -1/1 if the value is not set and the behaviour
of the method is undefined if there is no <EM>n</EM>-th component.
*/
virtual Rational toRational(size_t n =0) const =0;
/*!
@brief Return an auto-pointer to a copy (clone) of the value. The
caller owns this copy and the auto-poiner ensures that it will
be deleted.
This method is provided for users who need full control over the
value. A caller may, e.g., downcast the pointer to the appropriate
subclass of Value to make use of the interface of the subclass to set
or modify its contents.
@return An auto-pointer containing a pointer to a copy (clone) of the
value, 0 if the value is not set.
*/
virtual Value::UniquePtr getValue() const =0;
/*!
@brief Return a constant reference to the value.
This method is provided mostly for convenient and versatile output of
the value which can (to some extent) be formatted through standard
stream manipulators. Do not attempt to write to the value through
this reference. An Error is thrown if the value is not set; as an
alternative to catching it, one can use count() to check if there
is any data before calling this method.
@return A constant reference to the value.
@throw Error if the value is not set.
*/
virtual const Value& value() const =0;
//@}
protected:
//! @name Manipulators
//@{
/*!
@brief Assignment operator. Protected so that it can only be used
by subclasses but not directly.
*/
Metadatum& operator=(const Metadatum& rhs) = default;
//@}
}; // class Metadatum
/*!
@brief Output operator for Metadatum types, writing the interpreted
tag value.
*/
inline std::ostream& operator<<(std::ostream& os, const Metadatum& md)
{
return md.write(os);
}
/*!
@brief Compare two metadata by tag. Return true if the tag of metadatum
lhs is less than that of rhs.
*/
EXIV2API bool cmpMetadataByTag(const Metadatum& lhs, const Metadatum& rhs);
/*!
@brief Compare two metadata by key. Return true if the key of metadatum
lhs is less than that of rhs.
*/
EXIV2API bool cmpMetadataByKey(const Metadatum& lhs, const Metadatum& rhs);
} // namespace Exiv2
#endif // #ifndef METADATUM_HPP_
/*!
@brief Abstract base class defining the %Key of a metadatum.
Keys are used to identify and group metadata.
*/
class EXIV2API Key {
public:
//! Shortcut for a %Key auto pointer.
using UniquePtr = std::unique_ptr<Key>;
//! @name Creators
//@{
//! Destructor
virtual ~Key() = default;
//@}
//! @name Accessors
//@{
/*!
@brief Return the key of the metadatum as a string. The key is of the
form 'familyName.groupName.tagName'. Note however that the
key is not necessarily unique, e.g., an ExifData may contain
multiple metadata with the same key.
*/
virtual std::string key() const = 0;
//! Return an identifier for the type of metadata (the first part of the key)
virtual const char* familyName() const = 0;
//! Return the name of the group (the second part of the key)
virtual std::string groupName() const = 0;
//! Return the name of the tag (which is also the third part of the key)
virtual std::string tagName() const = 0;
//! Return a label for the tag
virtual std::string tagLabel() const = 0;
//! Return the tag number
virtual uint16_t tag() const = 0;
/*!
@brief Return an auto-pointer to a copy of itself (deep copy).
The caller owns this copy and the auto-pointer ensures that it
will be deleted.
*/
UniquePtr clone() const;
/*!
@brief Write the key to an output stream. You do not usually have
to use this function; it is used for the implementation of
the output operator for %Key,
operator<<(std::ostream &os, const Key &key).
*/
std::ostream& write(std::ostream& os) const {
return os << key();
}
//@}
protected:
//! @name Manipulators
//@{
/*!
@brief Assignment operator. Protected so that it can only be used
by subclasses but not directly.
*/
Key& operator=(const Key& rhs) = default;
//@}
private:
//! Internal virtual copy constructor.
virtual Key* clone_() const = 0;
}; // class Key
//! Output operator for Key types
inline std::ostream& operator<<(std::ostream& os, const Key& key) {
return key.write(os);
}
/*!
@brief Abstract base class defining the interface to access information
related to one metadata tag.
*/
class EXIV2API Metadatum {
public:
//! @name Creators
//@{
//! Default Constructor
Metadatum() = default;
//! Copy constructor
Metadatum(const Metadatum& rhs) = default;
//! Destructor
virtual ~Metadatum() = default;
//@}
//! @name Manipulators
//@{
/*!
@brief Set the value. This method copies (clones) the value pointed
to by pValue.
*/
virtual void setValue(const Value* pValue) = 0;
/*!
@brief Set the value to the string buf.
Uses Value::read(const std::string& buf). If the metadatum does
not have a value yet, then one is created. See subclasses for
more details. Return 0 if the value was read successfully.
*/
virtual int setValue(const std::string& buf) = 0;
//@}
//! @name Accessors
//@{
/*!
@brief Write the interpreted value to a string.
Implemented in terms of write(), see there.
*/
std::string print(const ExifData* pMetadata = nullptr) const;
/*!
@brief Write value to a data buffer and return the number
of bytes written.
The user must ensure that the buffer has enough memory. Otherwise
the call results in undefined behaviour.
@param buf Data buffer to write to.
@param byteOrder Applicable byte order (little or big endian).
@return Number of characters written.
*/
virtual size_t copy(byte* buf, ByteOrder byteOrder) const = 0;
/*!
@brief Write the interpreted value to an output stream, return
the stream.
The method takes an optional pointer to a metadata container.
Pretty-print functions may use that to refer to other metadata as it
is sometimes not sufficient to know only the value of the metadatum
that should be interpreted. Thus, it is advisable to always call this
method with a pointer to the metadata container if possible.
This functionality is currently only implemented for Exif tags.
The pointer is ignored when used to write IPTC datasets or XMP
properties.
Without the optional metadata pointer, you do not usually have to use
this function; it is used for the implementation of the output
operator for %Metadatum,
operator<<(std::ostream &os, const Metadatum &md).
See also print(), which prints the interpreted value to a string.
*/
virtual std::ostream& write(std::ostream& os, const ExifData* pMetadata = nullptr) const = 0;
/*!
@brief Return the key of the metadatum. The key is of the form
'familyName.groupName.tagName'. Note however that the key
is not necessarily unique, e.g., an ExifData object may
contain multiple metadata with the same key.
*/
virtual std::string key() const = 0;
//! Return the name of the metadata family (which is also the first part of the key)
virtual const char* familyName() const = 0;
//! Return the name of the metadata group (which is also the second part of the key)
virtual std::string groupName() const = 0;
//! Return the name of the tag (which is also the third part of the key)
virtual std::string tagName() const = 0;
//! Return a label for the tag
virtual std::string tagLabel() const = 0;
//! Return the tag
virtual uint16_t tag() const = 0;
//! Return the type id of the value
virtual TypeId typeId() const = 0;
//! Return the name of the type
virtual const char* typeName() const = 0;
//! Return the size in bytes of one component of this type
virtual size_t typeSize() const = 0;
//! Return the number of components in the value
virtual size_t count() const = 0;
//! Return the size of the value in bytes
virtual size_t size() const = 0;
//! Return the value as a string.
virtual std::string toString() const = 0;
/*!
@brief Return the <EM>n</EM>-th component of the value converted to
a string. The behaviour of the method is undefined if there
is no <EM>n</EM>-th component.
*/
virtual std::string toString(size_t n) const = 0;
/*!
@brief Return the <EM>n</EM>-th component of the value converted to int64_t.
The return value is -1 if the value is not set and the behaviour
of the method is undefined if there is no <EM>n</EM>-th component.
*/
virtual int64_t toInt64(size_t n = 0) const = 0;
/*!
@brief Return the <EM>n</EM>-th component of the value converted to uint32_t.
*/
uint32_t toUint32(size_t n = 0) const;
/*!
@brief Return the <EM>n</EM>-th component of the value converted to float.
The return value is -1 if the value is not set and the behaviour
of the method is undefined if there is no <EM>n</EM>-th component.
*/
virtual float toFloat(size_t n = 0) const = 0;
/*!
@brief Return the <EM>n</EM>-th component of the value converted to Rational.
The return value is -1/1 if the value is not set and the behaviour
of the method is undefined if there is no <EM>n</EM>-th component.
*/
virtual Rational toRational(size_t n = 0) const = 0;
/*!
@brief Return an auto-pointer to a copy (clone) of the value. The
caller owns this copy and the auto-poiner ensures that it will
be deleted.
This method is provided for users who need full control over the
value. A caller may, e.g., downcast the pointer to the appropriate
subclass of Value to make use of the interface of the subclass to set
or modify its contents.
@return An auto-pointer containing a pointer to a copy (clone) of the
value, 0 if the value is not set.
*/
virtual Value::UniquePtr getValue() const = 0;
/*!
@brief Return a constant reference to the value.
This method is provided mostly for convenient and versatile output of
the value which can (to some extent) be formatted through standard
stream manipulators. Do not attempt to write to the value through
this reference. An Error is thrown if the value is not set; as an
alternative to catching it, one can use count() to check if there
is any data before calling this method.
@return A constant reference to the value.
@throw Error if the value is not set.
*/
virtual const Value& value() const = 0;
//@}
protected:
//! @name Manipulators
//@{
/*!
@brief Assignment operator. Protected so that it can only be used
by subclasses but not directly.
*/
Metadatum& operator=(const Metadatum& rhs) = default;
//@}
}; // class Metadatum
/*!
@brief Output operator for Metadatum types, writing the interpreted
tag value.
*/
inline std::ostream& operator<<(std::ostream& os, const Metadatum& md) {
return md.write(os);
}
/*!
@brief Compare two metadata by tag. Return true if the tag of metadatum
lhs is less than that of rhs.
*/
EXIV2API bool cmpMetadataByTag(const Metadatum& lhs, const Metadatum& rhs);
/*!
@brief Compare two metadata by key. Return true if the key of metadatum
lhs is less than that of rhs.
*/
EXIV2API bool cmpMetadataByKey(const Metadatum& lhs, const Metadatum& rhs);
} // namespace Exiv2
#endif // #ifndef METADATUM_HPP_

@ -12,92 +12,91 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access raw Minolta MRW images. Exif metadata is supported
directly, IPTC is read from the Exif data, if present.
*/
class EXIV2API MrwImage : public Image {
public:
//! @name NOT Implemented
//@{
//! Copy constructor
MrwImage(const MrwImage& rhs) = delete;
//! Assignment operator
MrwImage& operator=(const MrwImage& rhs) = delete;
//@}
/*!
@brief Class to access raw Minolta MRW images. Exif metadata is supported
directly, IPTC is read from the Exif data, if present.
*/
class EXIV2API MrwImage : public Image {
public:
//! @name NOT Implemented
//@{
//! Copy constructor
MrwImage(const MrwImage& rhs) = delete;
//! Assignment operator
MrwImage& operator=(const MrwImage& rhs) = delete;
//@}
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing MRW image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
MrwImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing MRW image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
MrwImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
/*!
@brief Todo: Write metadata back to the image. This method is not
yet implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported).
*/
void writeMetadata() override;
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setExifData(const ExifData& exifData) override;
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setIptcData(const IptcData& iptcData) override;
/*!
@brief Not supported. MRW format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Manipulators
//@{
void readMetadata() override;
/*!
@brief Todo: Write metadata back to the image. This method is not
yet implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported).
*/
void writeMetadata() override;
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setExifData(const ExifData& exifData) override;
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setIptcData(const IptcData& iptcData) override;
/*!
@brief Not supported. MRW format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
}; // class MrwImage
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
}; // class MrwImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new MrwImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newMrwInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new MrwImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newMrwInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a MRW image.
EXIV2API bool isMrwType(BasicIo& iIo, bool advance);
//! Check if the file iIo is a MRW image.
EXIV2API bool isMrwType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef MRWIMAGE_HPP_
#endif // #ifndef MRWIMAGE_HPP_

@ -12,107 +12,99 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access raw Olympus ORF images. Exif metadata is supported
directly, IPTC is read from the Exif data, if present.
*/
class EXIV2API OrfImage : public TiffImage {
public:
//! @name NOT Implemented
//@{
//! Copy constructor
OrfImage(const OrfImage& rhs) = delete;
//! Assignment operator
OrfImage& operator=(const OrfImage& rhs) = delete;
//@}
/*!
@brief Class to access raw Olympus ORF images. Exif metadata is supported
directly, IPTC is read from the Exif data, if present.
*/
class EXIV2API OrfImage : public TiffImage {
public:
//! @name NOT Implemented
//@{
//! Copy constructor
OrfImage(const OrfImage& rhs) = delete;
//! Assignment operator
OrfImage& operator=(const OrfImage& rhs) = delete;
//@}
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing ORF image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
OrfImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing ORF image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
OrfImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Not supported. ORF format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Manipulators
//@{
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Not supported. ORF format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
}; // class OrfImage
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
}; // class OrfImage
/*!
@brief Stateless parser class for data in ORF format. Images use this
class to decode and encode ORF data.
See class TiffParser for details.
*/
class EXIV2API OrfParser {
public:
/*!
@brief Decode metadata from a buffer \em pData of length \em size
with data in ORF format to the provided metadata containers.
See TiffParser::decode().
*/
static ByteOrder decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData,
size_t size);
/*!
@brief Encode metadata from the provided metadata to ORF format.
See TiffParser::encode().
*/
static WriteMethod encode(BasicIo& io,
const byte* pData,
size_t size,
ByteOrder byteOrder,
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData
);
}; // class OrfParser
/*!
@brief Stateless parser class for data in ORF format. Images use this
class to decode and encode ORF data.
See class TiffParser for details.
*/
class EXIV2API OrfParser {
public:
/*!
@brief Decode metadata from a buffer \em pData of length \em size
with data in ORF format to the provided metadata containers.
See TiffParser::decode().
*/
static ByteOrder decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, size_t size);
/*!
@brief Encode metadata from the provided metadata to ORF format.
See TiffParser::encode().
*/
static WriteMethod encode(BasicIo& io, const byte* pData, size_t size, ByteOrder byteOrder, const ExifData& exifData,
const IptcData& iptcData, const XmpData& xmpData);
}; // class OrfParser
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new OrfImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newOrfInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new OrfImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newOrfInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is an ORF image.
EXIV2API bool isOrfType(BasicIo& iIo, bool advance);
//! Check if the file iIo is an ORF image.
EXIV2API bool isOrfType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef ORFIMAGE_HPP_
#endif // #ifndef ORFIMAGE_HPP_

@ -11,94 +11,91 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2
{
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access PGF images. Exif and IPTC metadata are supported
directly.
*/
class EXIV2API PgfImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing PGF image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
PgfImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override
{
return "image/pgf";
}
//@}
//! @name NOT implemented
//@{
//! Copy constructor
PgfImage(const PgfImage& rhs) = delete;
//! Assignment operator
PgfImage& operator=(const PgfImage& rhs) = delete;
private:
bool bSwap_; // true for bigEndian hardware, else false
/*!
@brief Provides the main implementation of writeMetadata() by
writing all buffered metadata to the provided BasicIo.
@param oIo BasicIo instance to write to (a temporary location).
@return 4 if opening or writing to the associated BasicIo fails
*/
void doWriteMetadata(BasicIo& outIo);
//! Read Magick number. Only version >= 6 is supported.
static byte readPgfMagicNumber(BasicIo& iIo);
//! Read PGF Header size encoded in 32 bits integer.
size_t readPgfHeaderSize(BasicIo& iIo) const;
//! Read header structure.
DataBuf readPgfHeaderStructure(BasicIo& iIo, uint32_t& width, uint32_t& height) const;
//@}
}; // class PgfImage
/*!
@brief Class to access PGF images. Exif and IPTC metadata are supported
directly.
*/
class EXIV2API PgfImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing PGF image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
PgfImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override {
return "image/pgf";
}
//@}
//! @name NOT implemented
//@{
//! Copy constructor
PgfImage(const PgfImage& rhs) = delete;
//! Assignment operator
PgfImage& operator=(const PgfImage& rhs) = delete;
private:
bool bSwap_; // true for bigEndian hardware, else false
/*!
@brief Provides the main implementation of writeMetadata() by
writing all buffered metadata to the provided BasicIo.
@param oIo BasicIo instance to write to (a temporary location).
@return 4 if opening or writing to the associated BasicIo fails
*/
void doWriteMetadata(BasicIo& outIo);
//! Read Magick number. Only version >= 6 is supported.
static byte readPgfMagicNumber(BasicIo& iIo);
//! Read PGF Header size encoded in 32 bits integer.
size_t readPgfHeaderSize(BasicIo& iIo) const;
//! Read header structure.
DataBuf readPgfHeaderStructure(BasicIo& iIo, uint32_t& width, uint32_t& height) const;
//@}
}; // class PgfImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new PgfImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newPgfInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new PgfImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newPgfInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a PGF image.
EXIV2API bool isPgfType(BasicIo& iIo, bool advance);
//! Check if the file iIo is a PGF image.
EXIV2API bool isPgfType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef PGFIMAGE_HPP_
#endif // #ifndef PGFIMAGE_HPP_

@ -11,94 +11,92 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2
{
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access PNG images. Exif and IPTC metadata are supported
directly.
*/
class EXIV2API PngImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing PNG image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
PngImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Print out the structure of image file.
@throw Error if reading of the file fails or the image data is
not valid (does not look like data of the specific image type).
@warning This function is not thread safe and intended for exiv2 -pS for debugging.
*/
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
//! @name NOT implemented
//@{
//! Copy constructor
PngImage(const PngImage& rhs) = delete;
//! Assignment operator
PngImage& operator=(const PngImage& rhs) = delete;
private:
/*!
@brief Provides the main implementation of writeMetadata() by
writing all buffered metadata to the provided BasicIo.
@throw Error on input-output errors or when the image data is not valid.
@param oIo BasicIo instance to write to (a temporary location).
*/
void doWriteMetadata(BasicIo& outIo);
//@}
std::string profileName_;
}; // class PngImage
/*!
@brief Class to access PNG images. Exif and IPTC metadata are supported
directly.
*/
class EXIV2API PngImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing PNG image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
PngImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Print out the structure of image file.
@throw Error if reading of the file fails or the image data is
not valid (does not look like data of the specific image type).
@warning This function is not thread safe and intended for exiv2 -pS for debugging.
*/
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
//! @name NOT implemented
//@{
//! Copy constructor
PngImage(const PngImage& rhs) = delete;
//! Assignment operator
PngImage& operator=(const PngImage& rhs) = delete;
private:
/*!
@brief Provides the main implementation of writeMetadata() by
writing all buffered metadata to the provided BasicIo.
@throw Error on input-output errors or when the image data is not valid.
@param oIo BasicIo instance to write to (a temporary location).
*/
void doWriteMetadata(BasicIo& outIo);
//@}
std::string profileName_;
}; // class PngImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new PngImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newPngInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new PngImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newPngInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a PNG image.
EXIV2API bool isPngType(BasicIo& iIo, bool advance);
//! Check if the file iIo is a PNG image.
EXIV2API bool isPngType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef PNGIMAGE_HPP_
#endif // #ifndef PNGIMAGE_HPP_

@ -11,136 +11,134 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
//! Type of preview image.
using PreviewId = int;
/*!
@brief Preview image properties.
*/
struct EXIV2API PreviewProperties
{
std::string mimeType_; //!< Preview image mime type.
std::string extension_; //!< Preview image extension.
size_t size_; //!< Preview image size in bytes.
size_t width_; //!< Preview image width in pixels or 0 for unknown width.
size_t height_; //!< Preview image height in pixels or 0 for unknown height.
PreviewId id_; //!< Identifies type of preview image.
};
//! Container type to hold all preview images metadata.
using PreviewPropertiesList = std::vector<PreviewProperties>;
/*!
@brief Class that holds preview image properties and data buffer.
*/
class EXIV2API PreviewImage {
friend class PreviewManager;
public:
//! @name Constructors
//@{
//! Copy constructor
PreviewImage(const PreviewImage& rhs);
//@}
//! @name Manipulators
//@{
//! Assignment operator
PreviewImage& operator=(const PreviewImage& rhs);
//@}
//! @name Accessors
//@{
/*!
@brief Return a copy of the preview image data. The caller owns
this copy and %DataBuf ensures that it will be deleted.
*/
DataBuf copy() const;
/*!
@brief Return a pointer to the image data for read-only access.
*/
const byte* pData() const;
/*!
@brief Return the size of the preview image in bytes.
*/
uint32_t size() const;
/*!
@brief Write the thumbnail image to a file.
A filename extension is appended to \em path according to the image
type of the preview image, so \em path should not include an extension.
The function will overwrite an existing file of the same name.
@param path File name of the preview image without extension.
@return The number of bytes written.
*/
size_t writeFile(const std::string& path) const;
/*!
@brief Return the MIME type of the preview image, usually either
\c "image/tiff" or \c "image/jpeg".
*/
std::string mimeType() const;
/*!
@brief Return the file extension for the format of the preview image
(".tif" or ".jpg").
*/
std::string extension() const;
/*!
@brief Return the width of the preview image in pixels.
*/
size_t width() const;
/*!
@brief Return the height of the preview image in pixels.
*/
size_t height() const;
/*!
@brief Return the preview image type identifier.
*/
PreviewId id() const;
//@}
private:
//! Private constructor
PreviewImage(PreviewProperties properties, DataBuf&& data);
PreviewProperties properties_; //!< Preview image properties
DataBuf preview_; //!< Preview image data
}; // class PreviewImage
/*!
@brief Class for extracting preview images from image metadata.
*/
class EXIV2API PreviewManager {
public:
//! @name Constructors
//@{
//! Constructor.
explicit PreviewManager(const Image& image);
//@}
//! @name Accessors
//@{
/*!
@brief Return the properties of all preview images in a list
sorted by preview width * height, starting with the smallest
preview image.
*/
PreviewPropertiesList getPreviewProperties() const;
/*!
@brief Return the preview image for the given preview properties.
*/
PreviewImage getPreviewImage(const PreviewProperties& properties) const;
//@}
private:
const Image& image_;
}; // class PreviewManager
// *****************************************************************************
// class definitions
//! Type of preview image.
using PreviewId = int;
/*!
@brief Preview image properties.
*/
struct EXIV2API PreviewProperties {
std::string mimeType_; //!< Preview image mime type.
std::string extension_; //!< Preview image extension.
size_t size_; //!< Preview image size in bytes.
size_t width_; //!< Preview image width in pixels or 0 for unknown width.
size_t height_; //!< Preview image height in pixels or 0 for unknown height.
PreviewId id_; //!< Identifies type of preview image.
};
//! Container type to hold all preview images metadata.
using PreviewPropertiesList = std::vector<PreviewProperties>;
/*!
@brief Class that holds preview image properties and data buffer.
*/
class EXIV2API PreviewImage {
friend class PreviewManager;
public:
//! @name Constructors
//@{
//! Copy constructor
PreviewImage(const PreviewImage& rhs);
//@}
//! @name Manipulators
//@{
//! Assignment operator
PreviewImage& operator=(const PreviewImage& rhs);
//@}
//! @name Accessors
//@{
/*!
@brief Return a copy of the preview image data. The caller owns
this copy and %DataBuf ensures that it will be deleted.
*/
DataBuf copy() const;
/*!
@brief Return a pointer to the image data for read-only access.
*/
const byte* pData() const;
/*!
@brief Return the size of the preview image in bytes.
*/
uint32_t size() const;
/*!
@brief Write the thumbnail image to a file.
A filename extension is appended to \em path according to the image
type of the preview image, so \em path should not include an extension.
The function will overwrite an existing file of the same name.
@param path File name of the preview image without extension.
@return The number of bytes written.
*/
size_t writeFile(const std::string& path) const;
/*!
@brief Return the MIME type of the preview image, usually either
\c "image/tiff" or \c "image/jpeg".
*/
std::string mimeType() const;
/*!
@brief Return the file extension for the format of the preview image
(".tif" or ".jpg").
*/
std::string extension() const;
/*!
@brief Return the width of the preview image in pixels.
*/
size_t width() const;
/*!
@brief Return the height of the preview image in pixels.
*/
size_t height() const;
/*!
@brief Return the preview image type identifier.
*/
PreviewId id() const;
//@}
private:
//! Private constructor
PreviewImage(PreviewProperties properties, DataBuf&& data);
PreviewProperties properties_; //!< Preview image properties
DataBuf preview_; //!< Preview image data
}; // class PreviewImage
/*!
@brief Class for extracting preview images from image metadata.
*/
class EXIV2API PreviewManager {
public:
//! @name Constructors
//@{
//! Constructor.
explicit PreviewManager(const Image& image);
//@}
//! @name Accessors
//@{
/*!
@brief Return the properties of all preview images in a list
sorted by preview width * height, starting with the smallest
preview image.
*/
PreviewPropertiesList getPreviewProperties() const;
/*!
@brief Return the preview image for the given preview properties.
*/
PreviewImage getPreviewImage(const PreviewProperties& properties) const;
//@}
private:
const Image& image_;
}; // class PreviewManager
} // namespace Exiv2
#endif // #ifndef PREVIEW_HPP_

@ -7,292 +7,288 @@
#include "exiv2lib_export.h"
// included header files
#include "datasets.hpp"
#include <mutex>
#include "datasets.hpp"
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class XmpKey;
class XmpKey;
// *****************************************************************************
// class definitions
//! Category of an XMP property
enum XmpCategory { xmpInternal, xmpExternal };
//! Information about one XMP property.
struct EXIV2API XmpPropertyInfo {
//! Comparison operator for name
bool operator==(const std::string& name) const;
const char* name_; //!< Property name
const char* title_; //!< Property title or label
const char* xmpValueType_; //!< XMP value type (for info only)
TypeId typeId_; //!< Exiv2 default type for the property
XmpCategory xmpCategory_; //!< Category (internal or external)
const char* desc_; //!< Property description
};
//! Structure mapping XMP namespaces and (preferred) prefixes.
struct EXIV2API XmpNsInfo {
//! For comparison with prefix
struct Prefix {
//! Constructor.
explicit Prefix(std::string prefix);
//! The prefix string.
std::string prefix_;
};
//! For comparison with namespace
struct Ns {
//! Constructor.
explicit Ns(std::string ns);
//! The namespace string
std::string ns_;
};
//! Comparison operator for namespace
bool operator==(const Ns& ns) const;
//! Comparison operator for prefix
bool operator==(const Prefix& prefix) const;
const char* ns_; //!< Namespace
const char* prefix_; //!< (Preferred) prefix
const XmpPropertyInfo* xmpPropertyInfo_; //!< List of known properties
const char* desc_; //!< Brief description of the namespace
};
//! XMP property reference, implemented as a static class.
class EXIV2API XmpProperties {
//! Prevent construction: not implemented.
XmpProperties();
//! Prevent copy-construction: not implemented.
XmpProperties(const XmpProperties& rhs);
//! Prevent assignment: not implemented.
XmpProperties& operator=(const XmpProperties& rhs);
private:
static const XmpNsInfo* nsInfoUnsafe(const std::string& prefix);
static void unregisterNsUnsafe(const std::string& ns);
static const XmpNsInfo* lookupNsRegistryUnsafe(const XmpNsInfo::Prefix& prefix);
public:
/*!
@brief Return the title (label) of the property.
@param key The property key
@return The title (label) of the property, 0 if the
key is of an unknown property.
*/
static const char* propertyTitle(const XmpKey& key);
/*!
@brief Return the description of the property.
@param key The property key
@return The description of the property, 0 if the
key is of an unknown property.
*/
static const char* propertyDesc(const XmpKey& key);
/*!
@brief Return the type for property \em key. The default
for unknown keys is xmpText.
@param key The property key
@return The type of the property
*/
static TypeId propertyType(const XmpKey& key);
/*!
@brief Return information for the property for key.
If the key is a path to a nested property (one which contains a slash,
like \c Xmp.MP.RegionInfo/MPRI:Regions), determines the innermost element
(\c Xmp.MPRI.Regions) and returns its property information.
@param key The property key
@return A pointer to the property information, 0 if the
key is of an unknown property.
*/
static const XmpPropertyInfo* propertyInfo(const XmpKey& key);
/*!
@brief Return the namespace name for the schema associated
with \em prefix.
@param prefix Prefix
@return The namespace name
@throw Error if no namespace is registered with \em prefix.
*/
static std::string ns(const std::string& prefix);
/*!
@brief Return the namespace description for the schema associated
with \em prefix.
@param prefix Prefix
@return The namespace description
@throw Error if no namespace is registered with \em prefix.
*/
static const char* nsDesc(const std::string& prefix);
/*!
@brief Return read-only list of built-in properties for \em prefix.
@param prefix Prefix
@return Pointer to the built-in properties for prefix, may be 0 if
none is configured in the namespace info.
@throw Error if no namespace is registered with \em prefix.
*/
static const XmpPropertyInfo* propertyList(const std::string& prefix);
/*!
@brief Return information about a schema namespace for \em prefix.
Always returns a valid pointer.
@param prefix The prefix
@return A pointer to the related information
@throw Error if no namespace is registered with \em prefix.
*/
static const XmpNsInfo* nsInfo(const std::string& prefix);
/*!
@brief Return the (preferred) prefix for schema namespace \em ns.
@param ns Schema namespace
@return The prefix or an empty string if namespace \em ns is not
registered.
*/
static std::string prefix(const std::string& ns);
//! Print a list of properties of a schema namespace to output stream \em os.
static void printProperties(std::ostream& os, const std::string& prefix);
//! Interpret and print the value of an XMP property
static std::ostream& printProperty(std::ostream& os,
const std::string& key,
const Value& value);
/*!
@brief Register namespace \em ns with preferred prefix \em prefix.
If the prefix is a known or previously registered prefix, the
corresponding namespace URI is overwritten.
@note This invalidates XMP keys generated with the previous prefix.
*/
static void registerNs(const std::string& ns, const std::string& prefix);
/*!
@brief Unregister a custom namespace \em ns.
The function only has an effect if there is a namespace \em ns
registered earlier, it does not unregister built-in namespaces.
@note This invalidates XMP keys generated in this namespace.
*/
static void unregisterNs(const std::string& ns);
/*!
@brief Lock to be used while modifying properties.
@todo For a proper read-write lock, this shall be improved by a
\em std::shared_timed_mutex (once C++14 is allowed) or
\em std::shared_mutex (once C++17 is allowed). The
read-access locks shall be updated to \em std::shared_lock then.
*/
static std::mutex mutex_;
/*!
@brief Unregister all custom namespaces.
The function only unregisters namespaces registered earlier, it does not
unregister built-in namespaces.
@note This invalidates XMP keys generated in any custom namespace.
*/
static void unregisterNs();
//! Type for the namespace registry
using NsRegistry = std::map<std::string, XmpNsInfo>;
/*!
@brief Get the registered namespace for a specific \em prefix from the registry.
*/
static const XmpNsInfo* lookupNsRegistry(const XmpNsInfo::Prefix& prefix);
// DATA
static NsRegistry nsRegistry_; //!< Namespace registry
/*!
@brief Get all registered namespaces (for both Exiv2 and XMPsdk)
*/
static void registeredNamespaces(Exiv2::Dictionary& nsDict);
}; // class XmpProperties
/*!
@brief Concrete keys for XMP metadata.
*/
class EXIV2API XmpKey : public Key
{
public:
//! Shortcut for an %XmpKey auto pointer.
using UniquePtr = std::unique_ptr<XmpKey>;
//! @name Creators
//@{
/*!
@brief Constructor to create an XMP key from a key string.
@param key The key string.
@throw Error if the first part of the key is not '<b>Xmp</b>' or
the second part of the key cannot be parsed and converted
to a known (i.e., built-in or registered) schema prefix.
*/
explicit XmpKey(const std::string& key);
/*!
@brief Constructor to create an XMP key from a schema prefix
and a property name.
@param prefix Schema prefix name
@param property Property name
@throw Error if the schema prefix is not known.
*/
XmpKey(const std::string& prefix, const std::string& property);
//! Copy constructor.
XmpKey(const XmpKey& rhs);
//! Virtual destructor.
~XmpKey() override;
//@}
//! @name Manipulators
//@{
//! Assignment operator.
XmpKey& operator=(const XmpKey& rhs);
//@}
//! @name Accessors
//@{
std::string key() const override;
const char* familyName() const override;
/*!
@brief Return the name of the group (the second part of the key).
For XMP keys, the group name is the schema prefix name.
*/
std::string groupName() const override;
std::string tagName() const override;
std::string tagLabel() const override;
//! Properties don't have a tag number. Return 0.
uint16_t tag() const override;
UniquePtr clone() const;
// Todo: Should this be removed? What about tagLabel then?
//! Return the schema namespace for the prefix of the key
std::string ns() const;
//@}
private:
//! Internal virtual copy constructor.
XmpKey* clone_() const override;
// Pimpl idiom
struct Impl;
std::unique_ptr<Impl> p_;
}; // class XmpKey
// *****************************************************************************
// free functions
//! Output operator for property info
EXIV2API std::ostream& operator<<(std::ostream& os, const XmpPropertyInfo& propertyInfo);
} // namespace Exiv2
#endif // #ifndef PROPERTIES_HPP_
//! Category of an XMP property
enum XmpCategory { xmpInternal, xmpExternal };
//! Information about one XMP property.
struct EXIV2API XmpPropertyInfo {
//! Comparison operator for name
bool operator==(const std::string& name) const;
const char* name_; //!< Property name
const char* title_; //!< Property title or label
const char* xmpValueType_; //!< XMP value type (for info only)
TypeId typeId_; //!< Exiv2 default type for the property
XmpCategory xmpCategory_; //!< Category (internal or external)
const char* desc_; //!< Property description
};
//! Structure mapping XMP namespaces and (preferred) prefixes.
struct EXIV2API XmpNsInfo {
//! For comparison with prefix
struct Prefix {
//! Constructor.
explicit Prefix(std::string prefix);
//! The prefix string.
std::string prefix_;
};
//! For comparison with namespace
struct Ns {
//! Constructor.
explicit Ns(std::string ns);
//! The namespace string
std::string ns_;
};
//! Comparison operator for namespace
bool operator==(const Ns& ns) const;
//! Comparison operator for prefix
bool operator==(const Prefix& prefix) const;
const char* ns_; //!< Namespace
const char* prefix_; //!< (Preferred) prefix
const XmpPropertyInfo* xmpPropertyInfo_; //!< List of known properties
const char* desc_; //!< Brief description of the namespace
};
//! XMP property reference, implemented as a static class.
class EXIV2API XmpProperties {
//! Prevent construction: not implemented.
XmpProperties();
//! Prevent copy-construction: not implemented.
XmpProperties(const XmpProperties& rhs);
//! Prevent assignment: not implemented.
XmpProperties& operator=(const XmpProperties& rhs);
private:
static const XmpNsInfo* nsInfoUnsafe(const std::string& prefix);
static void unregisterNsUnsafe(const std::string& ns);
static const XmpNsInfo* lookupNsRegistryUnsafe(const XmpNsInfo::Prefix& prefix);
public:
/*!
@brief Return the title (label) of the property.
@param key The property key
@return The title (label) of the property, 0 if the
key is of an unknown property.
*/
static const char* propertyTitle(const XmpKey& key);
/*!
@brief Return the description of the property.
@param key The property key
@return The description of the property, 0 if the
key is of an unknown property.
*/
static const char* propertyDesc(const XmpKey& key);
/*!
@brief Return the type for property \em key. The default
for unknown keys is xmpText.
@param key The property key
@return The type of the property
*/
static TypeId propertyType(const XmpKey& key);
/*!
@brief Return information for the property for key.
If the key is a path to a nested property (one which contains a slash,
like \c Xmp.MP.RegionInfo/MPRI:Regions), determines the innermost element
(\c Xmp.MPRI.Regions) and returns its property information.
@param key The property key
@return A pointer to the property information, 0 if the
key is of an unknown property.
*/
static const XmpPropertyInfo* propertyInfo(const XmpKey& key);
/*!
@brief Return the namespace name for the schema associated
with \em prefix.
@param prefix Prefix
@return The namespace name
@throw Error if no namespace is registered with \em prefix.
*/
static std::string ns(const std::string& prefix);
/*!
@brief Return the namespace description for the schema associated
with \em prefix.
@param prefix Prefix
@return The namespace description
@throw Error if no namespace is registered with \em prefix.
*/
static const char* nsDesc(const std::string& prefix);
/*!
@brief Return read-only list of built-in properties for \em prefix.
@param prefix Prefix
@return Pointer to the built-in properties for prefix, may be 0 if
none is configured in the namespace info.
@throw Error if no namespace is registered with \em prefix.
*/
static const XmpPropertyInfo* propertyList(const std::string& prefix);
/*!
@brief Return information about a schema namespace for \em prefix.
Always returns a valid pointer.
@param prefix The prefix
@return A pointer to the related information
@throw Error if no namespace is registered with \em prefix.
*/
static const XmpNsInfo* nsInfo(const std::string& prefix);
/*!
@brief Return the (preferred) prefix for schema namespace \em ns.
@param ns Schema namespace
@return The prefix or an empty string if namespace \em ns is not
registered.
*/
static std::string prefix(const std::string& ns);
//! Print a list of properties of a schema namespace to output stream \em os.
static void printProperties(std::ostream& os, const std::string& prefix);
//! Interpret and print the value of an XMP property
static std::ostream& printProperty(std::ostream& os, const std::string& key, const Value& value);
/*!
@brief Register namespace \em ns with preferred prefix \em prefix.
If the prefix is a known or previously registered prefix, the
corresponding namespace URI is overwritten.
@note This invalidates XMP keys generated with the previous prefix.
*/
static void registerNs(const std::string& ns, const std::string& prefix);
/*!
@brief Unregister a custom namespace \em ns.
The function only has an effect if there is a namespace \em ns
registered earlier, it does not unregister built-in namespaces.
@note This invalidates XMP keys generated in this namespace.
*/
static void unregisterNs(const std::string& ns);
/*!
@brief Lock to be used while modifying properties.
@todo For a proper read-write lock, this shall be improved by a
\em std::shared_timed_mutex (once C++14 is allowed) or
\em std::shared_mutex (once C++17 is allowed). The
read-access locks shall be updated to \em std::shared_lock then.
*/
static std::mutex mutex_;
/*!
@brief Unregister all custom namespaces.
The function only unregisters namespaces registered earlier, it does not
unregister built-in namespaces.
@note This invalidates XMP keys generated in any custom namespace.
*/
static void unregisterNs();
//! Type for the namespace registry
using NsRegistry = std::map<std::string, XmpNsInfo>;
/*!
@brief Get the registered namespace for a specific \em prefix from the registry.
*/
static const XmpNsInfo* lookupNsRegistry(const XmpNsInfo::Prefix& prefix);
// DATA
static NsRegistry nsRegistry_; //!< Namespace registry
/*!
@brief Get all registered namespaces (for both Exiv2 and XMPsdk)
*/
static void registeredNamespaces(Exiv2::Dictionary& nsDict);
}; // class XmpProperties
/*!
@brief Concrete keys for XMP metadata.
*/
class EXIV2API XmpKey : public Key {
public:
//! Shortcut for an %XmpKey auto pointer.
using UniquePtr = std::unique_ptr<XmpKey>;
//! @name Creators
//@{
/*!
@brief Constructor to create an XMP key from a key string.
@param key The key string.
@throw Error if the first part of the key is not '<b>Xmp</b>' or
the second part of the key cannot be parsed and converted
to a known (i.e., built-in or registered) schema prefix.
*/
explicit XmpKey(const std::string& key);
/*!
@brief Constructor to create an XMP key from a schema prefix
and a property name.
@param prefix Schema prefix name
@param property Property name
@throw Error if the schema prefix is not known.
*/
XmpKey(const std::string& prefix, const std::string& property);
//! Copy constructor.
XmpKey(const XmpKey& rhs);
//! Virtual destructor.
~XmpKey() override;
//@}
//! @name Manipulators
//@{
//! Assignment operator.
XmpKey& operator=(const XmpKey& rhs);
//@}
//! @name Accessors
//@{
std::string key() const override;
const char* familyName() const override;
/*!
@brief Return the name of the group (the second part of the key).
For XMP keys, the group name is the schema prefix name.
*/
std::string groupName() const override;
std::string tagName() const override;
std::string tagLabel() const override;
//! Properties don't have a tag number. Return 0.
uint16_t tag() const override;
UniquePtr clone() const;
// Todo: Should this be removed? What about tagLabel then?
//! Return the schema namespace for the prefix of the key
std::string ns() const;
//@}
private:
//! Internal virtual copy constructor.
XmpKey* clone_() const override;
// Pimpl idiom
struct Impl;
std::unique_ptr<Impl> p_;
}; // class XmpKey
// *****************************************************************************
// free functions
//! Output operator for property info
EXIV2API std::ostream& operator<<(std::ostream& os, const XmpPropertyInfo& propertyInfo);
} // namespace Exiv2
#endif // #ifndef PROPERTIES_HPP_

@ -12,104 +12,103 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access raw Photoshop images.
*/
class EXIV2API PsdImage : public Image {
public:
//! @name NOT Implemented
//@{
//! Copy constructor
PsdImage(const PsdImage& rhs) = delete;
//! Assignment operator
PsdImage& operator=(const PsdImage& rhs) = delete;
//@}
//! @name Creators
//@{
/*!
@brief Constructor to open a Photoshop image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
explicit PsdImage(BasicIo::UniquePtr io);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Not supported. Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
/*!
@brief Return the MIME type of the image.
The MIME type returned for Photoshop images is "image/x-photoshop".
@note This should really be "image/vnd.adobe.photoshop"
(officially registered with IANA in December 2005 -- see
http://www.iana.org/assignments/media-types/image/vnd.adobe.photoshop)
but Apple, as of Tiger (10.4.8), maps this official MIME type to a
dynamic UTI, rather than "com.adobe.photoshop-image" as it should.
*/
std::string mimeType() const override;
//@}
private:
//! @name Manipulators
//@{
void readResourceBlock(uint16_t resourceId, uint32_t resourceSize);
/*!
@brief Provides the main implementation of writeMetadata() by
writing all buffered metadata to the provided BasicIo.
@param oIo BasicIo instance to write to (a temporary location).
@return 4 if opening or writing to the associated BasicIo fails
*/
void doWriteMetadata(BasicIo& outIo);
uint32_t writeExifData(const ExifData& exifData, BasicIo& out);
//@}
//! @name Accessors
//@{
static uint32_t writeIptcData(const IptcData& iptcData, BasicIo& out);
uint32_t writeXmpData(const XmpData& xmpData, BasicIo& out) const;
//@}
}; // class PsdImage
/*!
@brief Class to access raw Photoshop images.
*/
class EXIV2API PsdImage : public Image {
public:
//! @name NOT Implemented
//@{
//! Copy constructor
PsdImage(const PsdImage& rhs) = delete;
//! Assignment operator
PsdImage& operator=(const PsdImage& rhs) = delete;
//@}
//! @name Creators
//@{
/*!
@brief Constructor to open a Photoshop image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
explicit PsdImage(BasicIo::UniquePtr io);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Not supported. Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
/*!
@brief Return the MIME type of the image.
The MIME type returned for Photoshop images is "image/x-photoshop".
@note This should really be "image/vnd.adobe.photoshop"
(officially registered with IANA in December 2005 -- see
http://www.iana.org/assignments/media-types/image/vnd.adobe.photoshop)
but Apple, as of Tiger (10.4.8), maps this official MIME type to a
dynamic UTI, rather than "com.adobe.photoshop-image" as it should.
*/
std::string mimeType() const override;
//@}
private:
//! @name Manipulators
//@{
void readResourceBlock(uint16_t resourceId, uint32_t resourceSize);
/*!
@brief Provides the main implementation of writeMetadata() by
writing all buffered metadata to the provided BasicIo.
@param oIo BasicIo instance to write to (a temporary location).
@return 4 if opening or writing to the associated BasicIo fails
*/
void doWriteMetadata(BasicIo& outIo);
uint32_t writeExifData(const ExifData& exifData, BasicIo& out);
//@}
//! @name Accessors
//@{
static uint32_t writeIptcData(const IptcData& iptcData, BasicIo& out);
uint32_t writeXmpData(const XmpData& xmpData, BasicIo& out) const;
//@}
}; // class PsdImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new PsdImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newPsdInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new PsdImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newPsdInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a Photoshop image.
EXIV2API bool isPsdType(BasicIo& iIo, bool advance);
//! Check if the file iIo is a Photoshop image.
EXIV2API bool isPsdType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef PSDIMAGE_HPP_
#endif // #ifndef PSDIMAGE_HPP_

@ -12,94 +12,93 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access raw Fujifilm RAF images. Exif metadata is
supported directly, IPTC is read from the Exif data, if present.
*/
class EXIV2API RafImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing RAF image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
RafImage(BasicIo::UniquePtr io, bool create);
//@}
/*!
@brief Class to access raw Fujifilm RAF images. Exif metadata is
supported directly, IPTC is read from the Exif data, if present.
*/
class EXIV2API RafImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing RAF image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
RafImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
void readMetadata() override;
/*!
@brief Todo: Write metadata back to the image. This method is not
yet implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported).
*/
void writeMetadata() override;
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setExifData(const ExifData& exifData) override;
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setIptcData(const IptcData& iptcData) override;
/*!
@brief Not supported. RAF format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Manipulators
//@{
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
void readMetadata() override;
/*!
@brief Todo: Write metadata back to the image. This method is not
yet implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported).
*/
void writeMetadata() override;
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setExifData(const ExifData& exifData) override;
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setIptcData(const IptcData& iptcData) override;
/*!
@brief Not supported. RAF format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
//! @name NOT implemented
//@{
//! Copy constructor
RafImage(const RafImage& rhs) = delete;
//! Assignment operator
RafImage& operator=(const RafImage& rhs) = delete;
//@}
//! @name NOT implemented
//@{
//! Copy constructor
RafImage(const RafImage& rhs) = delete;
//! Assignment operator
RafImage& operator=(const RafImage& rhs) = delete;
//@}
}; // class RafImage
}; // class RafImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new RafImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newRafInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new RafImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newRafInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a RAF image.
EXIV2API bool isRafType(BasicIo& iIo, bool advance);
//! Check if the file iIo is a RAF image.
EXIV2API bool isRafType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef RAFIMAGE_HPP_
#endif // #ifndef RAFIMAGE_HPP_

@ -12,113 +12,107 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access raw Panasonic RW2 images. Exif metadata is
supported directly, IPTC and XMP are read from the Exif data, if
present.
*/
class EXIV2API Rw2Image : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor to open an existing RW2 image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success or
failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
explicit Rw2Image(BasicIo::UniquePtr io);
//@}
//! @name Manipulators
//@{
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
void readMetadata() override;
/*!
@brief Todo: Write metadata back to the image. This method is not
yet implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported).
*/
void writeMetadata() override;
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setExifData(const ExifData& exifData) override;
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setIptcData(const IptcData& iptcData) override;
/*!
@brief Not supported. RW2 format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
//! @name NOT implemented
//@{
//! Copy constructor
Rw2Image(const Rw2Image& rhs) = delete;
//! Assignment operator
Rw2Image& operator=(const Rw2Image& rhs) = delete;
//@}
}; // class Rw2Image
/*!
@brief Stateless parser class for data in RW2 format. Images use this
class to decode and encode RW2 data. Only decoding is currently
implemented. See class TiffParser for details.
*/
class EXIV2API Rw2Parser {
public:
/*!
@brief Decode metadata from a buffer \em pData of length \em size
with data in RW2 format to the provided metadata containers.
See TiffParser::decode().
*/
static ByteOrder decode(ExifData& exifData,
IptcData& iptcData,
XmpData& xmpData,
const byte* pData,
size_t size
);
}; // class Rw2Parser
/*!
@brief Class to access raw Panasonic RW2 images. Exif metadata is
supported directly, IPTC and XMP are read from the Exif data, if
present.
*/
class EXIV2API Rw2Image : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor to open an existing RW2 image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success or
failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
explicit Rw2Image(BasicIo::UniquePtr io);
//@}
//! @name Manipulators
//@{
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
void readMetadata() override;
/*!
@brief Todo: Write metadata back to the image. This method is not
yet implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported).
*/
void writeMetadata() override;
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setExifData(const ExifData& exifData) override;
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setIptcData(const IptcData& iptcData) override;
/*!
@brief Not supported. RW2 format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
//! @name NOT implemented
//@{
//! Copy constructor
Rw2Image(const Rw2Image& rhs) = delete;
//! Assignment operator
Rw2Image& operator=(const Rw2Image& rhs) = delete;
//@}
}; // class Rw2Image
/*!
@brief Stateless parser class for data in RW2 format. Images use this
class to decode and encode RW2 data. Only decoding is currently
implemented. See class TiffParser for details.
*/
class EXIV2API Rw2Parser {
public:
/*!
@brief Decode metadata from a buffer \em pData of length \em size
with data in RW2 format to the provided metadata containers.
See TiffParser::decode().
*/
static ByteOrder decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, size_t size);
}; // class Rw2Parser
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new Rw2Image instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newRw2Instance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new Rw2Image instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newRw2Instance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a RW2 image.
EXIV2API bool isRw2Type(BasicIo& iIo, bool advance);
//! Check if the file iIo is a RW2 image.
EXIV2API bool isRw2Type(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef RW2IMAGE_HPP_
#endif // #ifndef RW2IMAGE_HPP_

File diff suppressed because it is too large Load Diff

@ -12,183 +12,182 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class ExifData;
class ExifKey;
class Value;
struct TagInfo;
class ExifData;
class ExifKey;
class Value;
struct TagInfo;
// *****************************************************************************
// type definitions
//! Type for a function pointer for functions interpreting the tag value
using PrintFct = std::ostream& (*)(std::ostream&, const Value&, const ExifData* pExifData);
//! A function returning a tag list.
using TagListFct = const TagInfo* (*)();
// *****************************************************************************
// class definitions
//! The details of an Exif group. Groups include IFDs and binary arrays.
struct EXIV2API GroupInfo {
struct GroupName;
bool operator==(int ifdId) const; //!< Comparison operator for IFD id
bool operator==(const GroupName& groupName) const; //!< Comparison operator for group name
int ifdId_; //!< IFD id
const char* ifdName_; //!< IFD name
const char* groupName_; //!< Group name, unique for each group.
TagListFct tagList_; //!< Tag list
};
//! Search key to find a GroupInfo by its group name.
struct EXIV2API GroupInfo::GroupName {
explicit GroupName(std::string groupName);
std::string g_; //!< Group name
};
//! Tag information
struct EXIV2API TagInfo {
uint16_t tag_; //!< Tag
const char* name_; //!< One word tag label
const char* title_; //!< Tag title
const char* desc_; //!< Short tag description
int ifdId_; //!< Link to the (preferred) IFD
int sectionId_; //!< Section id
TypeId typeId_; //!< Type id
int16_t count_; //!< The number of values (not bytes!), 0=any, -1=count not known.
PrintFct printFct_; //!< Pointer to tag print function
}; // struct TagInfo
//! Access to Exif group and tag lists and misc. tag reference methods, implemented as a static class.
class EXIV2API ExifTags {
public:
//! Prevent construction: not implemented.
ExifTags() = delete;
//! Prevent copy-construction: not implemented.
ExifTags(const ExifTags& rhs) = delete;
//! Prevent assignment: not implemented.
ExifTags& operator=(const ExifTags& rhs) = delete;
//! Return read-only list of built-in groups
static const GroupInfo* groupList();
//! Return read-only list of built-in \em groupName tags.
static const TagInfo* tagList(const std::string& groupName);
//! Print a list of all standard Exif tags to output stream
static void taglist(std::ostream& os);
//! Print the list of tags for \em groupName
static void taglist(std::ostream& os, const std::string& groupName);
//! Return the name of the section for an Exif \em key.
static const char* sectionName(const ExifKey& key);
//! Return the default number of components (not bytes!) \em key has. (0=any, -1=count not known)
static uint16_t defaultCount(const ExifKey& key);
//! Return the name of the IFD for the group.
static const char* ifdName(const std::string& groupName);
/*!
@brief Return true if \em groupName is a makernote group.
*/
static bool isMakerGroup(const std::string& groupName);
/*!
@brief Return true if \em groupName is a TIFF or Exif IFD, else false.
This is used to differentiate between standard Exif IFDs
and IFDs associated with the makernote.
*/
static bool isExifGroup(const std::string& groupName);
}; // class ExifTags
/*!
@brief Concrete keys for Exif metadata and access to Exif tag reference data.
*/
class EXIV2API ExifKey : public Key {
public:
//! Shortcut for an %ExifKey auto pointer.
using UniquePtr = std::unique_ptr<ExifKey>;
//! @name Creators
//@{
/*!
@brief Constructor to create an Exif key from a key string.
@param key The key string.
@throw Error if the first part of the key is not '<b>Exif</b>' or
the remaining parts of the key cannot be parsed and
converted to a group name and tag name.
*/
explicit ExifKey(const std::string& key);
/*!
@brief Constructor to create an Exif key from the tag number and
group name.
@param tag The tag value
@param groupName The name of the group, i.e., the second part of
the Exif key.
@throw Error if the key cannot be constructed from the tag number
and group name.
*/
ExifKey(uint16_t tag, const std::string& groupName);
/*!
@brief Constructor to create an Exif key from a TagInfo instance.
@param ti The TagInfo instance
@throw Error if the key cannot be constructed from the tag number
and group name.
*/
explicit ExifKey(const TagInfo& ti);
//! Copy constructor
ExifKey(const ExifKey& rhs);
//! Destructor
~ExifKey() override;
//@}
//! @name Manipulators
//@{
/*!
@brief Assignment operator.
*/
ExifKey& operator=(const ExifKey& rhs);
//! Set the index.
void setIdx(int idx);
//@}
//! @name Accessors
//@{
std::string key() const override;
const char* familyName() const override;
std::string groupName() const override;
//! Return the IFD id as an integer. (Do not use, this is meant for library internal use.)
int ifdId() const;
std::string tagName() const override;
uint16_t tag() const override;
std::string tagLabel() const override;
//! Return the tag description.
std::string tagDesc() const; // Todo: should be in the base class
//! Return the default type id for this tag.
TypeId defaultTypeId() const; // Todo: should be in the base class
UniquePtr clone() const;
//! Return the index (unique id of this key within the original Exif data, 0 if not set)
int idx() const;
//@}
private:
//! Internal virtual copy constructor.
ExifKey* clone_() const override;
// Pimpl idiom
struct Impl;
std::unique_ptr<Impl> p_;
}; // class ExifKey
//! Type for a function pointer for functions interpreting the tag value
using PrintFct = std::ostream& (*)(std::ostream&, const Value&, const ExifData* pExifData);
//! A function returning a tag list.
using TagListFct = const TagInfo* (*)();
// *****************************************************************************
// class definitions
//! The details of an Exif group. Groups include IFDs and binary arrays.
struct EXIV2API GroupInfo {
struct GroupName;
bool operator==(int ifdId) const; //!< Comparison operator for IFD id
bool operator==(const GroupName& groupName) const; //!< Comparison operator for group name
int ifdId_; //!< IFD id
const char* ifdName_; //!< IFD name
const char* groupName_; //!< Group name, unique for each group.
TagListFct tagList_; //!< Tag list
};
//! Search key to find a GroupInfo by its group name.
struct EXIV2API GroupInfo::GroupName {
explicit GroupName(std::string groupName);
std::string g_; //!< Group name
};
//! Tag information
struct EXIV2API TagInfo {
uint16_t tag_; //!< Tag
const char* name_; //!< One word tag label
const char* title_; //!< Tag title
const char* desc_; //!< Short tag description
int ifdId_; //!< Link to the (preferred) IFD
int sectionId_; //!< Section id
TypeId typeId_; //!< Type id
int16_t count_; //!< The number of values (not bytes!), 0=any, -1=count not known.
PrintFct printFct_; //!< Pointer to tag print function
}; // struct TagInfo
//! Access to Exif group and tag lists and misc. tag reference methods, implemented as a static class.
class EXIV2API ExifTags {
public:
//! Prevent construction: not implemented.
ExifTags() = delete;
//! Prevent copy-construction: not implemented.
ExifTags(const ExifTags& rhs) = delete;
//! Prevent assignment: not implemented.
ExifTags& operator=(const ExifTags& rhs) = delete;
//! Return read-only list of built-in groups
static const GroupInfo* groupList();
//! Return read-only list of built-in \em groupName tags.
static const TagInfo* tagList(const std::string& groupName);
//! Print a list of all standard Exif tags to output stream
static void taglist(std::ostream& os);
//! Print the list of tags for \em groupName
static void taglist(std::ostream& os, const std::string& groupName);
//! Return the name of the section for an Exif \em key.
static const char* sectionName(const ExifKey& key);
//! Return the default number of components (not bytes!) \em key has. (0=any, -1=count not known)
static uint16_t defaultCount(const ExifKey& key);
//! Return the name of the IFD for the group.
static const char* ifdName(const std::string& groupName);
/*!
@brief Return true if \em groupName is a makernote group.
*/
static bool isMakerGroup(const std::string& groupName);
/*!
@brief Return true if \em groupName is a TIFF or Exif IFD, else false.
This is used to differentiate between standard Exif IFDs
and IFDs associated with the makernote.
*/
static bool isExifGroup(const std::string& groupName);
}; // class ExifTags
/*!
@brief Concrete keys for Exif metadata and access to Exif tag reference data.
*/
class EXIV2API ExifKey : public Key {
public:
//! Shortcut for an %ExifKey auto pointer.
using UniquePtr = std::unique_ptr<ExifKey>;
//! @name Creators
//@{
/*!
@brief Constructor to create an Exif key from a key string.
@param key The key string.
@throw Error if the first part of the key is not '<b>Exif</b>' or
the remaining parts of the key cannot be parsed and
converted to a group name and tag name.
*/
explicit ExifKey(const std::string& key);
/*!
@brief Constructor to create an Exif key from the tag number and
group name.
@param tag The tag value
@param groupName The name of the group, i.e., the second part of
the Exif key.
@throw Error if the key cannot be constructed from the tag number
and group name.
*/
ExifKey(uint16_t tag, const std::string& groupName);
/*!
@brief Constructor to create an Exif key from a TagInfo instance.
@param ti The TagInfo instance
@throw Error if the key cannot be constructed from the tag number
and group name.
*/
explicit ExifKey(const TagInfo& ti);
//! Copy constructor
ExifKey(const ExifKey& rhs);
//! Destructor
~ExifKey() override;
//@}
//! @name Manipulators
//@{
/*!
@brief Assignment operator.
*/
ExifKey& operator=(const ExifKey& rhs);
//! Set the index.
void setIdx(int idx);
//@}
//! @name Accessors
//@{
std::string key() const override;
const char* familyName() const override;
std::string groupName() const override;
//! Return the IFD id as an integer. (Do not use, this is meant for library internal use.)
int ifdId() const;
std::string tagName() const override;
uint16_t tag() const override;
std::string tagLabel() const override;
//! Return the tag description.
std::string tagDesc() const; // Todo: should be in the base class
//! Return the default type id for this tag.
TypeId defaultTypeId() const; // Todo: should be in the base class
UniquePtr clone() const;
//! Return the index (unique id of this key within the original Exif data, 0 if not set)
int idx() const;
//@}
private:
//! Internal virtual copy constructor.
ExifKey* clone_() const override;
// Pimpl idiom
struct Impl;
std::unique_ptr<Impl> p_;
}; // class ExifKey
// *****************************************************************************
// free functions
//! Output operator for TagInfo
EXIV2API std::ostream& operator<<(std::ostream& os, const TagInfo& ti);
//! Output operator for TagInfo
EXIV2API std::ostream& operator<<(std::ostream& os, const TagInfo& ti);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef TAGS_HPP_
#endif // #ifndef TAGS_HPP_

@ -11,88 +11,87 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access raw TARGA images. This is just a stub - we only
read width and height.
*/
class EXIV2API TgaImage : public Image {
public:
//! @name NOT Implemented
//@{
//! Copy constructor
TgaImage(const TgaImage& rhs) = delete;
//! Assignment operator
TgaImage& operator=(const TgaImage& rhs) = delete;
//@}
/*!
@brief Class to access raw TARGA images. This is just a stub - we only
read width and height.
*/
class EXIV2API TgaImage : public Image {
public:
//! @name NOT Implemented
//@{
//! Copy constructor
TgaImage(const TgaImage& rhs) = delete;
//! Assignment operator
TgaImage& operator=(const TgaImage& rhs) = delete;
//@}
//! @name Creators
//@{
/*!
@brief Constructor to open a Targa image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
explicit TgaImage(BasicIo::UniquePtr io);
//@}
//! @name Creators
//@{
/*!
@brief Constructor to open a Targa image. Since the
constructor can not return a result, callers should check the
good() method after object construction to determine success
or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
explicit TgaImage(BasicIo::UniquePtr io);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
/*!
@brief Todo: Write metadata back to the image. This method is not
yet(?) implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported).
*/
void writeMetadata() override;
/*!
@brief Todo: Not supported yet(?). Calling this function will throw
an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setExifData(const ExifData& exifData) override;
/*!
@brief Todo: Not supported yet(?). Calling this function will throw
an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setIptcData(const IptcData& iptcData) override;
/*!
@brief Not supported. Calling this function will throw an instance
of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Manipulators
//@{
void readMetadata() override;
/*!
@brief Todo: Write metadata back to the image. This method is not
yet(?) implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported).
*/
void writeMetadata() override;
/*!
@brief Todo: Not supported yet(?). Calling this function will throw
an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setExifData(const ExifData& exifData) override;
/*!
@brief Todo: Not supported yet(?). Calling this function will throw
an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setIptcData(const IptcData& iptcData) override;
/*!
@brief Not supported. Calling this function will throw an instance
of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
}; // class TgaImage
}; // class TgaImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new TgaImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newTgaInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new TgaImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newTgaInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a Targa v2 image.
EXIV2API bool isTgaType(BasicIo& iIo, bool advance);
//! Check if the file iIo is a Targa v2 image.
EXIV2API bool isTgaType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef TGAIMAGE_HPP_
#endif // #ifndef TGAIMAGE_HPP_

@ -12,172 +12,159 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access TIFF images. Exif metadata is
supported directly, IPTC is read from the Exif data, if present.
*/
class EXIV2API TiffImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing TIFF image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
TiffImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Print out the structure of image file.
@throw Error if reading of the file fails or the image data is
not valid (does not look like data of the specific image type).
@warning This function is not thread safe and intended for exiv2 -p{S|R} as a file debugging aid
*/
void printStructure(std::ostream& out, PrintStructureOption option, int depth = 0) override;
/*!
@brief Not supported. TIFF format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
//! @name NOT Implemented
//@{
//! Copy constructor
TiffImage(const TiffImage& rhs) = delete;
//! Assignment operator
TiffImage& operator=(const TiffImage& rhs) = delete;
//@}
private:
//! @name Accessors
//@{
//! Return the group name of the group with the primary image.
std::string primaryGroup() const;
//@}
// DATA
mutable std::string primaryGroup_; //!< The primary group
mutable std::string mimeType_; //!< The MIME type
mutable uint32_t pixelWidthPrimary_; //!< Width of the primary image in pixels
mutable uint32_t pixelHeightPrimary_; //!< Height of the primary image in pixels
}; // class TiffImage
/*!
@brief Stateless parser class for data in TIFF format. Images use this
class to decode and encode TIFF data. It is a wrapper of the
internal class Internal::TiffParserWorker.
*/
class EXIV2API TiffParser {
public:
/*!
@brief Decode metadata from a buffer \em pData of length \em size
with data in TIFF format to the provided metadata containers.
@param exifData Exif metadata container.
@param iptcData IPTC metadata container.
@param xmpData XMP metadata container.
@param pData Pointer to the data buffer. Must point to data in TIFF
format; no checks are performed.
@param size Length of the data buffer.
@return Byte order in which the data is encoded.
*/
static ByteOrder decode(
ExifData& exifData,
IptcData& iptcData,
XmpData& xmpData,
const byte* pData,
size_t size
);
/*!
@brief Encode metadata from the provided metadata to TIFF format.
The original binary image in the memory block \em pData, \em size is
parsed and updated in-place if possible ("non-intrusive" writing).
If that is not possible (e.g., if new tags were added), the entire
TIFF structure is re-written to the \em io instance ("intrusive" writing).<br>
The return value indicates which write method was used. If it is
\c wmNonIntrusive, the original memory \em pData, \em size contains
the result and nothing is written to \em io. If the return value is
\c wmIntrusive, a new TIFF structure was created and written to
\em io. The memory block \em pData, \em size may be partly updated
in this case and should not be used anymore.
@note If there is no metadata to encode, i.e., all metadata
containers are empty, then the return value is \c wmIntrusive
and nothing is written to \em io, i.e., no TIFF header is written.
@param io IO instance to write the binary image to in case of
"intrusive" writing. Nothing is written to \em io in
the case of "non-intrusive" writing.
@param pData Pointer to the binary image data buffer. Must
point to data in TIFF format; no checks are
performed. Will be modified if "non-intrusive"
writing is possible.
@param size Length of the data buffer.
@param byteOrder Byte order to use.
@param exifData Exif metadata container.
@param iptcData IPTC metadata container.
@param xmpData XMP metadata container.
@return Write method used.
*/
static WriteMethod encode(BasicIo& io,
const byte* pData,
size_t size,
ByteOrder byteOrder,
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData
);
}; // class TiffParser
/*!
@brief Class to access TIFF images. Exif metadata is
supported directly, IPTC is read from the Exif data, if present.
*/
class EXIV2API TiffImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing TIFF image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
TiffImage(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Print out the structure of image file.
@throw Error if reading of the file fails or the image data is
not valid (does not look like data of the specific image type).
@warning This function is not thread safe and intended for exiv2 -p{S|R} as a file debugging aid
*/
void printStructure(std::ostream& out, PrintStructureOption option, int depth = 0) override;
/*!
@brief Not supported. TIFF format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
uint32_t pixelWidth() const override;
uint32_t pixelHeight() const override;
//@}
//! @name NOT Implemented
//@{
//! Copy constructor
TiffImage(const TiffImage& rhs) = delete;
//! Assignment operator
TiffImage& operator=(const TiffImage& rhs) = delete;
//@}
private:
//! @name Accessors
//@{
//! Return the group name of the group with the primary image.
std::string primaryGroup() const;
//@}
// DATA
mutable std::string primaryGroup_; //!< The primary group
mutable std::string mimeType_; //!< The MIME type
mutable uint32_t pixelWidthPrimary_; //!< Width of the primary image in pixels
mutable uint32_t pixelHeightPrimary_; //!< Height of the primary image in pixels
}; // class TiffImage
/*!
@brief Stateless parser class for data in TIFF format. Images use this
class to decode and encode TIFF data. It is a wrapper of the
internal class Internal::TiffParserWorker.
*/
class EXIV2API TiffParser {
public:
/*!
@brief Decode metadata from a buffer \em pData of length \em size
with data in TIFF format to the provided metadata containers.
@param exifData Exif metadata container.
@param iptcData IPTC metadata container.
@param xmpData XMP metadata container.
@param pData Pointer to the data buffer. Must point to data in TIFF
format; no checks are performed.
@param size Length of the data buffer.
@return Byte order in which the data is encoded.
*/
static ByteOrder decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, size_t size);
/*!
@brief Encode metadata from the provided metadata to TIFF format.
The original binary image in the memory block \em pData, \em size is
parsed and updated in-place if possible ("non-intrusive" writing).
If that is not possible (e.g., if new tags were added), the entire
TIFF structure is re-written to the \em io instance ("intrusive" writing).<br>
The return value indicates which write method was used. If it is
\c wmNonIntrusive, the original memory \em pData, \em size contains
the result and nothing is written to \em io. If the return value is
\c wmIntrusive, a new TIFF structure was created and written to
\em io. The memory block \em pData, \em size may be partly updated
in this case and should not be used anymore.
@note If there is no metadata to encode, i.e., all metadata
containers are empty, then the return value is \c wmIntrusive
and nothing is written to \em io, i.e., no TIFF header is written.
@param io IO instance to write the binary image to in case of
"intrusive" writing. Nothing is written to \em io in
the case of "non-intrusive" writing.
@param pData Pointer to the binary image data buffer. Must
point to data in TIFF format; no checks are
performed. Will be modified if "non-intrusive"
writing is possible.
@param size Length of the data buffer.
@param byteOrder Byte order to use.
@param exifData Exif metadata container.
@param iptcData IPTC metadata container.
@param xmpData XMP metadata container.
@return Write method used.
*/
static WriteMethod encode(BasicIo& io, const byte* pData, size_t size, ByteOrder byteOrder, const ExifData& exifData,
const IptcData& iptcData, const XmpData& xmpData);
}; // class TiffParser
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new TiffImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newTiffInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new TiffImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newTiffInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a TIFF image.
EXIV2API bool isTiffType(BasicIo& iIo, bool advance);
//! Check if the file iIo is a TIFF image.
EXIV2API bool isTiffType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef TIFFIMAGE_HPP_
#endif // #ifndef TIFFIMAGE_HPP_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -9,21 +9,19 @@
// *****************************************************************************
// included header files
// + standard includes
#include <vector>
#include <regex>
#include <vector>
/*!
@brief Make an integer version number for comparison from a major, minor and
a patch version number.
*/
#define EXIV2_MAKE_VERSION(major,minor,patch) \
(((major) << 16) | ((minor) << 8) | (patch))
#define EXIV2_MAKE_VERSION(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch))
/*!
@brief The %Exiv2 version number of the library used at compile-time as
an integer number for easy comparison.
*/
#define EXIV2_VERSION \
EXIV2_MAKE_VERSION(EXIV2_MAJOR_VERSION,EXIV2_MINOR_VERSION,EXIV2_PATCH_VERSION)
#define EXIV2_VERSION EXIV2_MAKE_VERSION(EXIV2_MAJOR_VERSION, EXIV2_MINOR_VERSION, EXIV2_PATCH_VERSION)
/*!
@brief Macro to test the version the %Exiv2 library at compile-time.
@ -68,45 +66,42 @@
#endif
@endcode
*/
#define EXIV2_TEST_VERSION(major,minor,patch) \
( EXIV2_VERSION >= EXIV2_MAKE_VERSION(major,minor,patch) )
#define EXIV2_TEST_VERSION(major, minor, patch) (EXIV2_VERSION >= EXIV2_MAKE_VERSION(major, minor, patch))
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
/*!
@brief Return the version of %Exiv2 available at runtime as an integer.
*/
EXIV2API int versionNumber();
/*!
@brief Return the version string Example: "0.25.0" (major.minor.patch)
*/
EXIV2API std::string versionString();
/*!
@brief Return the version of %Exiv2 as hex string of fixed length 6.
*/
EXIV2API std::string versionNumberHexString();
/*!
@brief Return the version of %Exiv2 as "C" string eg "0.27.0.2".
*/
EXIV2API const char* version();
/*!
@brief Test the version of the available %Exiv2 library at runtime. Return
true if it is the same as or newer than the passed-in version.
Versions are denoted using a triplet of integers: \em major.minor.patch .
The fourth version number is designated a "tweak" an used by Release Candidates
*/
EXIV2API bool testVersion(int major, int minor, int patch);
/*!
@brief dumpLibraryInfo implements the exiv2 option --version --verbose
used by exiv2 test suite to inspect libraries loaded at run-time
*/
EXIV2API void dumpLibraryInfo(std::ostream& os,const std::vector<std::regex>& keys);
} // namespace Exiv2
#endif // VERSION_HPP_
/*!
@brief Return the version of %Exiv2 available at runtime as an integer.
*/
EXIV2API int versionNumber();
/*!
@brief Return the version string Example: "0.25.0" (major.minor.patch)
*/
EXIV2API std::string versionString();
/*!
@brief Return the version of %Exiv2 as hex string of fixed length 6.
*/
EXIV2API std::string versionNumberHexString();
/*!
@brief Return the version of %Exiv2 as "C" string eg "0.27.0.2".
*/
EXIV2API const char* version();
/*!
@brief Test the version of the available %Exiv2 library at runtime. Return
true if it is the same as or newer than the passed-in version.
Versions are denoted using a triplet of integers: \em major.minor.patch .
The fourth version number is designated a "tweak" an used by Release Candidates
*/
EXIV2API bool testVersion(int major, int minor, int patch);
/*!
@brief dumpLibraryInfo implements the exiv2 option --version --verbose
used by exiv2 test suite to inspect libraries loaded at run-time
*/
EXIV2API void dumpLibraryInfo(std::ostream& os, const std::vector<std::regex>& keys);
} // namespace Exiv2
#endif // VERSION_HPP_

@ -12,100 +12,96 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access WEBP video files.
*/
class EXIV2API WebPImage:public Image
{
public:
//! @name Creators
//@{
/*!
@brief Constructor for a WebP video. Since the constructor
can not return a result, callers should check the good() method
after object construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
explicit WebPImage(BasicIo::UniquePtr io);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
//@}
/*!
@brief Not supported. Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
void setIptcData(const IptcData& /*iptcData*/) override;
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
//! Copy constructor
WebPImage(const WebPImage& rhs) = delete;
//! Assignment operator
WebPImage& operator=(const WebPImage& rhs) = delete;
//@}
private:
void doWriteMetadata(BasicIo& outIo);
//! @name NOT Implemented
//@{
static long getHeaderOffset(const byte* data, long data_size, const byte* header, long header_size);
static bool equalsWebPTag(Exiv2::DataBuf& buf, const char* str);
void debugPrintHex(byte *data, long size);
void decodeChunks(long filesize);
void inject_VP8X(BasicIo& iIo, bool has_xmp, bool has_exif,
bool has_alpha, bool has_icc, int width,
int height);
static const byte WEBP_PAD_ODD;
static const int WEBP_TAG_SIZE;
static const int WEBP_VP8X_ICC_BIT;
static const int WEBP_VP8X_ALPHA_BIT;
static const int WEBP_VP8X_EXIF_BIT;
static const int WEBP_VP8X_XMP_BIT;
static const char* const WEBP_CHUNK_HEADER_VP8X;
static const char* const WEBP_CHUNK_HEADER_VP8L;
static const char* const WEBP_CHUNK_HEADER_VP8;
static const char* const WEBP_CHUNK_HEADER_ANMF;
static const char* const WEBP_CHUNK_HEADER_ANIM;
static const char* const WEBP_CHUNK_HEADER_ICCP;
static const char* const WEBP_CHUNK_HEADER_EXIF;
static const char* const WEBP_CHUNK_HEADER_XMP;
}; //Class WebPImage
/*!
@brief Class to access WEBP video files.
*/
class EXIV2API WebPImage : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor for a WebP video. Since the constructor
can not return a result, callers should check the good() method
after object construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
explicit WebPImage(BasicIo::UniquePtr io);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
void printStructure(std::ostream& out, PrintStructureOption option, int depth) override;
//@}
/*!
@brief Not supported. Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
void setIptcData(const IptcData& /*iptcData*/) override;
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
//! Copy constructor
WebPImage(const WebPImage& rhs) = delete;
//! Assignment operator
WebPImage& operator=(const WebPImage& rhs) = delete;
//@}
private:
void doWriteMetadata(BasicIo& outIo);
//! @name NOT Implemented
//@{
static long getHeaderOffset(const byte* data, long data_size, const byte* header, long header_size);
static bool equalsWebPTag(Exiv2::DataBuf& buf, const char* str);
void debugPrintHex(byte* data, long size);
void decodeChunks(long filesize);
void inject_VP8X(BasicIo& iIo, bool has_xmp, bool has_exif, bool has_alpha, bool has_icc, int width, int height);
static const byte WEBP_PAD_ODD;
static const int WEBP_TAG_SIZE;
static const int WEBP_VP8X_ICC_BIT;
static const int WEBP_VP8X_ALPHA_BIT;
static const int WEBP_VP8X_EXIF_BIT;
static const int WEBP_VP8X_XMP_BIT;
static const char* const WEBP_CHUNK_HEADER_VP8X;
static const char* const WEBP_CHUNK_HEADER_VP8L;
static const char* const WEBP_CHUNK_HEADER_VP8;
static const char* const WEBP_CHUNK_HEADER_ANMF;
static const char* const WEBP_CHUNK_HEADER_ANIM;
static const char* const WEBP_CHUNK_HEADER_ICCP;
static const char* const WEBP_CHUNK_HEADER_EXIF;
static const char* const WEBP_CHUNK_HEADER_XMP;
}; // Class WebPImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new WebPImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newWebPInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new WebPImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newWebPInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a WebP Video.
EXIV2API bool isWebPType(BasicIo& iIo, bool advance);
//! Check if the file iIo is a WebP Video.
EXIV2API bool isWebPType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // WEBPIMAGE_HPP
#endif // WEBPIMAGE_HPP

@ -13,406 +13,409 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class ExifData;
class ExifData;
// *****************************************************************************
// class definitions
/*!
@brief Information related to an XMP property. An XMP metadatum consists
of an XmpKey and a Value and provides methods to manipulate these.
*/
class EXIV2API Xmpdatum : public Metadatum {
public:
//! @name Creators
//@{
/*!
@brief Constructor for new tags created by an application. The
%Xmpdatum is created from a key / value pair. %Xmpdatum
copies (clones) the value if one is provided. Alternatively, a
program can create an 'empty' %Xmpdatum with only a key and
set the value using setValue().
@param key The key of the %Xmpdatum.
@param pValue Pointer to a %Xmpdatum value.
@throw Error if the key cannot be parsed and converted
to a known schema namespace prefix and property name.
*/
explicit Xmpdatum(const XmpKey& key, const Value* pValue = nullptr);
//! Copy constructor
Xmpdatum(const Xmpdatum& rhs);
//! Destructor
~Xmpdatum() override;
//@}
//! @name Manipulators
//@{
//! Assignment operator
Xmpdatum& operator=(const Xmpdatum& rhs);
/*!
@brief Assign std::string \em value to the %Xmpdatum.
Calls setValue(const std::string&).
*/
Xmpdatum& operator=(const std::string& value);
/*!
@brief Assign const char* \em value to the %Xmpdatum.
Calls operator=(const std::string&).
*/
Xmpdatum& operator=(const char* value);
/*!
@brief Assign a boolean \em value to the %Xmpdatum.
Translates the value to a string "true" or "false".
*/
Xmpdatum& operator=(const bool& value);
/*!
@brief Assign a \em value of any type with an output operator
to the %Xmpdatum. Calls operator=(const std::string&).
*/
template<typename T>
Xmpdatum& operator=(const T& value);
/*!
@brief Assign Value \em value to the %Xmpdatum.
Calls setValue(const Value*).
*/
Xmpdatum& operator=(const Value& value);
void setValue(const Value* pValue) override;
/*!
@brief Set the value to the string \em value. Uses Value::read(const
std::string&). If the %Xmpdatum does not have a Value yet,
then a %Value of the correct type for this %Xmpdatum is
created. If the key is unknown, a XmpTextValue is used as
default. Return 0 if the value was read successfully.
*/
int setValue(const std::string& value) override;
//@}
//! @name Accessors
//@{
//! Not implemented. Calling this method will raise an exception.
size_t copy(byte* buf, ByteOrder byteOrder) const override;
std::ostream& write(std::ostream& os, const ExifData* pMetadata = nullptr) const override;
/*!
@brief Return the key of the Xmpdatum. The key is of the form
'<b>Xmp</b>.prefix.property'. Note however that the
key is not necessarily unique, i.e., an XmpData object may
contain multiple metadata with the same key.
*/
std::string key() const override;
const char* familyName() const override;
//! Return the (preferred) schema namespace prefix.
std::string groupName() const override;
//! Return the property name.
std::string tagName() const override;
std::string tagLabel() const override;
//! Properties don't have a tag number. Return 0.
uint16_t tag() const override;
TypeId typeId() const override;
const char* typeName() const override;
// Todo: Remove this method from the baseclass
//! The Exif typeSize doesn't make sense here. Return 0.
size_t typeSize() const override;
size_t count() const override;
size_t size() const override;
std::string toString() const override;
std::string toString(size_t n) const override;
int64_t toInt64(size_t n = 0) const override;
float toFloat(size_t n = 0) const override;
Rational toRational(size_t n = 0) const override;
Value::UniquePtr getValue() const override;
const Value& value() const override;
//@}
private:
// Pimpl idiom
struct Impl;
std::unique_ptr<Impl> p_;
}; // class Xmpdatum
//! Container type to hold all metadata
using XmpMetadata = std::vector<Xmpdatum>;
/*!
@brief A container for XMP data. This is a top-level class of
the %Exiv2 library.
Provide high-level access to the XMP data of an image:
- read XMP information from an XML block
- access metadata through keys and standard C++ iterators
- add, modify and delete metadata
- serialize XMP data to an XML block
*/
class EXIV2API XmpData {
public:
//! Default constructor
XmpData() = default;
//! XmpMetadata iterator type
using iterator = XmpMetadata::iterator;
//! XmpMetadata const iterator type
using const_iterator = XmpMetadata::const_iterator;
//! @name Manipulators
//@{
/*!
@brief Returns a reference to the %Xmpdatum that is associated with a
particular \em key. If %XmpData does not already contain such
an %Xmpdatum, operator[] adds object \em Xmpdatum(key).
@note Since operator[] might insert a new element, it can't be a const
member function.
*/
Xmpdatum& operator[](const std::string& key);
/*!
@brief Add an %Xmpdatum from the supplied key and value pair. This
method copies (clones) the value.
@return 0 if successful.
*/
int add(const XmpKey& key, const Value* value);
/*!
@brief Add a copy of the Xmpdatum to the XMP metadata.
@return 0 if successful.
*/
int add(const Xmpdatum& xmpdatum);
/*
@brief Delete the Xmpdatum at iterator position pos, return the
position of the next Xmpdatum.
@note Iterators into the metadata, including pos, are potentially
invalidated by this call.
@brief Delete the Xmpdatum at iterator position pos and update pos
*/
iterator erase(XmpData::iterator pos);
/*!
@brief Delete the Xmpdatum at iterator position pos and update pos
erases all following keys from the same family
See: https://github.com/Exiv2/exiv2/issues/521
*/
void eraseFamily(XmpData::iterator& pos);
//! Delete all Xmpdatum instances resulting in an empty container.
void clear();
//! Sort metadata by key
void sortByKey();
//! Begin of the metadata
iterator begin();
//! End of the metadata
iterator end();
/*!
@brief Find the first Xmpdatum with the given key, return an iterator
to it.
*/
iterator findKey(const XmpKey& key);
//@}
//! @name Accessors
//@{
//! Begin of the metadata
const_iterator begin() const;
//! End of the metadata
const_iterator end() const;
/*!
@brief Find the first Xmpdatum with the given key, return a const
iterator to it.
*/
const_iterator findKey(const XmpKey& key) const;
//! Return true if there is no XMP metadata
bool empty() const;
//! Get the number of metadata entries
long count() const;
//! are we to use the packet?
bool usePacket() const { return usePacket_; } ;
//! set usePacket_
bool usePacket(bool b) { bool r = usePacket_; usePacket_=b ; return r; };
//! setPacket
void setPacket(const std::string& xmpPacket) { xmpPacket_ = xmpPacket ; usePacket(false); };
// ! getPacket
const std::string& xmpPacket() const { return xmpPacket_ ; };
//@}
private:
// DATA
XmpMetadata xmpMetadata_;
std::string xmpPacket_ ;
bool usePacket_{};
}; // class XmpData
/*!
@brief Stateless parser class for XMP packets. Images use this
class to parse and serialize XMP packets. The parser uses
the XMP toolkit to do the job.
*/
class EXIV2API XmpParser {
public:
//! Options to control the format of the serialized XMP packet.
enum XmpFormatFlags {
omitPacketWrapper = 0x0010UL, //!< Omit the XML packet wrapper.
readOnlyPacket = 0x0020UL, //!< Default is a writeable packet.
useCompactFormat = 0x0040UL, //!< Use a compact form of RDF.
includeThumbnailPad = 0x0100UL, //!< Include a padding allowance for a thumbnail image.
exactPacketLength = 0x0200UL, //!< The padding parameter is the overall packet length.
writeAliasComments = 0x0400UL, //!< Show aliases as XML comments.
omitAllFormatting = 0x0800UL //!< Omit all formatting whitespace.
};
/*!
@brief Decode XMP metadata from an XMP packet \em xmpPacket into
\em xmpData. The format of the XMP packet must follow the
XMP specification. This method clears any previous contents
of \em xmpData.
@param xmpData Container for the decoded XMP properties
@param xmpPacket The raw XMP packet to decode
@return 0 if successful;<BR>
1 if XMP support has not been compiled-in;<BR>
2 if the XMP toolkit failed to initialize;<BR>
3 if the XMP toolkit failed and raised an XMP_Error
*/
static int decode( XmpData& xmpData,
const std::string& xmpPacket);
/*!
@brief Encode (serialize) XMP metadata from \em xmpData into a
string xmpPacket. The XMP packet returned in the string
follows the XMP specification. This method only modifies
\em xmpPacket if the operations succeeds (return code 0).
@param xmpPacket Reference to a string to hold the encoded XMP
packet.
@param xmpData XMP properties to encode.
@param formatFlags Flags that control the format of the XMP packet,
see enum XmpFormatFlags.
@param padding Padding length.
@return 0 if successful;<BR>
1 if XMP support has not been compiled-in;<BR>
2 if the XMP toolkit failed to initialize;<BR>
3 if the XMP toolkit failed and raised an XMP_Error
*/
static int encode( std::string& xmpPacket,
const XmpData& xmpData,
uint16_t formatFlags =useCompactFormat,
uint32_t padding =0);
/*!
@brief Lock/unlock function type
A function of this type can be passed to initialize() to
make subsequent registration of XMP namespaces thread-safe.
See the initialize() function for more information.
@param pLockData Pointer to the pLockData passed to initialize()
@param lockUnlock Indicates whether to lock (true) or unlock (false)
*/
using XmpLockFct = void (*)(void* pLockData, bool lockUnlock);
/*!
@brief Initialize the XMP Toolkit.
Calling this method is usually not needed, as encode() and
decode() will initialize the XMP Toolkit if necessary.
The function takes optional pointers to a callback function
\em xmpLockFct and related data \em pLockData that the parser
uses when XMP namespaces are subsequently registered.
The initialize() function itself still is not thread-safe and
needs to be called in a thread-safe manner (e.g., on program
startup), but if used with suitable additional locking
parameters, any subsequent registration of namespaces will be
thread-safe.
Example usage on Windows using a critical section:
@code
void main()
{
struct XmpLock
{
CRITICAL_SECTION cs;
XmpLock() { InitializeCriticalSection(&cs); }
~XmpLock() { DeleteCriticalSection(&cs); }
static void LockUnlock(void* pData, bool fLock)
{
XmpLock* pThis = reinterpret_cast<XmpLock*>(pData);
if (pThis)
{
(fLock) ? EnterCriticalSection(&pThis->cs)
: LeaveCriticalSection(&pThis->cs);
}
}
} xmpLock;
// Pass the locking mechanism to the XMP parser on initialization.
// Note however that this call itself is still not thread-safe.
Exiv2::XmpParser::initialize(XmpLock::LockUnlock, &xmpLock);
// Program continues here, subsequent registrations of XMP
// namespaces are serialized using xmpLock.
}
@endcode
@return True if the initialization was successful, else false.
*/
static bool initialize(XmpParser::XmpLockFct xmpLockFct = nullptr, void* pLockData = nullptr);
/*!
@brief Terminate the XMP Toolkit and unregister custom namespaces.
Call this method when the XmpParser is no longer needed to
allow the XMP Toolkit to cleanly shutdown.
*/
static void terminate();
private:
/*!
@brief Register a namespace with the XMP Toolkit.
*/
static void registerNs(const std::string& ns,
const std::string& prefix);
/*!
@brief Delete a namespace from the XMP Toolkit.
XmpProperties::unregisterNs calls this to synchronize namespaces.
*/
static void unregisterNs(const std::string& ns);
/*!
@brief Get namespaces registered with XMPsdk
*/
static void registeredNamespaces(Exiv2::Dictionary&);
// DATA
static bool initialized_; //! Indicates if the XMP Toolkit has been initialized
static XmpLockFct xmpLockFct_;
static void* pLockData_;
friend class XmpProperties; // permit XmpProperties -> registerNs() and registeredNamespaces()
}; // class XmpParser
/*!
@brief Information related to an XMP property. An XMP metadatum consists
of an XmpKey and a Value and provides methods to manipulate these.
*/
class EXIV2API Xmpdatum : public Metadatum {
public:
//! @name Creators
//@{
/*!
@brief Constructor for new tags created by an application. The
%Xmpdatum is created from a key / value pair. %Xmpdatum
copies (clones) the value if one is provided. Alternatively, a
program can create an 'empty' %Xmpdatum with only a key and
set the value using setValue().
@param key The key of the %Xmpdatum.
@param pValue Pointer to a %Xmpdatum value.
@throw Error if the key cannot be parsed and converted
to a known schema namespace prefix and property name.
*/
explicit Xmpdatum(const XmpKey& key, const Value* pValue = nullptr);
//! Copy constructor
Xmpdatum(const Xmpdatum& rhs);
//! Destructor
~Xmpdatum() override;
//@}
//! @name Manipulators
//@{
//! Assignment operator
Xmpdatum& operator=(const Xmpdatum& rhs);
/*!
@brief Assign std::string \em value to the %Xmpdatum.
Calls setValue(const std::string&).
*/
Xmpdatum& operator=(const std::string& value);
/*!
@brief Assign const char* \em value to the %Xmpdatum.
Calls operator=(const std::string&).
*/
Xmpdatum& operator=(const char* value);
/*!
@brief Assign a boolean \em value to the %Xmpdatum.
Translates the value to a string "true" or "false".
*/
Xmpdatum& operator=(const bool& value);
/*!
@brief Assign a \em value of any type with an output operator
to the %Xmpdatum. Calls operator=(const std::string&).
*/
template <typename T>
Xmpdatum& operator=(const T& value);
/*!
@brief Assign Value \em value to the %Xmpdatum.
Calls setValue(const Value*).
*/
Xmpdatum& operator=(const Value& value);
void setValue(const Value* pValue) override;
/*!
@brief Set the value to the string \em value. Uses Value::read(const
std::string&). If the %Xmpdatum does not have a Value yet,
then a %Value of the correct type for this %Xmpdatum is
created. If the key is unknown, a XmpTextValue is used as
default. Return 0 if the value was read successfully.
*/
int setValue(const std::string& value) override;
//@}
//! @name Accessors
//@{
//! Not implemented. Calling this method will raise an exception.
size_t copy(byte* buf, ByteOrder byteOrder) const override;
std::ostream& write(std::ostream& os, const ExifData* pMetadata = nullptr) const override;
/*!
@brief Return the key of the Xmpdatum. The key is of the form
'<b>Xmp</b>.prefix.property'. Note however that the
key is not necessarily unique, i.e., an XmpData object may
contain multiple metadata with the same key.
*/
std::string key() const override;
const char* familyName() const override;
//! Return the (preferred) schema namespace prefix.
std::string groupName() const override;
//! Return the property name.
std::string tagName() const override;
std::string tagLabel() const override;
//! Properties don't have a tag number. Return 0.
uint16_t tag() const override;
TypeId typeId() const override;
const char* typeName() const override;
// Todo: Remove this method from the baseclass
//! The Exif typeSize doesn't make sense here. Return 0.
size_t typeSize() const override;
size_t count() const override;
size_t size() const override;
std::string toString() const override;
std::string toString(size_t n) const override;
int64_t toInt64(size_t n = 0) const override;
float toFloat(size_t n = 0) const override;
Rational toRational(size_t n = 0) const override;
Value::UniquePtr getValue() const override;
const Value& value() const override;
//@}
private:
// Pimpl idiom
struct Impl;
std::unique_ptr<Impl> p_;
}; // class Xmpdatum
//! Container type to hold all metadata
using XmpMetadata = std::vector<Xmpdatum>;
/*!
@brief A container for XMP data. This is a top-level class of
the %Exiv2 library.
Provide high-level access to the XMP data of an image:
- read XMP information from an XML block
- access metadata through keys and standard C++ iterators
- add, modify and delete metadata
- serialize XMP data to an XML block
*/
class EXIV2API XmpData {
public:
//! Default constructor
XmpData() = default;
//! XmpMetadata iterator type
using iterator = XmpMetadata::iterator;
//! XmpMetadata const iterator type
using const_iterator = XmpMetadata::const_iterator;
//! @name Manipulators
//@{
/*!
@brief Returns a reference to the %Xmpdatum that is associated with a
particular \em key. If %XmpData does not already contain such
an %Xmpdatum, operator[] adds object \em Xmpdatum(key).
@note Since operator[] might insert a new element, it can't be a const
member function.
*/
Xmpdatum& operator[](const std::string& key);
/*!
@brief Add an %Xmpdatum from the supplied key and value pair. This
method copies (clones) the value.
@return 0 if successful.
*/
int add(const XmpKey& key, const Value* value);
/*!
@brief Add a copy of the Xmpdatum to the XMP metadata.
@return 0 if successful.
*/
int add(const Xmpdatum& xmpdatum);
/*
@brief Delete the Xmpdatum at iterator position pos, return the
position of the next Xmpdatum.
@note Iterators into the metadata, including pos, are potentially
invalidated by this call.
@brief Delete the Xmpdatum at iterator position pos and update pos
*/
iterator erase(XmpData::iterator pos);
/*!
@brief Delete the Xmpdatum at iterator position pos and update pos
erases all following keys from the same family
See: https://github.com/Exiv2/exiv2/issues/521
*/
void eraseFamily(XmpData::iterator& pos);
//! Delete all Xmpdatum instances resulting in an empty container.
void clear();
//! Sort metadata by key
void sortByKey();
//! Begin of the metadata
iterator begin();
//! End of the metadata
iterator end();
/*!
@brief Find the first Xmpdatum with the given key, return an iterator
to it.
*/
iterator findKey(const XmpKey& key);
//@}
//! @name Accessors
//@{
//! Begin of the metadata
const_iterator begin() const;
//! End of the metadata
const_iterator end() const;
/*!
@brief Find the first Xmpdatum with the given key, return a const
iterator to it.
*/
const_iterator findKey(const XmpKey& key) const;
//! Return true if there is no XMP metadata
bool empty() const;
//! Get the number of metadata entries
long count() const;
//! are we to use the packet?
bool usePacket() const {
return usePacket_;
};
//! set usePacket_
bool usePacket(bool b) {
bool r = usePacket_;
usePacket_ = b;
return r;
};
//! setPacket
void setPacket(const std::string& xmpPacket) {
xmpPacket_ = xmpPacket;
usePacket(false);
};
// ! getPacket
const std::string& xmpPacket() const {
return xmpPacket_;
};
//@}
private:
// DATA
XmpMetadata xmpMetadata_;
std::string xmpPacket_;
bool usePacket_{};
}; // class XmpData
/*!
@brief Stateless parser class for XMP packets. Images use this
class to parse and serialize XMP packets. The parser uses
the XMP toolkit to do the job.
*/
class EXIV2API XmpParser {
public:
//! Options to control the format of the serialized XMP packet.
enum XmpFormatFlags {
omitPacketWrapper = 0x0010UL, //!< Omit the XML packet wrapper.
readOnlyPacket = 0x0020UL, //!< Default is a writeable packet.
useCompactFormat = 0x0040UL, //!< Use a compact form of RDF.
includeThumbnailPad = 0x0100UL, //!< Include a padding allowance for a thumbnail image.
exactPacketLength = 0x0200UL, //!< The padding parameter is the overall packet length.
writeAliasComments = 0x0400UL, //!< Show aliases as XML comments.
omitAllFormatting = 0x0800UL //!< Omit all formatting whitespace.
};
/*!
@brief Decode XMP metadata from an XMP packet \em xmpPacket into
\em xmpData. The format of the XMP packet must follow the
XMP specification. This method clears any previous contents
of \em xmpData.
@param xmpData Container for the decoded XMP properties
@param xmpPacket The raw XMP packet to decode
@return 0 if successful;<BR>
1 if XMP support has not been compiled-in;<BR>
2 if the XMP toolkit failed to initialize;<BR>
3 if the XMP toolkit failed and raised an XMP_Error
*/
static int decode(XmpData& xmpData, const std::string& xmpPacket);
/*!
@brief Encode (serialize) XMP metadata from \em xmpData into a
string xmpPacket. The XMP packet returned in the string
follows the XMP specification. This method only modifies
\em xmpPacket if the operations succeeds (return code 0).
@param xmpPacket Reference to a string to hold the encoded XMP
packet.
@param xmpData XMP properties to encode.
@param formatFlags Flags that control the format of the XMP packet,
see enum XmpFormatFlags.
@param padding Padding length.
@return 0 if successful;<BR>
1 if XMP support has not been compiled-in;<BR>
2 if the XMP toolkit failed to initialize;<BR>
3 if the XMP toolkit failed and raised an XMP_Error
*/
static int encode(std::string& xmpPacket, const XmpData& xmpData, uint16_t formatFlags = useCompactFormat,
uint32_t padding = 0);
/*!
@brief Lock/unlock function type
A function of this type can be passed to initialize() to
make subsequent registration of XMP namespaces thread-safe.
See the initialize() function for more information.
@param pLockData Pointer to the pLockData passed to initialize()
@param lockUnlock Indicates whether to lock (true) or unlock (false)
*/
using XmpLockFct = void (*)(void* pLockData, bool lockUnlock);
/*!
@brief Initialize the XMP Toolkit.
Calling this method is usually not needed, as encode() and
decode() will initialize the XMP Toolkit if necessary.
The function takes optional pointers to a callback function
\em xmpLockFct and related data \em pLockData that the parser
uses when XMP namespaces are subsequently registered.
The initialize() function itself still is not thread-safe and
needs to be called in a thread-safe manner (e.g., on program
startup), but if used with suitable additional locking
parameters, any subsequent registration of namespaces will be
thread-safe.
Example usage on Windows using a critical section:
@code
void main()
{
struct XmpLock
{
CRITICAL_SECTION cs;
XmpLock() { InitializeCriticalSection(&cs); }
~XmpLock() { DeleteCriticalSection(&cs); }
static void LockUnlock(void* pData, bool fLock)
{
XmpLock* pThis = reinterpret_cast<XmpLock*>(pData);
if (pThis)
{
(fLock) ? EnterCriticalSection(&pThis->cs)
: LeaveCriticalSection(&pThis->cs);
}
}
} xmpLock;
// Pass the locking mechanism to the XMP parser on initialization.
// Note however that this call itself is still not thread-safe.
Exiv2::XmpParser::initialize(XmpLock::LockUnlock, &xmpLock);
// Program continues here, subsequent registrations of XMP
// namespaces are serialized using xmpLock.
}
@endcode
@return True if the initialization was successful, else false.
*/
static bool initialize(XmpParser::XmpLockFct xmpLockFct = nullptr, void* pLockData = nullptr);
/*!
@brief Terminate the XMP Toolkit and unregister custom namespaces.
Call this method when the XmpParser is no longer needed to
allow the XMP Toolkit to cleanly shutdown.
*/
static void terminate();
private:
/*!
@brief Register a namespace with the XMP Toolkit.
*/
static void registerNs(const std::string& ns, const std::string& prefix);
/*!
@brief Delete a namespace from the XMP Toolkit.
XmpProperties::unregisterNs calls this to synchronize namespaces.
*/
static void unregisterNs(const std::string& ns);
/*!
@brief Get namespaces registered with XMPsdk
*/
static void registeredNamespaces(Exiv2::Dictionary&);
// DATA
static bool initialized_; //! Indicates if the XMP Toolkit has been initialized
static XmpLockFct xmpLockFct_;
static void* pLockData_;
friend class XmpProperties; // permit XmpProperties -> registerNs() and registeredNamespaces()
}; // class XmpParser
// *****************************************************************************
// free functions, template and inline definitions
inline Xmpdatum& Xmpdatum::operator=(const char* value)
{
return Xmpdatum::operator=(std::string(value));
}
inline Xmpdatum& Xmpdatum::operator=(const char* value) {
return Xmpdatum::operator=(std::string(value));
}
inline Xmpdatum& Xmpdatum::operator=(const bool& value)
{
return operator=(value ? "True" : "False");
}
inline Xmpdatum& Xmpdatum::operator=(const bool& value) {
return operator=(value ? "True" : "False");
}
template<typename T>
Xmpdatum& Xmpdatum::operator=(const T& value)
{
setValue(Exiv2::toString(value));
return *this;
}
template <typename T>
Xmpdatum& Xmpdatum::operator=(const T& value) {
setValue(Exiv2::toString(value));
return *this;
}
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef XMP_HPP_
#endif // #ifndef XMP_HPP_

@ -12,77 +12,76 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief Class to access XMP sidecar files. They contain only XMP metadata.
*/
class EXIV2API XmpSidecar : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor for an XMP sidecar file. Since the constructor
can not return a result, callers should check the good() method
after object construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new image should be created (true).
*/
XmpSidecar(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Not supported. XMP sidecar files do not contain a comment.
Calling this function will throw an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
private:
//! @name NOT Implemented
//@{
//! Copy constructor
XmpSidecar(const XmpSidecar& rhs);
//! Assignment operator
XmpSidecar& operator=(const XmpSidecar& rhs);
//@}
Exiv2::Dictionary dates_;
}; // class XmpSidecar
/*!
@brief Class to access XMP sidecar files. They contain only XMP metadata.
*/
class EXIV2API XmpSidecar : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor for an XMP sidecar file. Since the constructor
can not return a result, callers should check the good() method
after object construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new image should be created (true).
*/
XmpSidecar(BasicIo::UniquePtr io, bool create);
//@}
//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
/*!
@brief Not supported. XMP sidecar files do not contain a comment.
Calling this function will throw an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/
void setComment(std::string_view comment) override;
//@}
//! @name Accessors
//@{
std::string mimeType() const override;
//@}
private:
//! @name NOT Implemented
//@{
//! Copy constructor
XmpSidecar(const XmpSidecar& rhs);
//! Assignment operator
XmpSidecar& operator=(const XmpSidecar& rhs);
//@}
Exiv2::Dictionary dates_;
}; // class XmpSidecar
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new XmpSidecar instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newXmpInstance(BasicIo::UniquePtr io, bool create);
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new XmpSidecar instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newXmpInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is an XMP sidecar file.
EXIV2API bool isXmpType(BasicIo& iIo, bool advance);
//! Check if the file iIo is an XMP sidecar file.
EXIV2API bool isXmpType(BasicIo& iIo, bool advance);
} // namespace Exiv2
} // namespace Exiv2
#endif // #ifndef XMPSIDECAR_HPP_
#endif // #ifndef XMPSIDECAR_HPP_

@ -57,7 +57,7 @@ target_include_directories(getopt-test PRIVATE
${CMAKE_SOURCE_DIR}/app
) # To find getopt.hpp
add_executable( metacopy metacopy.cpp ../app/getopt.cpp)
add_executable( metacopy metacopy.cpp metacopy.hpp ../app/getopt.cpp)
list(APPEND APPLICATIONS metacopy)
target_include_directories(metacopy PRIVATE
${CMAKE_SOURCE_DIR}/app

File diff suppressed because it is too large Load Diff

@ -22,434 +22,496 @@ THE SOFTWARE.
#ifndef Jzon_h__
#define Jzon_h__
#ifndef JzonAPI
# ifdef _WINDLL
# define JzonAPI __declspec(dllimport)
# elif defined(__GNUC__) && (__GNUC__ >= 4)
# define JzonAPI __attribute__ ((visibility("default")))
# else
# define JzonAPI
# endif
#ifndef JzonAPI
#ifdef _WINDLL
#define JzonAPI __declspec(dllimport)
#elif defined(__GNUC__) && (__GNUC__ >= 4)
#define JzonAPI __attribute__((visibility("default")))
#else
#define JzonAPI
#endif
#endif
#include <string>
#include <vector>
#include <queue>
#include <iterator>
#include <queue>
#include <stdexcept>
#include <string>
#include <vector>
namespace Jzon
{
class Node;
class Value;
class Object;
class Array;
using NamedNode = std::pair<std::string, Node&>;
using NamedNodePtr = std::pair<std::string, Node*>;
class TypeException : public std::logic_error
{
public:
TypeException() : std::logic_error("A Node was used as the wrong type")
{}
};
class NotFoundException : public std::out_of_range
{
public:
NotFoundException() : std::out_of_range("The node could not be found")
{}
};
struct Format
{
bool newline;
bool spacing;
bool useTabs;
unsigned int indentSize;
};
static const Format StandardFormat = { true, true, true, 1 };
static const Format NoFormat = { false, false, false, 0 };
class JzonAPI Node
{
friend class Object;
friend class Array;
public:
enum Type
{
T_OBJECT,
T_ARRAY,
T_VALUE
};
Node() noexcept = default;
virtual ~Node() noexcept = default;
virtual Type GetType() const = 0;
inline bool IsObject() const { return (GetType() == T_OBJECT); }
inline bool IsArray() const { return (GetType() == T_ARRAY); }
inline bool IsValue() const { return (GetType() == T_VALUE); }
Object &AsObject();
const Object &AsObject() const;
Array &AsArray();
const Array &AsArray() const;
Value &AsValue();
const Value &AsValue() const;
virtual inline bool IsNull() const { return false; }
virtual inline bool IsString() const { return false; }
virtual inline bool IsNumber() const { return false; }
virtual inline bool IsBool() const { return false; }
virtual std::string ToString() const { throw TypeException(); }
virtual int ToInt() const { throw TypeException(); }
virtual float ToFloat() const { throw TypeException(); }
virtual double ToDouble() const { throw TypeException(); }
virtual bool ToBool() const { throw TypeException(); }
virtual bool Has(const std::string &/*name*/) const { throw TypeException(); }
virtual size_t GetCount() const { return 0; }
virtual Node &Get(const std::string &/*name*/) const { throw TypeException(); }
virtual Node &Get(size_t /*index*/) const { throw TypeException(); }
static Type DetermineType(const std::string &json);
protected:
virtual Node *GetCopy() const = 0;
};
class JzonAPI Value : public Node
{
public:
enum ValueType
{
VT_NULL,
VT_STRING,
VT_NUMBER,
VT_BOOL
};
Value();
Value(const Value &rhs);
Value(const Node &rhs);
Value(ValueType type, const std::string &value);
Value(const std::string &value);
Value(const char *value);
Value(const int value);
Value(const float value);
Value(const double value);
Value(const bool value);
~Value() override = default;
Type GetType() const override;
ValueType GetValueType() const;
inline bool IsNull() const override
{
return (type == VT_NULL);
}
inline bool IsString() const override
{
return (type == VT_STRING);
}
inline bool IsNumber() const override
{
return (type == VT_NUMBER);
}
inline bool IsBool() const override
{
return (type == VT_BOOL);
}
std::string ToString() const override;
int ToInt() const override;
float ToFloat() const override;
double ToDouble() const override;
bool ToBool() const override;
void SetNull();
void Set(const Value &value);
void Set(ValueType type, const std::string &value);
void Set(const std::string &value);
void Set(const char *value);
void Set(const int value);
void Set(const float value);
void Set(const double value);
void Set(const bool value);
Value &operator=(const Value &rhs);
Value &operator=(const Node &rhs);
Value &operator=(const std::string &rhs);
Value &operator=(const char *rhs);
Value &operator=(const int rhs);
Value &operator=(const float rhs);
Value &operator=(const double rhs);
Value &operator=(const bool rhs);
bool operator==(const Value &other) const;
bool operator!=(const Value &other) const;
static std::string EscapeString(const std::string &value);
static std::string UnescapeString(const std::string &value);
protected:
Node *GetCopy() const override;
private:
std::string valueStr;
ValueType type;
};
static const Value null;
class JzonAPI Object : public Node
{
public:
class iterator : public std::iterator<std::input_iterator_tag, NamedNode>
{
public:
iterator(NamedNodePtr *o) : p(o) {}
iterator(const iterator &it) : p(it.p) {}
iterator &operator++() { ++p; return *this; }
iterator operator++(int) { iterator tmp(*this); operator++(); return tmp; }
bool operator==(const iterator &rhs) { return p == rhs.p; }
bool operator!=(const iterator &rhs) { return p != rhs.p; }
NamedNode operator*() { return NamedNode(p->first, *p->second); }
private:
NamedNodePtr *p;
};
class const_iterator : public std::iterator<std::input_iterator_tag, const NamedNode>
{
public:
const_iterator(const NamedNodePtr *o) : p(o) {}
const_iterator(const const_iterator &it) : p(it.p) {}
const_iterator &operator++() { ++p; return *this; }
const_iterator operator++(int) { const_iterator tmp(*this); operator++(); return tmp; }
bool operator==(const const_iterator &rhs) { return p == rhs.p; }
bool operator!=(const const_iterator &rhs) { return p != rhs.p; }
const NamedNode operator*() { return NamedNode(p->first, *p->second); }
private:
const NamedNodePtr *p;
};
Object() = default;
Object(const Object &other);
Object(const Node &other);
~Object() override;
Type GetType() const override;
void Add(const std::string &name, Node &node);
void Add(const std::string &name, const Value &node);
void Remove(const std::string &name);
void Clear();
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
bool Has(const std::string &name) const override;
size_t GetCount() const override;
Node &Get(const std::string &name) const override;
using Node::Get;
protected:
Node *GetCopy() const override;
private:
using ChildList = std::vector<NamedNodePtr>;
ChildList children;
};
class JzonAPI Array : public Node
{
public:
class iterator : public std::iterator<std::input_iterator_tag, Node>
{
public:
iterator(Node **o) : p(o) {}
iterator(const iterator &it) : p(it.p) {}
iterator &operator++() { ++p; return *this; }
iterator operator++(int) { iterator tmp(*this); operator++(); return tmp; }
bool operator==(const iterator &rhs) { return p == rhs.p; }
bool operator!=(const iterator &rhs) { return p != rhs.p; }
Node &operator*() { return **p; }
private:
Node **p;
};
class const_iterator : public std::iterator<std::input_iterator_tag, const Node>
{
public:
const_iterator(const Node *const *o) : p(o) {}
const_iterator(const const_iterator &it) : p(it.p) {}
const_iterator &operator++() { ++p; return *this; }
const_iterator operator++(int) { const_iterator tmp(*this); operator++(); return tmp; }
bool operator==(const const_iterator &rhs) { return p == rhs.p; }
bool operator!=(const const_iterator &rhs) { return p != rhs.p; }
const Node &operator*() { return **p; }
private:
const Node *const *p;
};
Array() = default;
Array(const Array &other);
Array(const Node &other);
~Array() override;
Type GetType() const override;
void Add(Node &node);
void Add(const Value &node);
void Remove(size_t index);
void Clear();
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
size_t GetCount() const override;
Node &Get(size_t index) const override;
using Node::Get;
protected:
Node *GetCopy() const override;
private:
using ChildList = std::vector<Node *>;
ChildList children;
};
class JzonAPI FileWriter
{
public:
FileWriter(std::string filename);
~FileWriter() = default;
static void WriteFile(const std::string &filename, const Node &root, const Format &format = NoFormat);
void Write(const Node &root, const Format &format = NoFormat);
private:
std::string filename;
};
class JzonAPI FileReader
{
public:
FileReader(const std::string &filename);
~FileReader() = default;
static bool ReadFile(const std::string &filename, Node &node);
bool Read(Node &node);
namespace Jzon {
class Node;
class Value;
class Object;
class Array;
using NamedNode = std::pair<std::string, Node &>;
using NamedNodePtr = std::pair<std::string, Node *>;
class TypeException : public std::logic_error {
public:
TypeException() : std::logic_error("A Node was used as the wrong type") {
}
};
class NotFoundException : public std::out_of_range {
public:
NotFoundException() : std::out_of_range("The node could not be found") {
}
};
struct Format {
bool newline;
bool spacing;
bool useTabs;
unsigned int indentSize;
};
static const Format StandardFormat = {true, true, true, 1};
static const Format NoFormat = {false, false, false, 0};
class JzonAPI Node {
friend class Object;
friend class Array;
public:
enum Type { T_OBJECT, T_ARRAY, T_VALUE };
Node() noexcept = default;
virtual ~Node() noexcept = default;
virtual Type GetType() const = 0;
inline bool IsObject() const {
return (GetType() == T_OBJECT);
}
inline bool IsArray() const {
return (GetType() == T_ARRAY);
}
inline bool IsValue() const {
return (GetType() == T_VALUE);
}
Object &AsObject();
const Object &AsObject() const;
Array &AsArray();
const Array &AsArray() const;
Value &AsValue();
const Value &AsValue() const;
virtual inline bool IsNull() const {
return false;
}
virtual inline bool IsString() const {
return false;
}
virtual inline bool IsNumber() const {
return false;
}
virtual inline bool IsBool() const {
return false;
}
virtual std::string ToString() const {
throw TypeException();
}
virtual int ToInt() const {
throw TypeException();
}
virtual float ToFloat() const {
throw TypeException();
}
virtual double ToDouble() const {
throw TypeException();
}
virtual bool ToBool() const {
throw TypeException();
}
virtual bool Has(const std::string & /*name*/) const {
throw TypeException();
}
virtual size_t GetCount() const {
return 0;
}
virtual Node &Get(const std::string & /*name*/) const {
throw TypeException();
}
virtual Node &Get(size_t /*index*/) const {
throw TypeException();
}
static Type DetermineType(const std::string &json);
protected:
virtual Node *GetCopy() const = 0;
};
class JzonAPI Value : public Node {
public:
enum ValueType { VT_NULL, VT_STRING, VT_NUMBER, VT_BOOL };
Value();
Value(const Value &rhs);
Value(const Node &rhs);
Value(ValueType type, const std::string &value);
Value(const std::string &value);
Value(const char *value);
Value(const int value);
Value(const float value);
Value(const double value);
Value(const bool value);
~Value() override = default;
Type GetType() const override;
ValueType GetValueType() const;
inline bool IsNull() const override {
return (type == VT_NULL);
}
inline bool IsString() const override {
return (type == VT_STRING);
}
inline bool IsNumber() const override {
return (type == VT_NUMBER);
}
inline bool IsBool() const override {
return (type == VT_BOOL);
}
std::string ToString() const override;
int ToInt() const override;
float ToFloat() const override;
double ToDouble() const override;
bool ToBool() const override;
void SetNull();
void Set(const Value &value);
void Set(ValueType type, const std::string &value);
void Set(const std::string &value);
void Set(const char *value);
void Set(const int value);
void Set(const float value);
void Set(const double value);
void Set(const bool value);
Value &operator=(const Value &rhs);
Value &operator=(const Node &rhs);
Value &operator=(const std::string &rhs);
Value &operator=(const char *rhs);
Value &operator=(const int rhs);
Value &operator=(const float rhs);
Value &operator=(const double rhs);
Value &operator=(const bool rhs);
bool operator==(const Value &other) const;
bool operator!=(const Value &other) const;
static std::string EscapeString(const std::string &value);
static std::string UnescapeString(const std::string &value);
protected:
Node *GetCopy() const override;
private:
std::string valueStr;
ValueType type;
};
static const Value null;
class JzonAPI Object : public Node {
public:
class iterator : public std::iterator<std::input_iterator_tag, NamedNode> {
public:
iterator(NamedNodePtr *o) : p(o) {
}
iterator(const iterator &it) : p(it.p) {
}
iterator &operator++() {
++p;
return *this;
}
iterator operator++(int) {
iterator tmp(*this);
operator++();
return tmp;
}
bool operator==(const iterator &rhs) {
return p == rhs.p;
}
bool operator!=(const iterator &rhs) {
return p != rhs.p;
}
NamedNode operator*() {
return NamedNode(p->first, *p->second);
}
private:
NamedNodePtr *p;
};
class const_iterator : public std::iterator<std::input_iterator_tag, const NamedNode> {
public:
const_iterator(const NamedNodePtr *o) : p(o) {
}
const_iterator(const const_iterator &it) : p(it.p) {
}
const_iterator &operator++() {
++p;
return *this;
}
const_iterator operator++(int) {
const_iterator tmp(*this);
operator++();
return tmp;
}
bool operator==(const const_iterator &rhs) {
return p == rhs.p;
}
bool operator!=(const const_iterator &rhs) {
return p != rhs.p;
}
const NamedNode operator*() {
return NamedNode(p->first, *p->second);
}
private:
const NamedNodePtr *p;
};
Object() = default;
Object(const Object &other);
Object(const Node &other);
~Object() override;
Type GetType() const override;
void Add(const std::string &name, Node &node);
void Add(const std::string &name, const Value &node);
void Remove(const std::string &name);
void Clear();
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
bool Has(const std::string &name) const override;
size_t GetCount() const override;
Node &Get(const std::string &name) const override;
using Node::Get;
protected:
Node *GetCopy() const override;
private:
using ChildList = std::vector<NamedNodePtr>;
ChildList children;
};
class JzonAPI Array : public Node {
public:
class iterator : public std::iterator<std::input_iterator_tag, Node> {
public:
iterator(Node **o) : p(o) {
}
iterator(const iterator &it) : p(it.p) {
}
iterator &operator++() {
++p;
return *this;
}
iterator operator++(int) {
iterator tmp(*this);
operator++();
return tmp;
}
bool operator==(const iterator &rhs) {
return p == rhs.p;
}
bool operator!=(const iterator &rhs) {
return p != rhs.p;
}
Node &operator*() {
return **p;
}
private:
Node **p;
};
class const_iterator : public std::iterator<std::input_iterator_tag, const Node> {
public:
const_iterator(const Node *const *o) : p(o) {
}
const_iterator(const const_iterator &it) : p(it.p) {
}
const_iterator &operator++() {
++p;
return *this;
}
const_iterator operator++(int) {
const_iterator tmp(*this);
operator++();
return tmp;
}
bool operator==(const const_iterator &rhs) {
return p == rhs.p;
}
bool operator!=(const const_iterator &rhs) {
return p != rhs.p;
}
const Node &operator*() {
return **p;
}
private:
const Node *const *p;
};
Array() = default;
Array(const Array &other);
Array(const Node &other);
~Array() override;
Type GetType() const override;
void Add(Node &node);
void Add(const Value &node);
void Remove(size_t index);
void Clear();
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
size_t GetCount() const override;
Node &Get(size_t index) const override;
using Node::Get;
protected:
Node *GetCopy() const override;
private:
using ChildList = std::vector<Node *>;
ChildList children;
};
class JzonAPI FileWriter {
public:
FileWriter(std::string filename);
~FileWriter() = default;
static void WriteFile(const std::string &filename, const Node &root, const Format &format = NoFormat);
void Write(const Node &root, const Format &format = NoFormat);
private:
std::string filename;
};
class JzonAPI FileReader {
public:
FileReader(const std::string &filename);
~FileReader() = default;
static bool ReadFile(const std::string &filename, Node &node);
bool Read(Node &node);
Node::Type DetermineType();
Node::Type DetermineType();
const std::string &GetError() const;
private:
static bool loadFile(const std::string &filename, std::string &json);
std::string json;
std::string error;
};
const std::string &GetError() const;
class JzonAPI Writer {
public:
Writer(const Node &root, const Format &format = NoFormat);
~Writer();
private:
static bool loadFile(const std::string &filename, std::string &json);
std::string json;
std::string error;
};
void SetFormat(const Format &format);
const std::string &Write();
class JzonAPI Writer
{
public:
Writer(const Node &root, const Format &format = NoFormat);
~Writer();
// Return result from last call to Write()
const std::string &GetResult() const;
void SetFormat(const Format &format);
const std::string &Write();
// Disable assignment operator
Writer &operator=(const Writer &) = delete;
// Return result from last call to Write()
const std::string &GetResult() const;
private:
void writeNode(const Node &node, size_t level);
void writeObject(const Object &node, size_t level);
void writeArray(const Array &node, size_t level);
void writeValue(const Value &node);
// Disable assignment operator
Writer &operator=(const Writer&) = delete;
private:
void writeNode(const Node &node, size_t level);
void writeObject(const Object &node, size_t level);
void writeArray(const Array &node, size_t level);
void writeValue(const Value &node);
std::string result;
std::string result;
class FormatInterpreter *fi;
class FormatInterpreter *fi;
const Node &root;
};
const Node &root;
};
class JzonAPI Parser {
public:
Parser(Node &root);
Parser(Node &root, const std::string &json);
~Parser() = default;
class JzonAPI Parser
{
public:
Parser(Node &root);
Parser(Node &root, const std::string &json);
~Parser() = default;
void SetJson(const std::string &json);
bool Parse();
void SetJson(const std::string &json);
bool Parse();
const std::string &GetError() const;
const std::string &GetError() const;
// Disable assignment operator
Parser &operator=(const Parser &) = delete;
// Disable assignment operator
Parser &operator=(const Parser&) = delete;
private:
enum Token
{
T_UNKNOWN,
T_OBJ_BEGIN,
T_OBJ_END,
T_ARRAY_BEGIN,
T_ARRAY_END,
T_SEPARATOR_NODE,
T_SEPARATOR_NAME,
T_VALUE
};
private:
enum Token {
T_UNKNOWN,
T_OBJ_BEGIN,
T_OBJ_END,
T_ARRAY_BEGIN,
T_ARRAY_END,
T_SEPARATOR_NODE,
T_SEPARATOR_NAME,
T_VALUE
};
void tokenize();
bool assemble();
void tokenize();
bool assemble();
char peek();
void jumpToNext(char c);
void jumpToCommentEnd();
char peek();
void jumpToNext(char c);
void jumpToCommentEnd();
void readString();
bool interpretValue(const std::string &value);
void readString();
bool interpretValue(const std::string &value);
std::string json;
std::size_t jsonSize{0};
std::string json;
std::size_t jsonSize{0};
std::queue<Token> tokens;
std::queue<std::pair<Value::ValueType, std::string> > data;
std::queue<Token> tokens;
std::queue<std::pair<Value::ValueType, std::string>> data;
std::size_t cursor{0};
std::size_t cursor{0};
Node &root;
Node &root;
std::string error;
};
}
std::string error;
};
} // namespace Jzon
#endif // Jzon_h__
#endif // Jzon_h__

@ -3,11 +3,11 @@
#include <exiv2/exiv2.hpp>
#include <iostream>
#include <cassert>
#include <iostream>
int main(int argc, char* const argv[])
try {
int main(int argc, char* const argv[]) {
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
@ -15,8 +15,8 @@ try {
#endif
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
std::string file(argv[1]);
@ -31,10 +31,10 @@ try {
// This is the quickest way to add (simple) Exif data. If a metadatum for
// a given key already exists, its value is overwritten. Otherwise a new
// tag is added.
exifData["Exif.Image.Model"] = "Test 1"; // AsciiValue
exifData["Exif.Image.SamplesPerPixel"] = uint16_t(162); // UShortValue
exifData["Exif.Image.XResolution"] = -2; // LongValue
exifData["Exif.Image.YResolution"] = Exiv2::Rational(-2, 3); // RationalValue
exifData["Exif.Image.Model"] = "Test 1"; // AsciiValue
exifData["Exif.Image.SamplesPerPixel"] = uint16_t(162); // UShortValue
exifData["Exif.Image.XResolution"] = -2; // LongValue
exifData["Exif.Image.YResolution"] = Exiv2::Rational(-2, 3); // RationalValue
std::cout << "Added a few tags the quick way.\n";
// Create a ASCII string value (note the use of create)
@ -67,29 +67,27 @@ try {
std::string date = tag.toString();
date.replace(0, 4, "2000");
tag.setValue(date);
std::cout << "Modified key \"" << tag.key()
<< "\", new value \"" << tag.value() << "\"\n";
std::cout << "Modified key \"" << tag.key() << "\", new value \"" << tag.value() << "\"\n";
// Alternatively, we can use findKey()
key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities");
auto pos = exifData.findKey(key);
if (pos == exifData.end())
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Key not found");
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Key not found");
// Get a pointer to a copy of the value
v = pos->getValue();
// Downcast the Value pointer to its actual type
auto prv = dynamic_cast<Exiv2::URationalValue*>(v.get());
if (!prv)
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Downcast failed");
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Downcast failed");
rv = Exiv2::URationalValue(*prv);
// Modify the value directly through the interface of URationalValue
rv.value_.at(2) = {88, 77};
// Copy the modified value back to the metadatum
pos->setValue(&rv);
std::cout << "Modified key \"" << key
<< "\", new value \"" << pos->value() << "\"\n";
std::cout << "Modified key \"" << key << "\", new value \"" << pos->value() << "\"\n";
// *************************************************************************
// Delete metadata from the Exif data container
@ -97,7 +95,8 @@ try {
// Delete the metadatum at iterator position pos
key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities");
pos = exifData.findKey(key);
if (pos == exifData.end()) throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Key not found");
if (pos == exifData.end())
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Key not found");
exifData.erase(pos);
std::cout << "Deleted key \"" << key << "\"\n";
@ -108,8 +107,8 @@ try {
image->writeMetadata();
return 0;
}
catch (Exiv2::Error& e) {
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
}

@ -3,113 +3,118 @@
#include <exiv2/exiv2.hpp>
#ifdef EXV_USE_CURL
#include <curl/curl.h>
#include <curl/curl.h>
#endif
#include <iostream>
#include <cstdlib>
#include <iostream>
void httpcon(const std::string& url, bool useHttp1_0 = false) {
Exiv2::Dictionary response;
Exiv2::Dictionary request;
std::string errors;
Exiv2::Uri uri = Exiv2::Uri::Parse(url);
Exiv2::Uri::Decode(uri);
request["server"] = uri.Host;
request["page"] = uri.Path;
request["port"] = uri.Port;
if (!useHttp1_0) request["version"] = "1.1";
int serverCode = Exiv2::http(request,response,errors);
if (serverCode < 0 || serverCode >= 400 || !errors.empty()) {
throw Exiv2::Error(Exiv2::ErrorCode::kerTiffDirectoryTooLarge, "Server", serverCode);
}
Exiv2::Dictionary response;
Exiv2::Dictionary request;
std::string errors;
Exiv2::Uri uri = Exiv2::Uri::Parse(url);
Exiv2::Uri::Decode(uri);
request["server"] = uri.Host;
request["page"] = uri.Path;
request["port"] = uri.Port;
if (!useHttp1_0)
request["version"] = "1.1";
int serverCode = Exiv2::http(request, response, errors);
if (serverCode < 0 || serverCode >= 400 || !errors.empty()) {
throw Exiv2::Error(Exiv2::ErrorCode::kerTiffDirectoryTooLarge, "Server", serverCode);
}
}
#ifdef EXV_USE_CURL
void curlcon(const std::string& url, bool useHttp1_0 = false) {
CURL* curl = curl_easy_init();
if(!curl) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Unable to init libcurl.");
}
// get the timeout value
std::string timeoutStr = Exiv2::getEnv(Exiv2::envTIMEOUT);
long timeout = atol(timeoutStr.c_str());
if (timeout == 0) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Timeout Environmental Variable must be a positive integer.");
}
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Exiv2::curlWriter);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout);
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); // debug
if (useHttp1_0) curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
else curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
/* Perform the request, res will get the return code */
CURLcode res = curl_easy_perform(curl);
if(res != CURLE_OK) { // error happened
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, curl_easy_strerror(res));
}
// get return code
long returnCode;
curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &returnCode); // get code
curl_easy_cleanup(curl);
if (returnCode >= 400 || returnCode < 0) {
throw Exiv2::Error(Exiv2::ErrorCode::kerTiffDirectoryTooLarge, "Server", returnCode);
}
CURL* curl = curl_easy_init();
if (!curl) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Unable to init libcurl.");
}
// get the timeout value
std::string timeoutStr = Exiv2::getEnv(Exiv2::envTIMEOUT);
long timeout = atol(timeoutStr.c_str());
if (timeout == 0) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Timeout Environmental Variable must be a positive integer.");
}
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Exiv2::curlWriter);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout);
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); // debug
if (useHttp1_0)
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
else
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
/* Perform the request, res will get the return code */
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) { // error happened
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, curl_easy_strerror(res));
}
// get return code
long returnCode;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &returnCode); // get code
curl_easy_cleanup(curl);
if (returnCode >= 400 || returnCode < 0) {
throw Exiv2::Error(Exiv2::ErrorCode::kerTiffDirectoryTooLarge, "Server", returnCode);
}
}
#endif
int main(int argc,const char** argv)
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, const char** argv) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " url {-http1_0}" << std::endl;
return 1;
}
std::string url(argv[1]);
Exiv2::Protocol prot = Exiv2::fileProtocol(url);
bool useHttp1_0 = false;
for ( int a = 1 ; a < argc ; a++ ) {
std::string arg(argv[a]);
if (arg == "-http1_0") useHttp1_0 = true;
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " url {-http1_0}" << std::endl;
return 1;
}
std::string url(argv[1]);
Exiv2::Protocol prot = Exiv2::fileProtocol(url);
bool useHttp1_0 = false;
for (int a = 1; a < argc; a++) {
std::string arg(argv[a]);
if (arg == "-http1_0")
useHttp1_0 = true;
}
bool isOk = false;
try {
#ifdef EXV_USE_CURL
if (prot == Exiv2::pHttp || prot == Exiv2::pHttps || prot == Exiv2::pFtp) {
curlcon(url, useHttp1_0);
isOk = true;
}
bool isOk = false;
try {
#ifdef EXV_USE_CURL
if (prot == Exiv2::pHttp || prot == Exiv2::pHttps || prot == Exiv2::pFtp) {
curlcon(url, useHttp1_0);
isOk = true;
}
#endif
if (!isOk && prot == Exiv2::pHttp) {
httpcon(url, useHttp1_0);
isOk = true;
}
} catch (const Exiv2::Error& e) {
std::cout << "Error: '" << e << "'" << std::endl;
return -1;
#endif
if (!isOk && prot == Exiv2::pHttp) {
httpcon(url, useHttp1_0);
isOk = true;
}
if (!isOk) std::cout << "The protocol is unsupported." << std::endl;
else std::cout << "OK." << std::endl;
return 0;
} catch (const Exiv2::Error& e) {
std::cout << "Error: '" << e << "'" << std::endl;
return -1;
}
if (!isOk)
std::cout << "The protocol is unsupported." << std::endl;
else
std::cout << "OK." << std::endl;
return 0;
}
// That's all Folks!

@ -3,11 +3,11 @@
#include <exiv2/exiv2.hpp>
#include <iostream>
#include <cassert>
#include <iostream>
int main(int argc, char* const argv[])
try {
int main(int argc, char* const argv[]) {
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
@ -15,8 +15,8 @@ try {
#endif
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
auto image = Exiv2::ImageFactory::open(argv[1]);
@ -31,10 +31,10 @@ try {
image->setXmpData(xmpData);
image->setExifData(exifData);
image->writeMetadata();
return 0;
}
catch (Exiv2::Error& e) {
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
}

@ -1,57 +1,55 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Sample program using high-level metadata access functions
#include <cassert>
#include <exiv2/exiv2.hpp>
#include <iostream>
#include <iomanip>
#include <cassert>
#include <iostream>
using EasyAccessFct = Exiv2::ExifData::const_iterator (*)(const Exiv2::ExifData&);
struct EasyAccess {
const char* label_;
EasyAccessFct findFct_;
const char* label_;
EasyAccessFct findFct_;
};
static const EasyAccess easyAccess[] = {
{ "Orientation", Exiv2::orientation },
{ "ISO speed", Exiv2::isoSpeed },
{ "Date & time original", Exiv2::dateTimeOriginal },
{ "Flash bias", Exiv2::flashBias },
{ "Exposure mode", Exiv2::exposureMode },
{ "Scene mode", Exiv2::sceneMode },
{ "Macro mode", Exiv2::macroMode },
{ "Image quality", Exiv2::imageQuality },
{ "White balance", Exiv2::whiteBalance },
{ "Lens name", Exiv2::lensName },
{ "Saturation", Exiv2::saturation },
{ "Sharpness", Exiv2::sharpness },
{ "Contrast", Exiv2::contrast },
{ "Scene capture type", Exiv2::sceneCaptureType },
{ "Metering mode", Exiv2::meteringMode },
{ "Camera make", Exiv2::make },
{ "Camera model", Exiv2::model },
{ "Exposure time", Exiv2::exposureTime },
{ "FNumber", Exiv2::fNumber },
{ "Shutter speed value", Exiv2::shutterSpeedValue },
{ "Aperture value", Exiv2::apertureValue },
{ "Brightness value", Exiv2::brightnessValue },
{ "Exposure bias", Exiv2::exposureBiasValue },
{ "Max aperture value", Exiv2::maxApertureValue },
{ "Subject distance", Exiv2::subjectDistance },
{ "Light source", Exiv2::lightSource },
{ "Flash", Exiv2::flash },
{ "Camera serial number", Exiv2::serialNumber },
{ "Focal length", Exiv2::focalLength },
{ "Subject location/area", Exiv2::subjectArea },
{ "Flash energy", Exiv2::flashEnergy },
{ "Exposure index", Exiv2::exposureIndex },
{ "Sensing method", Exiv2::sensingMethod },
{ "AF point", Exiv2::afPoint }
};
static const EasyAccess easyAccess[] = {{"Orientation", Exiv2::orientation},
{"ISO speed", Exiv2::isoSpeed},
{"Date & time original", Exiv2::dateTimeOriginal},
{"Flash bias", Exiv2::flashBias},
{"Exposure mode", Exiv2::exposureMode},
{"Scene mode", Exiv2::sceneMode},
{"Macro mode", Exiv2::macroMode},
{"Image quality", Exiv2::imageQuality},
{"White balance", Exiv2::whiteBalance},
{"Lens name", Exiv2::lensName},
{"Saturation", Exiv2::saturation},
{"Sharpness", Exiv2::sharpness},
{"Contrast", Exiv2::contrast},
{"Scene capture type", Exiv2::sceneCaptureType},
{"Metering mode", Exiv2::meteringMode},
{"Camera make", Exiv2::make},
{"Camera model", Exiv2::model},
{"Exposure time", Exiv2::exposureTime},
{"FNumber", Exiv2::fNumber},
{"Shutter speed value", Exiv2::shutterSpeedValue},
{"Aperture value", Exiv2::apertureValue},
{"Brightness value", Exiv2::brightnessValue},
{"Exposure bias", Exiv2::exposureBiasValue},
{"Max aperture value", Exiv2::maxApertureValue},
{"Subject distance", Exiv2::subjectDistance},
{"Light source", Exiv2::lightSource},
{"Flash", Exiv2::flash},
{"Camera serial number", Exiv2::serialNumber},
{"Focal length", Exiv2::focalLength},
{"Subject location/area", Exiv2::subjectArea},
{"Flash energy", Exiv2::flashEnergy},
{"Exposure index", Exiv2::exposureIndex},
{"Sensing method", Exiv2::sensingMethod},
{"AF point", Exiv2::afPoint}};
int main(int argc, char **argv)
try {
int main(int argc, char** argv) {
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
@ -59,8 +57,8 @@ try {
#endif
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
auto image = Exiv2::ImageFactory::open(argv[1]);
@ -68,20 +66,19 @@ try {
Exiv2::ExifData& ed = image->exifData();
for (auto&& ea : easyAccess) {
auto pos = ea.findFct_(ed);
std::cout << std::setw(21) << std::left << ea.label_;
if (pos != ed.end()) {
std::cout << " (" << std::setw(35) << pos->key() << ") : "
<< pos->print(&ed) << "\n";
}
else {
std::cout << " (" << std::setw(35) << " " << ") : \n";
}
auto pos = ea.findFct_(ed);
std::cout << std::setw(21) << std::left << ea.label_;
if (pos != ed.end()) {
std::cout << " (" << std::setw(35) << pos->key() << ") : " << pos->print(&ed) << "\n";
} else {
std::cout << " (" << std::setw(35) << " "
<< ") : \n";
}
}
return 0;
}
catch (Exiv2::Error& e) {
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
}

@ -1,14 +1,14 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Abstract : Sample program showing how to set the Exif comment of an image, Exif.Photo.UserComment
#include <cassert>
#include <exiv2/exiv2.hpp>
#include <iostream>
#include <cassert>
// *****************************************************************************
// Main
int main(int argc, char* const argv[])
try {
int main(int argc, char* const argv[]) {
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
@ -16,13 +16,13 @@ try {
#endif
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
auto image = Exiv2::ImageFactory::open(argv[1]);
image->readMetadata();
Exiv2::ExifData &exifData = image->exifData();
Exiv2::ExifData& exifData = image->exifData();
/*
Exiv2 uses a CommentValue for Exif user comments. The format of the
@ -41,15 +41,13 @@ try {
exifData["Exif.Photo.UserComment"] = "Another undefined Exif comment added with Exiv2";
exifData["Exif.Photo.UserComment"] = "charset=Ascii An ASCII Exif comment added with Exiv2";
std::cout << "Writing user comment '"
<< exifData["Exif.Photo.UserComment"]
<< "' back to the image\n";
std::cout << "Writing user comment '" << exifData["Exif.Photo.UserComment"] << "' back to the image\n";
image->writeMetadata();
return 0;
}
catch (Exiv2::Error& e) {
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
}

@ -8,9 +8,8 @@ void print(const std::string& file);
// *****************************************************************************
// Main
int main(int argc, char* const argv[])
{
try {
int main(int argc, char* const argv[]) {
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
@ -18,19 +17,19 @@ try {
#endif
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
std::string file(argv[1]);
auto image = Exiv2::ImageFactory::open(file);
assert (image);
assert(image);
image->readMetadata();
Exiv2::ExifData &ed = image->exifData();
Exiv2::ExifData& ed = image->exifData();
if (ed.empty()) {
std::string error = file + ": No Exif data found in the file";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
std::string error = file + ": No Exif data found in the file";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
std::cout << "Copy construction, non-intrusive changes\n";
@ -40,7 +39,7 @@ try {
ed1["Exif.Photo.DateTimeOriginal"] = "Sunday, 11am";
ed1["Exif.Photo.MeteringMode"] = uint16_t(1);
ed1["Exif.Iop.InteroperabilityIndex"] = "123";
// ed1["Exif.Thumbnail.Orientation"] = uint16_t(2);
// ed1["Exif.Thumbnail.Orientation"] = uint16_t(2);
write(file, ed1);
print(file);
std::cout << "----------------------------------------------\n";
@ -87,40 +86,29 @@ try {
print(file);
return 0;
}
catch (Exiv2::Error& e) {
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
}
}
void write(const std::string& file, Exiv2::ExifData& ed)
{
auto image = Exiv2::ImageFactory::open(file);
image->setExifData(ed);
image->writeMetadata();
void write(const std::string& file, Exiv2::ExifData& ed) {
auto image = Exiv2::ImageFactory::open(file);
image->setExifData(ed);
image->writeMetadata();
}
void print(const std::string& file)
{
auto image = Exiv2::ImageFactory::open(file);
image->readMetadata();
void print(const std::string& file) {
auto image = Exiv2::ImageFactory::open(file);
image->readMetadata();
Exiv2::ExifData &ed = image->exifData();
auto end = ed.end();
for (auto i = ed.begin(); i != end; ++i) {
std::cout << std::setw(45) << std::setfill(' ') << std::left
<< i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right
<< std::hex << i->tag() << " "
<< std::setw(12) << std::setfill(' ') << std::left
<< i->ifdName() << " "
<< std::setw(9) << std::setfill(' ') << std::left
<< i->typeName() << " "
<< std::dec << std::setw(3)
<< std::setfill(' ') << std::right
<< i->count() << " "
<< std::dec << i->toString()
<< "\n";
}
Exiv2::ExifData& ed = image->exifData();
auto end = ed.end();
for (auto i = ed.begin(); i != end; ++i) {
std::cout << std::setw(45) << std::setfill(' ') << std::left << i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " " << std::setw(12)
<< std::setfill(' ') << std::left << i->ifdName() << " " << std::setw(9) << std::setfill(' ') << std::left
<< i->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << i->count()
<< " " << std::dec << i->toString() << "\n";
}
}

@ -3,208 +3,211 @@
#include <exiv2/exiv2.hpp>
#include <iostream>
#include <cassert>
#include <iostream>
#include <string>
using format_t = std::map<std::string, int>;
using format_i = format_t::const_iterator;
enum format_e
{
wolf,
csv,
json,
xml
};
void syntax(const char* argv[],format_t& formats)
{
std::cout << "Usage: " << argv[0] << " file format" << std::endl;
int count = 0;
std::cout << "formats: ";
for (auto&& format : formats) {
std::cout << (count++ ? " | " : "") << format.first;
}
std::cout << std::endl;
enum format_e { wolf, csv, json, xml };
void syntax(const char* argv[], format_t& formats) {
std::cout << "Usage: " << argv[0] << " file format" << std::endl;
int count = 0;
std::cout << "formats: ";
for (auto&& format : formats) {
std::cout << (count++ ? " | " : "") << format.first;
}
std::cout << std::endl;
}
size_t formatInit(Exiv2::ExifData& exifData)
{
return std::distance(exifData.begin(), exifData.end());
size_t formatInit(Exiv2::ExifData& exifData) {
return std::distance(exifData.begin(), exifData.end());
}
///////////////////////////////////////////////////////////////////////
std::string escapeCSV(Exiv2::ExifData::const_iterator it,bool bValue)
{
std::string result ;
std::ostringstream os;
if ( bValue ) os << it->value() ; else os << it->key() ;
std::string s = os.str();
for (auto&& c : s) {
if (c == ',')
result += '\\';
result += c;
}
return result;
std::string escapeCSV(Exiv2::ExifData::const_iterator it, bool bValue) {
std::string result;
std::ostringstream os;
if (bValue)
os << it->value();
else
os << it->key();
std::string s = os.str();
for (auto&& c : s) {
if (c == ',')
result += '\\';
result += c;
}
return result;
}
std::string formatCSV(Exiv2::ExifData& exifData)
{
size_t count = 0;
size_t length = formatInit(exifData);
std::ostringstream result;
for (auto i = exifData.begin(); count++ < length; ++i) {
result << escapeCSV(i,false) << (count != length ? ", " : "" ) ;
}
result << std::endl;
count = 0;
for (auto i = exifData.begin(); count++ < length ; ++i) {
result << escapeCSV(i,true) << (count != length ? ", " : "" ) ;
}
return result.str();
std::string formatCSV(Exiv2::ExifData& exifData) {
size_t count = 0;
size_t length = formatInit(exifData);
std::ostringstream result;
for (auto i = exifData.begin(); count++ < length; ++i) {
result << escapeCSV(i, false) << (count != length ? ", " : "");
}
result << std::endl;
count = 0;
for (auto i = exifData.begin(); count++ < length; ++i) {
result << escapeCSV(i, true) << (count != length ? ", " : "");
}
return result.str();
}
///////////////////////////////////////////////////////////////////////
std::string formatWolf(Exiv2::ExifData& exifData)
{
size_t count = 0;
size_t length = formatInit(exifData);
std::ostringstream result;
result << "{ " << std::endl;
for (auto i = exifData.begin(); count++ < length ; ++i) {
result << " " << i->key() << " -> " << i->value() << (count != length ? "," : "" ) << std::endl ;
}
result << "}";
return result.str();
std::string formatWolf(Exiv2::ExifData& exifData) {
size_t count = 0;
size_t length = formatInit(exifData);
std::ostringstream result;
result << "{ " << std::endl;
for (auto i = exifData.begin(); count++ < length; ++i) {
result << " " << i->key() << " -> " << i->value() << (count != length ? "," : "") << std::endl;
}
result << "}";
return result.str();
}
///////////////////////////////////////////////////////////////////////
std::string escapeJSON(Exiv2::ExifData::const_iterator it,bool bValue=true)
{
std::string result ;
std::ostringstream os;
if ( bValue ) os << it->value() ; else os << it->key() ;
std::string s = os.str();
for (auto&& c : s) {
if (c == '"')
result += "\\\"";
result += c;
}
std::string q = "\"";
return q + result + q;
std::string escapeJSON(Exiv2::ExifData::const_iterator it, bool bValue = true) {
std::string result;
std::ostringstream os;
if (bValue)
os << it->value();
else
os << it->key();
std::string s = os.str();
for (auto&& c : s) {
if (c == '"')
result += "\\\"";
result += c;
}
std::string q = "\"";
return q + result + q;
}
std::string formatJSON(Exiv2::ExifData& exifData)
{
size_t count = 0;
size_t length = formatInit(exifData);
std::ostringstream result;
result << "{" << std::endl ;
for (auto i = exifData.begin(); count++ < length ; ++i) {
result << " " << escapeJSON(i,false) << ":" << escapeJSON(i,true) << ( count != length ? "," : "" ) << std::endl ;
}
result << "}";
return result.str();
std::string formatJSON(Exiv2::ExifData& exifData) {
size_t count = 0;
size_t length = formatInit(exifData);
std::ostringstream result;
result << "{" << std::endl;
for (auto i = exifData.begin(); count++ < length; ++i) {
result << " " << escapeJSON(i, false) << ":" << escapeJSON(i, true) << (count != length ? "," : "") << std::endl;
}
result << "}";
return result.str();
}
///////////////////////////////////////////////////////////////////////
std::string escapeXML(Exiv2::ExifData::const_iterator it,bool bValue=true)
{
std::string result ;
std::ostringstream os;
if ( bValue ) os << it->value() ; else os << it->key() ;
std::string s = os.str();
for (auto&& c : s) {
if (c == '<')
result += "&lg;";
if (c == '>')
result += "&gt;";
result += c;
}
return result;
std::string escapeXML(Exiv2::ExifData::const_iterator it, bool bValue = true) {
std::string result;
std::ostringstream os;
if (bValue)
os << it->value();
else
os << it->key();
std::string s = os.str();
for (auto&& c : s) {
if (c == '<')
result += "&lg;";
if (c == '>')
result += "&gt;";
result += c;
}
return result;
}
std::string formatXML(Exiv2::ExifData& exifData)
{
size_t count = 0;
size_t length = formatInit(exifData);
std::ostringstream result;
result << "<exif>" << std::endl;
for (auto i = exifData.begin(); count++ < length ; ++i) {
std::string key = escapeXML(i,false);
std::string value = escapeXML(i,true);
result << " <" << key << ">" << value << "<" << key << "/>" << std::endl ;
}
result << "</exif>" << std::endl;
return result.str();
std::string formatXML(Exiv2::ExifData& exifData) {
size_t count = 0;
size_t length = formatInit(exifData);
std::ostringstream result;
result << "<exif>" << std::endl;
for (auto i = exifData.begin(); count++ < length; ++i) {
std::string key = escapeXML(i, false);
std::string value = escapeXML(i, true);
result << " <" << key << ">" << value << "<" << key << "/>" << std::endl;
}
result << "</exif>" << std::endl;
return result.str();
}
///////////////////////////////////////////////////////////////////////
int main(int argc,const char* argv[])
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, const char* argv[]) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
format_t formats;
formats["wolf"] = wolf;
formats["csv" ] = csv ;
formats["json"] = json;
formats["xml" ] = xml ;
int result = 0 ;
if (argc != 3) {
syntax(argv,formats) ;
result = 1;
format_t formats;
formats["wolf"] = wolf;
formats["csv"] = csv;
formats["json"] = json;
formats["xml"] = xml;
int result = 0;
if (argc != 3) {
syntax(argv, formats);
result = 1;
}
const char* file = argv[1];
const char* format = argv[2];
if (!result && formats.find(format) == formats.end()) {
std::cout << "Unrecognised format " << format << std::endl;
syntax(argv, formats);
result = 2;
}
if (!result)
try {
auto image = Exiv2::ImageFactory::open(file);
image->readMetadata();
Exiv2::ExifData& exifData = image->exifData();
switch (formats.find(format)->second) {
case wolf:
std::cout << formatWolf(exifData) << std::endl;
break;
case csv:
std::cout << formatCSV(exifData) << std::endl;
break;
case json:
std::cout << formatJSON(exifData) << std::endl;
break;
case xml:
std::cout << formatXML(exifData) << std::endl;
break;
default:
std::cout << "*** error: format not implemented yet: " << format << " ***" << std::endl;
result = 3;
break;
}
} catch (Exiv2::Error& e) {
std::cerr << "*** error exiv2 exception '" << e << "' ***" << std::endl;
result = 4;
} catch (...) {
std::cerr << "*** error exception" << std::endl;
result = 5;
}
const char* file = argv[1];
const char* format = argv[2];
if ( !result && formats.find(format) == formats.end() ) {
std::cout << "Unrecognised format " << format << std::endl;
syntax(argv,formats);
result = 2;
}
if ( !result ) try {
auto image = Exiv2::ImageFactory::open(file);
image->readMetadata();
Exiv2::ExifData &exifData = image->exifData();
switch ( formats.find(format)->second ) {
case wolf : std::cout << formatWolf(exifData) << std::endl; break;
case csv : std::cout << formatCSV (exifData) << std::endl; break;
case json : std::cout << formatJSON(exifData) << std::endl; break;
case xml : std::cout << formatXML (exifData) << std::endl; break;
default : std::cout << "*** error: format not implemented yet: " << format << " ***" << std::endl;
result = 3;
break;
}
} catch (Exiv2::Error& e) {
std::cerr << "*** error exiv2 exception '" << e << "' ***" << std::endl;
result = 4;
} catch ( ... ) {
std::cerr << "*** error exception" << std::endl;
result = 5;
}
return result;
return result;
}

@ -5,15 +5,14 @@
#include <regex>
// copied from src/tiffvisitor_int.cpp
static const Exiv2::TagInfo* findTag(const Exiv2::TagInfo* pList,uint16_t tag)
{
while ( pList->tag_ != 0xffff && pList->tag_ != tag ) pList++;
return pList->tag_ != 0xffff ? pList : nullptr;
static const Exiv2::TagInfo* findTag(const Exiv2::TagInfo* pList, uint16_t tag) {
while (pList->tag_ != 0xffff && pList->tag_ != tag)
pList++;
return pList->tag_ != 0xffff ? pList : nullptr;
}
int main(int argc, char* const argv[])
try {
int main(int argc, char* const argv[]) {
try {
setlocale(LC_CTYPE, ".utf8");
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
@ -23,56 +22,55 @@ try {
const char* prog = argv[0];
if (argc == 1) {
std::cout << "Usage: " << prog << " [ [--lint] path | --version | --version-test ]" << std::endl;
return 1;
std::cout << "Usage: " << prog << " [ [--lint] path | --version | --version-test ]" << std::endl;
return 1;
}
int rc = 0 ;
int rc = 0;
const char* file = argv[1];
bool bLint = strcmp(file, "--lint") == 0 && argc == 3;
if ( bLint ) file= argv[2];
bool bLint = strcmp(file, "--lint") == 0 && argc == 3;
if (bLint)
file = argv[2];
if ( strcmp(file,"--version") == 0 ) {
std::vector<std::regex> keys;
Exiv2::dumpLibraryInfo(std::cout,keys);
return rc;
if (strcmp(file, "--version") == 0) {
std::vector<std::regex> keys;
Exiv2::dumpLibraryInfo(std::cout, keys);
return rc;
}
if (strcmp(file, "--version-test") == 0) {
// verifies/test macro EXIV2_TEST_VERSION
// described in include/exiv2/version.hpp
std::cout << "EXV_PACKAGE_VERSION " << EXV_PACKAGE_VERSION << std::endl
<< "Exiv2::version() " << Exiv2::version() << std::endl
<< "strlen(Exiv2::version()) " << ::strlen(Exiv2::version()) << std::endl
<< "Exiv2::versionNumber() " << Exiv2::versionNumber() << std::endl
<< "Exiv2::versionString() " << Exiv2::versionString() << std::endl
<< "Exiv2::versionNumberHexString() " << Exiv2::versionNumberHexString() << std::endl
;
// verifies/test macro EXIV2_TEST_VERSION
// described in include/exiv2/version.hpp
std::cout << "EXV_PACKAGE_VERSION " << EXV_PACKAGE_VERSION << std::endl
<< "Exiv2::version() " << Exiv2::version() << std::endl
<< "strlen(Exiv2::version()) " << ::strlen(Exiv2::version()) << std::endl
<< "Exiv2::versionNumber() " << Exiv2::versionNumber() << std::endl
<< "Exiv2::versionString() " << Exiv2::versionString() << std::endl
<< "Exiv2::versionNumberHexString() " << Exiv2::versionNumberHexString() << std::endl;
// Test the Exiv2 version available at runtime but compile the if-clause only if
// the compile-time version is at least 0.15. Earlier versions didn't have a
// testVersion() function:
#if EXIV2_TEST_VERSION(0,15,0)
if (Exiv2::testVersion(0,13,0)) {
std::cout << "Available Exiv2 version is equal to or greater than 0.13\n";
} else {
std::cout << "Installed Exiv2 version is less than 0.13\n";
}
#else
std::cout << "Compile-time Exiv2 version doesn't have Exiv2::testVersion()\n";
#endif
return rc;
// Test the Exiv2 version available at runtime but compile the if-clause only if
// the compile-time version is at least 0.15. Earlier versions didn't have a
// testVersion() function:
#if EXIV2_TEST_VERSION(0, 15, 0)
if (Exiv2::testVersion(0, 13, 0)) {
std::cout << "Available Exiv2 version is equal to or greater than 0.13\n";
} else {
std::cout << "Installed Exiv2 version is less than 0.13\n";
}
#else
std::cout << "Compile-time Exiv2 version doesn't have Exiv2::testVersion()\n";
#endif
return rc;
}
auto image = Exiv2::ImageFactory::open(file);
image->readMetadata();
Exiv2::ExifData &exifData = image->exifData();
Exiv2::ExifData& exifData = image->exifData();
if (exifData.empty()) {
std::string error("No Exif data found in file");
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
std::string error("No Exif data found in file");
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
std::set<std::string> shortLong;
shortLong.insert("Exif.Photo.PixelXDimension");
shortLong.insert("Exif.Photo.PixelYDimension");
@ -84,42 +82,34 @@ try {
auto end = exifData.end();
for (auto i = exifData.begin(); i != end; ++i) {
if ( ! bLint ) {
const char* tn = i->typeName();
std::cout << std::setw(44) << std::setfill(' ') << std::left
<< i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right
<< std::hex << i->tag() << " "
<< std::setw(9) << std::setfill(' ') << std::left
<< (tn ? tn : "Unknown") << " "
<< std::dec << std::setw(3)
<< std::setfill(' ') << std::right
<< i->count() << " "
<< std::dec << i->toString()
<< "\n";
} else {
const Exiv2::TagInfo* tagInfo = findTag( Exiv2::ExifTags::tagList(i->groupName()),i->tag() );
if ( tagInfo ) {
Exiv2::TypeId type = i->typeId();
if ( type!= tagInfo-> typeId_
&&!(tagInfo->typeId_ == Exiv2::comment && type == Exiv2::undefined) // comment is stored as undefined
&&!(shortLong.find(i->key())!=shortLong.end() &&(type == Exiv2::unsignedShort||type==Exiv2::unsignedLong)) // can be short or long!
) {
std::cerr << i->key()
<< " type " << i->typeName() << " (" << type << ")"
<< " expected " << Exiv2::TypeInfo::typeName(tagInfo-> typeId_) << " (" << tagInfo-> typeId_ << ")"
<< std::endl;
rc=2;
}
}
if (!bLint) {
const char* tn = i->typeName();
std::cout << std::setw(44) << std::setfill(' ') << std::left << i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " "
<< std::setw(9) << std::setfill(' ') << std::left << (tn ? tn : "Unknown") << " " << std::dec
<< std::setw(3) << std::setfill(' ') << std::right << i->count() << " " << std::dec << i->toString()
<< "\n";
} else {
const Exiv2::TagInfo* tagInfo = findTag(Exiv2::ExifTags::tagList(i->groupName()), i->tag());
if (tagInfo) {
Exiv2::TypeId type = i->typeId();
if (type != tagInfo->typeId_ &&
!(tagInfo->typeId_ == Exiv2::comment && type == Exiv2::undefined) // comment is stored as undefined
&& !(shortLong.find(i->key()) != shortLong.end() &&
(type == Exiv2::unsignedShort || type == Exiv2::unsignedLong)) // can be short or long!
) {
std::cerr << i->key() << " type " << i->typeName() << " (" << type << ")"
<< " expected " << Exiv2::TypeInfo::typeName(tagInfo->typeId_) << " (" << tagInfo->typeId_ << ")"
<< std::endl;
rc = 2;
}
}
}
}
return rc;
}
//catch (std::exception& e) {
//catch (Exiv2::Error& e) {
catch (Exiv2::Error& e) {
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e.what() << "'\n";
return -1;
}
}

@ -5,40 +5,39 @@
#include <iostream>
int main(int argc, char* const argv[])
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " file key\n";
return 1;
}
const char* file = argv[1];
const char* key = argv[2];
auto image = Exiv2::ImageFactory::open(file);
image->readMetadata();
Exiv2::ExifData &exifData = image->exifData();
if ( exifData.empty()) {
std::cerr << "no metadata found in file " << file << std::endl;
exit(2);
}
try {
std::cout << exifData[key] << std::endl;
} catch (Exiv2::Error& e) {
std::cerr << "Caught Exiv2 exception '" << e << "'" << std::endl;
exit(3);
} catch ( ... ) {
std::cerr << "Caught a cold!" << std::endl;
exit(4);
}
return 0;
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " file key\n";
return 1;
}
const char* file = argv[1];
const char* key = argv[2];
auto image = Exiv2::ImageFactory::open(file);
image->readMetadata();
Exiv2::ExifData& exifData = image->exifData();
if (exifData.empty()) {
std::cerr << "no metadata found in file " << file << std::endl;
exit(2);
}
try {
std::cout << exifData[key] << std::endl;
} catch (Exiv2::Error& e) {
std::cerr << "Caught Exiv2 exception '" << e << "'" << std::endl;
exit(3);
} catch (...) {
std::cerr << "Caught a cold!" << std::endl;
exit(4);
}
return 0;
}

@ -19,83 +19,86 @@
#endif
struct Token {
std::string n; // the name eg "History"
bool a; // name is an array eg History[]
int i; // index (indexed from 1) eg History[1]/stEvt:action
std::string n; // the name eg "History"
bool a; // name is an array eg History[]
int i; // index (indexed from 1) eg History[1]/stEvt:action
};
using Tokens = std::vector<Token>;
// "XMP.xmp.MP.RegionInfo/MPRI:Regions[1]/MPReg:Rectangle"
bool getToken(std::string& in, Token& token, std::set<std::string>* pNS = nullptr)
{
bool result = false;
bool ns = false;
token.n = "" ;
token.a = false ;
token.i = 0 ;
while ( !result && in.length() ) {
std::string c = in.substr(0,1);
char C = c.at(0);
in = in.substr(1,std::string::npos);
if ( in.length() == 0 && C != ']' ) token.n += c;
if ( C == '/' || C == '[' || C == ':' || C == '.' || C == ']' || in.length() == 0 ) {
ns |= C == '/' ;
token.a = C == '[' ;
if ( C == ']' ) token.i = std::atoi(token.n.c_str()); // encoded string first index == 1
result = token.n.length() > 0 ;
} else {
token.n += c;
}
bool getToken(std::string& in, Token& token, std::set<std::string>* pNS = nullptr) {
bool result = false;
bool ns = false;
token.n = "";
token.a = false;
token.i = 0;
while (!result && in.length()) {
std::string c = in.substr(0, 1);
char C = c.at(0);
in = in.substr(1, std::string::npos);
if (in.length() == 0 && C != ']')
token.n += c;
if (C == '/' || C == '[' || C == ':' || C == '.' || C == ']' || in.length() == 0) {
ns |= C == '/';
token.a = C == '[';
if (C == ']')
token.i = std::atoi(token.n.c_str()); // encoded string first index == 1
result = token.n.length() > 0;
} else {
token.n += c;
}
if (ns && pNS) pNS->insert(token.n);
}
if (ns && pNS)
pNS->insert(token.n);
return result;
return result;
}
Jzon::Node& addToTree(Jzon::Node& r1, const Token& token)
{
Jzon::Object object ;
Jzon::Array array ;
std::string key = token.n ;
size_t index = token.i-1; // array Eg: "History[1]" indexed from 1. Jzon expects 0 based index.
auto& empty = token.a ? static_cast<Jzon::Node&>(array) : static_cast<Jzon::Node&>(object);
if ( r1.IsObject() ) {
Jzon::Object& o1 = r1.AsObject();
if ( !o1.Has(key) ) o1.Add(key,empty);
return o1.Get(key);
}
if (r1.IsArray()) {
Jzon::Array& a1 = r1.AsArray();
while ( a1.GetCount() <= index ) a1.Add(empty);
return a1.Get(index);
}
return r1;
Jzon::Node& addToTree(Jzon::Node& r1, const Token& token) {
Jzon::Object object;
Jzon::Array array;
std::string key = token.n;
size_t index = token.i - 1; // array Eg: "History[1]" indexed from 1. Jzon expects 0 based index.
auto& empty = token.a ? static_cast<Jzon::Node&>(array) : static_cast<Jzon::Node&>(object);
if (r1.IsObject()) {
Jzon::Object& o1 = r1.AsObject();
if (!o1.Has(key))
o1.Add(key, empty);
return o1.Get(key);
}
if (r1.IsArray()) {
Jzon::Array& a1 = r1.AsArray();
while (a1.GetCount() <= index)
a1.Add(empty);
return a1.Get(index);
}
return r1;
}
Jzon::Node& recursivelyBuildTree(Jzon::Node& root,Tokens& tokens,size_t k)
{
return addToTree( k==0 ? root : recursivelyBuildTree(root,tokens,k-1), tokens.at(k) );
Jzon::Node& recursivelyBuildTree(Jzon::Node& root, Tokens& tokens, size_t k) {
return addToTree(k == 0 ? root : recursivelyBuildTree(root, tokens, k - 1), tokens.at(k));
}
// build the json tree for this key. return location and discover the name
Jzon::Node& objectForKey(const std::string& Key, Jzon::Object& root, std::string& name,
std::set<std::string>* pNS = nullptr)
{
// Parse the key
Tokens tokens ;
Token token ;
std::string input = Key ; // Example: "XMP.xmp.MP.RegionInfo/MPRI:Regions[1]/MPReg:Rectangle"
while ( getToken(input,token,pNS) ) tokens.push_back(token);
size_t l = tokens.size()-1; // leave leaf name to push()
name = tokens.at(l).n ;
// The second token. For example: XMP.dc is a namespace
if ( pNS && tokens.size() > 1 ) pNS->insert(tokens[1].n);
return recursivelyBuildTree(root,tokens,l-1);
std::set<std::string>* pNS = nullptr) {
// Parse the key
Tokens tokens;
Token token;
std::string input = Key; // Example: "XMP.xmp.MP.RegionInfo/MPRI:Regions[1]/MPReg:Rectangle"
while (getToken(input, token, pNS))
tokens.push_back(token);
size_t l = tokens.size() - 1; // leave leaf name to push()
name = tokens.at(l).n;
// The second token. For example: XMP.dc is a namespace
if (pNS && tokens.size() > 1)
pNS->insert(tokens[1].n);
return recursivelyBuildTree(root, tokens, l - 1);
#if 0
// recursivelyBuildTree:
@ -110,224 +113,221 @@ Jzon::Node& objectForKey(const std::string& Key, Jzon::Object& root, std::string
#endif
}
bool isObject(std::string& value)
{
return value == std::string("type=\"Struct\"");
bool isObject(std::string& value) {
return value == std::string("type=\"Struct\"");
}
bool isArray(std::string& value)
{
return value == "type=\"Seq\"" || value == "type=\"Bag\"" || value == "type=\"Alt\"";
bool isArray(std::string& value) {
return value == "type=\"Seq\"" || value == "type=\"Bag\"" || value == "type=\"Alt\"";
}
#define STORE(node,key,value) \
if (node.IsObject()) node.AsObject().Add(key,value);\
else node.AsArray() .Add( value)
#define STORE(node, key, value) \
if (node.IsObject()) \
node.AsObject().Add(key, value); \
else \
node.AsArray().Add(value)
template <class T>
void push(Jzon::Node& node,const std::string& key,T i)
{
#define ABORT_IF_I_EMPTY \
if (i->value().size() == 0) { \
return; \
}
std::string value = i->value().toString();
switch ( i->typeId() ) {
case Exiv2::xmpText:
if ( ::isObject(value) ) {
Jzon::Object v;
STORE(node,key,v);
} else if ( ::isArray(value) ) {
Jzon::Array v;
STORE(node,key,v);
} else {
STORE(node,key,value);
}
break;
case Exiv2::unsignedByte:
case Exiv2::unsignedShort:
case Exiv2::unsignedLong:
case Exiv2::signedByte:
case Exiv2::signedShort:
case Exiv2::signedLong:
STORE(node,key,std::atoi(value.c_str()) );
break;
case Exiv2::tiffFloat:
case Exiv2::tiffDouble:
STORE(node,key,std::atof(value.c_str()) );
break;
case Exiv2::unsignedRational:
case Exiv2::signedRational: {
ABORT_IF_I_EMPTY
Jzon::Array arr;
Exiv2::Rational rat = i->value().toRational();
arr.Add(rat.first );
arr.Add(rat.second);
STORE(node,key,arr);
} break;
case Exiv2::langAlt: {
ABORT_IF_I_EMPTY
Jzon::Object l ;
const auto& langs = dynamic_cast<const Exiv2::LangAltValue&>(i->value());
for (auto&& lang : langs.value_) {
l.Add(lang.first, lang.second);
}
Jzon::Object o ;
o.Add("lang",l);
STORE(node,key,o);
}
break;
default:
case Exiv2::date:
case Exiv2::time:
case Exiv2::asciiString :
case Exiv2::string:
case Exiv2::comment:
case Exiv2::undefined:
case Exiv2::tiffIfd:
case Exiv2::directory:
case Exiv2::xmpAlt:
case Exiv2::xmpBag:
case Exiv2::xmpSeq:
// http://dev.exiv2.org/boards/3/topics/1367#message-1373
if ( key == "UserComment" ) {
size_t pos = value.find('\0') ;
if ( pos != std::string::npos )
value = value.substr(0,pos);
}
if ( key == "MakerNote") return;
STORE(node,key,value);
break;
}
void push(Jzon::Node& node, const std::string& key, T i) {
#define ABORT_IF_I_EMPTY \
if (i->value().size() == 0) { \
return; \
}
std::string value = i->value().toString();
switch (i->typeId()) {
case Exiv2::xmpText:
if (::isObject(value)) {
Jzon::Object v;
STORE(node, key, v);
} else if (::isArray(value)) {
Jzon::Array v;
STORE(node, key, v);
} else {
STORE(node, key, value);
}
break;
case Exiv2::unsignedByte:
case Exiv2::unsignedShort:
case Exiv2::unsignedLong:
case Exiv2::signedByte:
case Exiv2::signedShort:
case Exiv2::signedLong:
STORE(node, key, std::atoi(value.c_str()));
break;
case Exiv2::tiffFloat:
case Exiv2::tiffDouble:
STORE(node, key, std::atof(value.c_str()));
break;
case Exiv2::unsignedRational:
case Exiv2::signedRational: {
ABORT_IF_I_EMPTY
Jzon::Array arr;
Exiv2::Rational rat = i->value().toRational();
arr.Add(rat.first);
arr.Add(rat.second);
STORE(node, key, arr);
} break;
case Exiv2::langAlt: {
ABORT_IF_I_EMPTY
Jzon::Object l;
const auto& langs = dynamic_cast<const Exiv2::LangAltValue&>(i->value());
for (auto&& lang : langs.value_) {
l.Add(lang.first, lang.second);
}
Jzon::Object o;
o.Add("lang", l);
STORE(node, key, o);
} break;
default:
case Exiv2::date:
case Exiv2::time:
case Exiv2::asciiString:
case Exiv2::string:
case Exiv2::comment:
case Exiv2::undefined:
case Exiv2::tiffIfd:
case Exiv2::directory:
case Exiv2::xmpAlt:
case Exiv2::xmpBag:
case Exiv2::xmpSeq:
// http://dev.exiv2.org/boards/3/topics/1367#message-1373
if (key == "UserComment") {
size_t pos = value.find('\0');
if (pos != std::string::npos)
value = value.substr(0, pos);
}
if (key == "MakerNote")
return;
STORE(node, key, value);
break;
}
}
void fileSystemPush(const char* path,Jzon::Node& nfs)
{
auto& fs = dynamic_cast<Jzon::Object&>(nfs);
fs.Add("path",path);
fs.Add("realpath", std::filesystem::absolute(std::filesystem::path(path)).string());
struct stat buf;
memset(&buf,0,sizeof(buf));
stat(path,&buf);
fs.Add("st_dev", static_cast<int>(buf.st_dev)); /* ID of device containing file */
fs.Add("st_ino", static_cast<int>(buf.st_ino)); /* inode number */
fs.Add("st_mode", static_cast<int>(buf.st_mode)); /* protection */
fs.Add("st_nlink", static_cast<int>(buf.st_nlink)); /* number of hard links */
fs.Add("st_uid", static_cast<int>(buf.st_uid)); /* user ID of owner */
fs.Add("st_gid", static_cast<int>(buf.st_gid)); /* group ID of owner */
fs.Add("st_rdev", static_cast<int>(buf.st_rdev)); /* device ID (if special file) */
fs.Add("st_size", static_cast<int>(buf.st_size)); /* total size, in bytes */
fs.Add("st_atime", static_cast<int>(buf.st_atime)); /* time of last access */
fs.Add("st_mtime", static_cast<int>(buf.st_mtime)); /* time of last modification */
fs.Add("st_ctime", static_cast<int>(buf.st_ctime)); /* time of last status change */
void fileSystemPush(const char* path, Jzon::Node& nfs) {
auto& fs = dynamic_cast<Jzon::Object&>(nfs);
fs.Add("path", path);
fs.Add("realpath", std::filesystem::absolute(std::filesystem::path(path)).string());
struct stat buf;
memset(&buf, 0, sizeof(buf));
stat(path, &buf);
fs.Add("st_dev", static_cast<int>(buf.st_dev)); /* ID of device containing file */
fs.Add("st_ino", static_cast<int>(buf.st_ino)); /* inode number */
fs.Add("st_mode", static_cast<int>(buf.st_mode)); /* protection */
fs.Add("st_nlink", static_cast<int>(buf.st_nlink)); /* number of hard links */
fs.Add("st_uid", static_cast<int>(buf.st_uid)); /* user ID of owner */
fs.Add("st_gid", static_cast<int>(buf.st_gid)); /* group ID of owner */
fs.Add("st_rdev", static_cast<int>(buf.st_rdev)); /* device ID (if special file) */
fs.Add("st_size", static_cast<int>(buf.st_size)); /* total size, in bytes */
fs.Add("st_atime", static_cast<int>(buf.st_atime)); /* time of last access */
fs.Add("st_mtime", static_cast<int>(buf.st_mtime)); /* time of last modification */
fs.Add("st_ctime", static_cast<int>(buf.st_ctime)); /* time of last status change */
#if defined(_MSC_VER) || defined(__MINGW__)
size_t blksize = 1024;
size_t blocks = (buf.st_size+blksize-1)/blksize;
size_t blksize = 1024;
size_t blocks = (buf.st_size + blksize - 1) / blksize;
#else
size_t blksize = buf.st_blksize;
size_t blocks = buf.st_blocks ;
size_t blksize = buf.st_blksize;
size_t blocks = buf.st_blocks;
#endif
fs.Add("st_blksize", static_cast<int>(blksize)); /* blocksize for file system I/O */
fs.Add("st_blocks", static_cast<int>(blocks)); /* number of 512B blocks allocated */
fs.Add("st_blksize", static_cast<int>(blksize)); /* blocksize for file system I/O */
fs.Add("st_blocks", static_cast<int>(blocks)); /* number of 512B blocks allocated */
}
int main(int argc, char* const argv[])
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
try {
if (argc < 2 || argc > 3) {
std::cout << "Usage: " << argv[0] << " [-option] file" << std::endl;
std::cout << "Option: all | exif | iptc | xmp | filesystem" << std::endl;
return 1;
}
const char* path = argv[argc-1];
const char* opt = argc == 3 ? argv[1] : "-all" ;
while (opt[0] == '-') opt++ ; // skip past leading -'s
char option = opt[0];
Exiv2::Image::UniquePtr image = Exiv2::ImageFactory::open(path);
assert(image.get() != 0);
image->readMetadata();
Jzon::Object root;
if ( option == 'f' ) { // only report filesystem when requested
const char* Fs="FS";
Jzon::Object fs ;
root.Add(Fs,fs) ;
fileSystemPush(path,root.Get(Fs));
}
try {
if (argc < 2 || argc > 3) {
std::cout << "Usage: " << argv[0] << " [-option] file" << std::endl;
std::cout << "Option: all | exif | iptc | xmp | filesystem" << std::endl;
return 1;
}
const char* path = argv[argc - 1];
const char* opt = argc == 3 ? argv[1] : "-all";
while (opt[0] == '-')
opt++; // skip past leading -'s
char option = opt[0];
Exiv2::Image::UniquePtr image = Exiv2::ImageFactory::open(path);
assert(image.get() != 0);
image->readMetadata();
Jzon::Object root;
if (option == 'f') { // only report filesystem when requested
const char* Fs = "FS";
Jzon::Object fs;
root.Add(Fs, fs);
fileSystemPush(path, root.Get(Fs));
}
if ( option == 'a' || option == 'e' ) {
Exiv2::ExifData &exifData = image->exifData();
for ( auto i = exifData.begin(); i != exifData.end() ; ++i ) {
std::string name ;
Jzon::Node& object = objectForKey(i->key(),root,name);
push(object,name,i);
}
}
if (option == 'a' || option == 'e') {
Exiv2::ExifData& exifData = image->exifData();
for (auto i = exifData.begin(); i != exifData.end(); ++i) {
std::string name;
Jzon::Node& object = objectForKey(i->key(), root, name);
push(object, name, i);
}
}
if (option == 'a' || option == 'i') {
Exiv2::IptcData& iptcData = image->iptcData();
for (auto i = iptcData.begin(); i != iptcData.end(); ++i) {
std::string name;
Jzon::Node& object = objectForKey(i->key(), root, name);
push(object, name, i);
}
}
if ( option == 'a' || option == 'i' ) {
Exiv2::IptcData &iptcData = image->iptcData();
for (auto i = iptcData.begin(); i != iptcData.end(); ++i) {
std::string name ;
Jzon::Node& object = objectForKey(i->key(),root,name);
push(object,name,i);
}
#ifdef EXV_HAVE_XMP_TOOLKIT
if (option == 'a' || option == 'x') {
Exiv2::XmpData& xmpData = image->xmpData();
if (!xmpData.empty()) {
// get the xmpData and recursively parse into a Jzon Object
std::set<std::string> namespaces;
for (auto i = xmpData.begin(); i != xmpData.end(); ++i) {
std::string name;
Jzon::Node& object = objectForKey(i->key(), root, name, &namespaces);
push(object, name, i);
}
#ifdef EXV_HAVE_XMP_TOOLKIT
if ( option == 'a' || option == 'x' ) {
Exiv2::XmpData &xmpData = image->xmpData();
if ( !xmpData.empty() ) {
// get the xmpData and recursively parse into a Jzon Object
std::set<std::string> namespaces;
for (auto i = xmpData.begin(); i != xmpData.end(); ++i) {
std::string name ;
Jzon::Node& object = objectForKey(i->key(),root,name,&namespaces);
push(object,name,i);
}
// get the namespace dictionary from XMP
Exiv2::Dictionary nsDict;
Exiv2::XmpProperties::registeredNamespaces(nsDict);
// create and populate a Jzon::Object for the namespaces
Jzon::Object xmlns;
for (auto&& ns : namespaces) {
xmlns.Add(ns, nsDict[ns]);
}
// add xmlns as Xmp.xmlns
root.Get("Xmp").AsObject().Add("xmlns",xmlns);
}
// get the namespace dictionary from XMP
Exiv2::Dictionary nsDict;
Exiv2::XmpProperties::registeredNamespaces(nsDict);
// create and populate a Jzon::Object for the namespaces
Jzon::Object xmlns;
for (auto&& ns : namespaces) {
xmlns.Add(ns, nsDict[ns]);
}
#endif
Jzon::Writer writer(root, Jzon::StandardFormat);
writer.Write();
std::cout << writer.GetResult() << std::endl;
return EXIT_SUCCESS;
// add xmlns as Xmp.xmlns
root.Get("Xmp").AsObject().Add("xmlns", xmlns);
}
}
#endif
catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e.what() << "'\n";
return EXIT_FAILURE;
}
Jzon::Writer writer(root, Jzon::StandardFormat);
writer.Write();
std::cout << writer.GetResult() << std::endl;
return EXIT_SUCCESS;
}
catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e.what() << "'\n";
return EXIT_FAILURE;
}
}

File diff suppressed because it is too large Load Diff

@ -31,105 +31,88 @@
#endif
#include <iostream>
#define Safe(x) (x?x:"unknown")
#define Safe(x) (x ? x : "unknown")
const char* optstring = ":hVvqfbuktTFa:Y:O:D:r:p:P:d:e:i:c:m:M:l:S:g:K:n:Q:";
// *****************************************************************************
// class Params
class Params : public Util::Getopt {
public:
/*!
@brief Call Getopt::getopt() with optstring, to initiate command line
argument parsing, perform consistency checks after all command line
arguments are parsed.
@param argc Argument count as passed to main() on program invocation.
@param argv Argument array as passed to main() on program invocation.
@return 0 if successful, >0 in case of errors.
*/
int getopt(int argc, char** const argv) {
int rc = Util::Getopt::getopt(argc, argv, ::optstring);
std::cout << "Params::getopt()"
<< " rc = " << rc << std::endl;
return rc;
}
//! Handle options and their arguments.
int option(int opt, const std::string& optarg, int optopt) override {
std::cout << "Params::option()"
<< " opt = " << opt << " optarg = " << optarg << " optopt = " << optopt << std::endl;
return 0;
}
public:
/*!
@brief Call Getopt::getopt() with optstring, to initiate command line
argument parsing, perform consistency checks after all command line
arguments are parsed.
@param argc Argument count as passed to main() on program invocation.
@param argv Argument array as passed to main() on program invocation.
@return 0 if successful, >0 in case of errors.
*/
int getopt(int argc, char** const argv)
{
int rc = Util::Getopt::getopt(argc, argv, ::optstring);
std::cout << "Params::getopt()"
<< " rc = " << rc
<< std::endl;
return rc ;
}
//! Handle options and their arguments.
int option(int opt, const std::string& optarg, int optopt) override
{
std::cout << "Params::option()"
<< " opt = " << opt
<< " optarg = " << optarg
<< " optopt = " << optopt
<< std::endl;
return 0;
}
//! Handle non-option parameters.
int nonoption(const std::string& argv) override
{
std::cout << "Params::nonoption()"
<< " " << argv
<< std::endl;
return 0 ;
}
}; // class Params
//! Handle non-option parameters.
int nonoption(const std::string& argv) override {
std::cout << "Params::nonoption()"
<< " " << argv << std::endl;
return 0;
}
}; // class Params
int main(int argc, char** const argv)
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char** const argv) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
int n;
int n;
#ifdef EXV_HAVE_UNISTD_H
std::cout << "standard getopt()" << std::endl;
do {
n = ::getopt(argc,argv,::optstring);
if ( n >= 0 ) {
auto N = static_cast<char>(n);
std::cout << n << " = " << N;
} else {
std::cout << n ;
}
std::cout << " optind = " << ::optind
<< " opterr = " << ::opterr
<< " optopt = " << ::optopt
<< " optarg = " << Safe(::optarg)
<< std::endl;
} while ( n >= 0 );
std::cout << std::endl;
std::cout << "standard getopt()" << std::endl;
do {
n = ::getopt(argc, argv, ::optstring);
if (n >= 0) {
auto N = static_cast<char>(n);
std::cout << n << " = " << N;
} else {
std::cout << n;
}
std::cout << " optind = " << ::optind << " opterr = " << ::opterr << " optopt = " << ::optopt
<< " optarg = " << Safe(::optarg) << std::endl;
} while (n >= 0);
std::cout << std::endl;
#endif
std::cout << "homemade getopt()" << std::endl;
do {
n = Util::getopt(argc,argv,::optstring);
if ( n >= 0 ) {
auto N = static_cast<char>(n);
std::cout << n << " = " << N;
} else {
std::cout << n ;
}
std::cout << " optind = " << Util::optind
<< " opterr = " << Util::opterr
<< " optopt = " << Util::optopt
<< " optarg = " << Safe(Util::optarg)
<< std::endl;
} while ( n >= 0 );
std::cout << std::endl;
// Handle command line arguments
Params params;
params.getopt(argc, argv);
std::cout << "homemade getopt()" << std::endl;
do {
n = Util::getopt(argc, argv, ::optstring);
if (n >= 0) {
auto N = static_cast<char>(n);
std::cout << n << " = " << N;
} else {
std::cout << n;
}
std::cout << " optind = " << Util::optind << " opterr = " << Util::opterr << " optopt = " << Util::optopt
<< " optarg = " << Safe(Util::optarg) << std::endl;
return 0;
}
} while (n >= 0);
std::cout << std::endl;
// Handle command line arguments
Params params;
params.getopt(argc, argv);
return 0;
}

@ -12,34 +12,30 @@ Config loaded from : 'initest.ini' version=6, name=Bob Smith, email=bob@smith.co
#include <exiv2/exiv2.hpp>
#include <iostream>
int main()
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main() {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
int result = 0 ;
const char* ini = "ini-test.ini";
Exiv2::INIReader reader(ini);
int result = 0;
const char* ini = "ini-test.ini";
Exiv2::INIReader reader(ini);
if (reader.ParseError() < 0) {
std::cerr << "Can't load '" << ini << "'" << std::endl ;
result = 1;
} else {
std::cout << "Config loaded from : '" << ini << "' "
<< "version=" << reader.GetInteger("protocol", "version", -1)
<< ", name=" << reader.Get("user", "name", "UNKNOWN")
<< ", email=" << reader.Get("user", "email", "UNKNOWN")
<< ", pi=" << reader.GetReal("user", "pi", -1)
<< ", active=" << reader.GetBoolean("user", "active", true)
<< std::endl ;
if (reader.ParseError() < 0) {
std::cerr << "Can't load '" << ini << "'" << std::endl;
result = 1;
} else {
std::cout << "Config loaded from : '" << ini << "' "
<< "version=" << reader.GetInteger("protocol", "version", -1)
<< ", name=" << reader.Get("user", "name", "UNKNOWN")
<< ", email=" << reader.Get("user", "email", "UNKNOWN") << ", pi=" << reader.GetReal("user", "pi", -1)
<< ", active=" << reader.GetBoolean("user", "active", true) << std::endl;
std::cout << "169=" << reader.Get("canon", "169","UNDEFINED")
<< ", 170=" << reader.Get("canon", "170","UNDEFINED")
<< std::endl ;
}
std::cout << "169=" << reader.Get("canon", "169", "UNDEFINED")
<< ", 170=" << reader.Get("canon", "170", "UNDEFINED") << std::endl;
}
return result ;
return result;
}

@ -3,239 +3,235 @@
#include <iostream>
using Exiv2::byte;
using Exiv2::BasicIo;
using Exiv2::MemIo;
using Exiv2::byte;
using Exiv2::Error;
using Exiv2::FileIo;
using Exiv2::IoCloser;
using Exiv2::Error;
using Exiv2::MemIo;
using Exiv2::strError;
int WriteReadSeek(BasicIo &io);
int WriteReadSeek(BasicIo& io);
// *****************************************************************************
// Main
int main(int argc, char* const argv[])
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
try {
if (argc < 4 || argc > 6 ) {
std::cout << "Usage: " << argv[0] << " filein fileout1 fileout2 [remote [blocksize]]\n"
"copy filein to fileout1 and copy filein to fileout2\n"
"fileout1 and fileout2 are overwritten and should match filein exactly\n"
"\n"
"You may optionally provide the URL of a remote file to be copied to filein\n"
"If you use `remote`, you may optionally provide a blocksize for the copy buffer (default 10k)\n"
;
return 1;
}
const char* f0 = argv[1]; // fileIn
const char* f1 = argv[2]; // fileOut1
const char* f2 = argv[3]; // fileOut2
const char* fr = argv[4]; // remote file
const char* ba = argv[5]; // block argument
if ( argc >= 5 ) {
int blocksize = argc==6 ? atoi(ba) : 10000;
// ensure blocksize is sane
if (blocksize>1024*1024)
blocksize=10000;
std::vector<Exiv2::byte> bytes (blocksize);
// copy fileIn from a remote location.
auto io = Exiv2::ImageFactory::createIo(fr);
if ( io->open() != 0 ) {
Error(Exiv2::ErrorCode::kerFileOpenFailed, io->path(), "rb", strError());
}
FileIo output(f0);
if ( !output.open("wb") ) {
Error(Exiv2::ErrorCode::kerFileOpenFailed, output.path() , "w+b", strError());
}
size_t l = 0;
if ( !bytes.empty() ) {
size_t r ;
while ( (r=io->read(bytes.data(),blocksize)) > 0 ) {
l += r;
output.write(bytes.data(),r) ;
}
} else {
// read/write byte-wise (#1029)
while ( l++ < io->size() ) {
output.putb(io->getb()) ;
}
}
output.close();
}
FileIo fileIn(f0);
if (fileIn.open() != 0) {
throw Error(Exiv2::ErrorCode::kerDataSourceOpenFailed, fileIn.path(), strError());
}
FileIo fileOut1(f1);
if (fileOut1.open("w+b") != 0) {
throw Error(Exiv2::ErrorCode::kerFileOpenFailed, f1, "w+b", strError());
}
MemIo memIo1;
// Copy to output file through memIo
memIo1.write(fileIn);
memIo1.seek(0, BasicIo::beg);
fileOut1.write(memIo1);
// Make sure they are all the same size
if(fileIn.size() != memIo1.size() || memIo1.size() != fileOut1.size()) {
std::cerr << argv[0] <<
": Sizes do not match\n";
return 1;
}
// Read writereadseek test on MemIo
MemIo memIo2;
int rc = WriteReadSeek(memIo2);
if (rc != 0) return rc;
// Read writereadseek test on FileIo
// Create or overwrite the file, then close it
FileIo fileTest("iotest.txt");
if (fileTest.open("w+b") != 0) {
throw Error(Exiv2::ErrorCode::kerFileOpenFailed, "iotest.txt", "w+b", strError());
}
fileTest.close();
rc = WriteReadSeek(fileTest);
if (rc != 0) return rc;
// Another test of reading and writing
fileOut1.seek(0, BasicIo::beg);
memIo2.seek(0, BasicIo::beg);
FileIo fileOut2(f2);
if (fileOut2.open("w+b") != 0) {
throw Error(Exiv2::ErrorCode::kerFileOpenFailed, f2, "w+b", strError());
try {
if (argc < 4 || argc > 6) {
std::cout << "Usage: " << argv[0]
<< " filein fileout1 fileout2 [remote [blocksize]]\n"
"copy filein to fileout1 and copy filein to fileout2\n"
"fileout1 and fileout2 are overwritten and should match filein exactly\n"
"\n"
"You may optionally provide the URL of a remote file to be copied to filein\n"
"If you use `remote`, you may optionally provide a blocksize for the copy buffer (default 10k)\n";
return 1;
}
const char* f0 = argv[1]; // fileIn
const char* f1 = argv[2]; // fileOut1
const char* f2 = argv[3]; // fileOut2
const char* fr = argv[4]; // remote file
const char* ba = argv[5]; // block argument
if (argc >= 5) {
int blocksize = argc == 6 ? atoi(ba) : 10000;
// ensure blocksize is sane
if (blocksize > 1024 * 1024)
blocksize = 10000;
std::vector<Exiv2::byte> bytes(blocksize);
// copy fileIn from a remote location.
auto io = Exiv2::ImageFactory::createIo(fr);
if (io->open() != 0) {
Error(Exiv2::ErrorCode::kerFileOpenFailed, io->path(), "rb", strError());
}
FileIo output(f0);
if (!output.open("wb")) {
Error(Exiv2::ErrorCode::kerFileOpenFailed, output.path(), "w+b", strError());
}
size_t l = 0;
if (!bytes.empty()) {
size_t r;
while ((r = io->read(bytes.data(), blocksize)) > 0) {
l += r;
output.write(bytes.data(), r);
}
size_t readCount = 0;
byte buf[32];
while ((readCount=fileOut1.read(buf, sizeof(buf)))) {
if (memIo2.write(buf, readCount) != readCount) {
std::cerr << argv[0] <<
": MemIo bad write 2\n";
return 13;
}
if (fileOut2.write(buf, readCount) != readCount) {
std::cerr << argv[0] <<
": FileIo bad write 2\n";
return 14;
}
} else {
// read/write byte-wise (#1029)
while (l++ < io->size()) {
output.putb(io->getb());
}
return 0;
} catch (Exiv2::Error& e) {
std::cerr << "Caught Exiv2 exception '" << e << "'\n";
return 20;
}
}
int WriteReadSeek(BasicIo &io)
{
byte buf[4096];
const char tester1[] = "this is a little test of MemIo";
const char tester2[] = "Appending this on the end";
const char expect[] = "this is a little teAppending this on the end";
const size_t insert = 19;
const size_t size1 = std::strlen(tester1) + 1;
const size_t size2 = std::strlen(tester2) + 1;
if (io.open() != 0) {
throw Error(Exiv2::ErrorCode::kerDataSourceOpenFailed, io.path(), strError());
}
IoCloser closer(io);
if (io.write(reinterpret_cast<const byte*>(tester1), size1) != size1) {
std::cerr << ": WRS initial write failed\n";
return 2;
}
if (io.size() != size1) {
std::cerr << ": WRS size is not " << size1 << "\n";
return 2;
}
output.close();
}
auto backup = static_cast<long>(size1);
io.seek(-backup, BasicIo::cur);
int c = EOF;
std::memset(buf, -1, sizeof(buf));
for (int i = 0; (c=io.getb()) != EOF; ++i) {
buf[i] = static_cast<byte>(c);
FileIo fileIn(f0);
if (fileIn.open() != 0) {
throw Error(Exiv2::ErrorCode::kerDataSourceOpenFailed, fileIn.path(), strError());
}
// Make sure we got the null back
if(buf[size1-1] != 0) {
std::cerr << ": WRS missing null terminator 1\n";
return 3;
FileIo fileOut1(f1);
if (fileOut1.open("w+b") != 0) {
throw Error(Exiv2::ErrorCode::kerFileOpenFailed, f1, "w+b", strError());
}
if (strcmp(tester1, reinterpret_cast<char*>(buf)) != 0) {
std::cerr << ": WRS strings don't match 1\n";
return 4;
}
MemIo memIo1;
io.seek(-2, BasicIo::end);
if (io.getb() != 'o') {
std::cerr << ": WRS bad getb o\n";
return 5;
}
io.seek(-2, BasicIo::cur);
if (io.getb() != 'I') {
std::cerr << ": WRS bad getb I\n";
return 6;
}
// Copy to output file through memIo
memIo1.write(fileIn);
memIo1.seek(0, BasicIo::beg);
fileOut1.write(memIo1);
if (io.putb('O') != 'O') {
std::cerr << ": WRS bad putb\n";
return 7;
// Make sure they are all the same size
if (fileIn.size() != memIo1.size() || memIo1.size() != fileOut1.size()) {
std::cerr << argv[0] << ": Sizes do not match\n";
return 1;
}
io.seek(-1, BasicIo::cur);
if (io.getb() != 'O') {
std::cerr << ": WRS bad getb O\n";
return 8;
}
// Read writereadseek test on MemIo
MemIo memIo2;
int rc = WriteReadSeek(memIo2);
if (rc != 0)
return rc;
io.seek(insert, BasicIo::beg);
if (io.write(reinterpret_cast<const byte*>(tester2), size2) != size2) {
std::cerr << ": WRS bad write 1\n";
return 9;
// Read writereadseek test on FileIo
// Create or overwrite the file, then close it
FileIo fileTest("iotest.txt");
if (fileTest.open("w+b") != 0) {
throw Error(Exiv2::ErrorCode::kerFileOpenFailed, "iotest.txt", "w+b", strError());
}
// open should seek to beginning
if (io.open() != 0) {
throw Error(Exiv2::ErrorCode::kerDataSourceOpenFailed, io.path(), strError());
}
std::memset(buf, -1, sizeof(buf));
if (io.read(buf, sizeof(buf)) != insert + size2) {
std::cerr << ": WRS something went wrong\n";
return 10;
}
fileTest.close();
rc = WriteReadSeek(fileTest);
if (rc != 0)
return rc;
// Make sure we got the null back
if(buf[insert + size2 - 1] != 0) {
std::cerr << ": WRS missing null terminator 2\n";
return 11;
// Another test of reading and writing
fileOut1.seek(0, BasicIo::beg);
memIo2.seek(0, BasicIo::beg);
FileIo fileOut2(f2);
if (fileOut2.open("w+b") != 0) {
throw Error(Exiv2::ErrorCode::kerFileOpenFailed, f2, "w+b", strError());
}
if (std::strcmp(expect, reinterpret_cast<char*>(buf)) != 0) {
std::cerr << ": WRS strings don't match 2\n";
return 12;
size_t readCount = 0;
byte buf[32];
while ((readCount = fileOut1.read(buf, sizeof(buf)))) {
if (memIo2.write(buf, readCount) != readCount) {
std::cerr << argv[0] << ": MemIo bad write 2\n";
return 13;
}
if (fileOut2.write(buf, readCount) != readCount) {
std::cerr << argv[0] << ": FileIo bad write 2\n";
return 14;
}
}
return 0;
} catch (Exiv2::Error& e) {
std::cerr << "Caught Exiv2 exception '" << e << "'\n";
return 20;
}
}
int WriteReadSeek(BasicIo& io) {
byte buf[4096];
const char tester1[] = "this is a little test of MemIo";
const char tester2[] = "Appending this on the end";
const char expect[] = "this is a little teAppending this on the end";
const size_t insert = 19;
const size_t size1 = std::strlen(tester1) + 1;
const size_t size2 = std::strlen(tester2) + 1;
if (io.open() != 0) {
throw Error(Exiv2::ErrorCode::kerDataSourceOpenFailed, io.path(), strError());
}
IoCloser closer(io);
if (io.write(reinterpret_cast<const byte*>(tester1), size1) != size1) {
std::cerr << ": WRS initial write failed\n";
return 2;
}
if (io.size() != size1) {
std::cerr << ": WRS size is not " << size1 << "\n";
return 2;
}
auto backup = static_cast<long>(size1);
io.seek(-backup, BasicIo::cur);
int c = EOF;
std::memset(buf, -1, sizeof(buf));
for (int i = 0; (c = io.getb()) != EOF; ++i) {
buf[i] = static_cast<byte>(c);
}
// Make sure we got the null back
if (buf[size1 - 1] != 0) {
std::cerr << ": WRS missing null terminator 1\n";
return 3;
}
if (strcmp(tester1, reinterpret_cast<char*>(buf)) != 0) {
std::cerr << ": WRS strings don't match 1\n";
return 4;
}
io.seek(-2, BasicIo::end);
if (io.getb() != 'o') {
std::cerr << ": WRS bad getb o\n";
return 5;
}
io.seek(-2, BasicIo::cur);
if (io.getb() != 'I') {
std::cerr << ": WRS bad getb I\n";
return 6;
}
if (io.putb('O') != 'O') {
std::cerr << ": WRS bad putb\n";
return 7;
}
io.seek(-1, BasicIo::cur);
if (io.getb() != 'O') {
std::cerr << ": WRS bad getb O\n";
return 8;
}
io.seek(insert, BasicIo::beg);
if (io.write(reinterpret_cast<const byte*>(tester2), size2) != size2) {
std::cerr << ": WRS bad write 1\n";
return 9;
}
// open should seek to beginning
if (io.open() != 0) {
throw Error(Exiv2::ErrorCode::kerDataSourceOpenFailed, io.path(), strError());
}
std::memset(buf, -1, sizeof(buf));
if (io.read(buf, sizeof(buf)) != insert + size2) {
std::cerr << ": WRS something went wrong\n";
return 10;
}
// Make sure we got the null back
if (buf[insert + size2 - 1] != 0) {
std::cerr << ": WRS missing null terminator 2\n";
return 11;
}
if (std::strcmp(expect, reinterpret_cast<char*>(buf)) != 0) {
std::cerr << ": WRS strings don't match 2\n";
return 12;
}
return 0;
}

@ -5,46 +5,44 @@
#include <iostream>
int main(int argc, char* const argv[])
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
std::string file(argv[1]);
Exiv2::IptcData iptcData;
iptcData["Iptc.Application2.Headline"] = "The headline I am";
iptcData["Iptc.Application2.Keywords"] = "Yet another keyword";
iptcData["Iptc.Application2.DateCreated"] = "2004-8-3";
iptcData["Iptc.Application2.Urgency"] = uint16_t(1);
iptcData["Iptc.Envelope.ModelVersion"] = 42;
iptcData["Iptc.Envelope.TimeSent"] = "14:41:0-05:00";
iptcData["Iptc.Application2.RasterizedCaption"] = "230 42 34 2 90 84 23 146";
iptcData["Iptc.0x0009.0x0001"] = "Who am I?";
Exiv2::StringValue value;
value.read("very!");
iptcData["Iptc.Application2.Urgency"] = value;
std::cout << "Time sent: " << iptcData["Iptc.Envelope.TimeSent"] << "\n";
// Open image file
auto image = Exiv2::ImageFactory::open(file);
// Set IPTC data and write it to the file
image->setIptcData(iptcData);
image->writeMetadata();
return 0;
}
catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
std::string file(argv[1]);
Exiv2::IptcData iptcData;
iptcData["Iptc.Application2.Headline"] = "The headline I am";
iptcData["Iptc.Application2.Keywords"] = "Yet another keyword";
iptcData["Iptc.Application2.DateCreated"] = "2004-8-3";
iptcData["Iptc.Application2.Urgency"] = uint16_t(1);
iptcData["Iptc.Envelope.ModelVersion"] = 42;
iptcData["Iptc.Envelope.TimeSent"] = "14:41:0-05:00";
iptcData["Iptc.Application2.RasterizedCaption"] = "230 42 34 2 90 84 23 146";
iptcData["Iptc.0x0009.0x0001"] = "Who am I?";
Exiv2::StringValue value;
value.read("very!");
iptcData["Iptc.Application2.Urgency"] = value;
std::cout << "Time sent: " << iptcData["Iptc.Envelope.TimeSent"] << "\n";
// Open image file
auto image = Exiv2::ImageFactory::open(file);
// Set IPTC data and write it to the file
image->setIptcData(iptcData);
image->writeMetadata();
return 0;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}

@ -5,51 +5,41 @@
#include <iostream>
int main(int argc, char* const argv[])
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
auto image = Exiv2::ImageFactory::open(argv[1]);
image->readMetadata();
Exiv2::IptcData &iptcData = image->iptcData();
if (iptcData.empty()) {
std::string error(argv[1]);
error += ": No IPTC data found in the file";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
auto end = iptcData.end();
for (auto md = iptcData.begin(); md != end; ++md) {
std::cout << std::setw(44) << std::setfill(' ') << std::left
<< md->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right
<< std::hex << md->tag() << " "
<< std::setw(9) << std::setfill(' ') << std::left
<< md->typeName() << " "
<< std::dec << std::setw(3)
<< std::setfill(' ') << std::right
<< md->count() << " "
<< std::dec << md->value()
<< std::endl;
}
return 0;
}
catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return 1;
}
catch (const std::exception& e) {
std::cout << "Caught exception: '" << e.what() << "'\n";
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
auto image = Exiv2::ImageFactory::open(argv[1]);
image->readMetadata();
Exiv2::IptcData& iptcData = image->iptcData();
if (iptcData.empty()) {
std::string error(argv[1]);
error += ": No IPTC data found in the file";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
auto end = iptcData.end();
for (auto md = iptcData.begin(); md != end; ++md) {
std::cout << std::setw(44) << std::setfill(' ') << std::left << md->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << md->tag() << " " << std::setw(9)
<< std::setfill(' ') << std::left << md->typeName() << " " << std::dec << std::setw(3)
<< std::setfill(' ') << std::right << md->count() << " " << std::dec << md->value() << std::endl;
}
return 0;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return 1;
} catch (const std::exception& e) {
std::cout << "Caught exception: '" << e.what() << "'\n";
return 1;
}

@ -6,162 +6,150 @@
using namespace Exiv2;
bool processLine(const std::string& line, int num, IptcData &iptcData);
void processAdd(const std::string& line, int num, IptcData &iptcData);
void processRemove(const std::string& line, int num, IptcData &iptcData);
void processModify(const std::string& line, int num, IptcData &iptcData);
bool processLine(const std::string& line, int num, IptcData& iptcData);
void processAdd(const std::string& line, int num, IptcData& iptcData);
void processRemove(const std::string& line, int num, IptcData& iptcData);
void processModify(const std::string& line, int num, IptcData& iptcData);
// *****************************************************************************
// Main
int main(int argc, char* const argv[])
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
try {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " image\n";
std::cout << "Commands read from stdin.\n";
return 1;
}
try {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " image\n";
std::cout << "Commands read from stdin.\n";
return 1;
}
auto image = ImageFactory::open(argv[1]);
image->readMetadata();
auto image = ImageFactory::open(argv[1]);
image->readMetadata();
// Process commands
std::string line;
int num = 0;
std::getline(std::cin, line);
while (line.length() && processLine(line, ++num, image->iptcData())) {
std::getline(std::cin, line);
}
// Process commands
std::string line;
int num = 0;
std::getline(std::cin, line);
while (line.length() && processLine(line, ++num, image->iptcData())) {
std::getline(std::cin, line);
}
// Save any changes
image->writeMetadata();
// Save any changes
image->writeMetadata();
return 0;
}
catch (Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
return 0;
} catch (Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
}
bool processLine(const std::string& line, int num, IptcData &iptcData)
{
switch (line.at(0)) {
case 'a':
case 'A':
processAdd(line, num, iptcData);
break;
case 'r':
case 'R':
processRemove(line, num, iptcData);
break;
case 'm':
case 'M':
processModify(line, num, iptcData);
break;
case 'q':
case 'Q':
return false;
default:
std::ostringstream os;
os << "Unknown command (" << line.at(0) << ") at line " << num;
throw Error(ErrorCode::kerErrorMessage, os.str());
}
return true;
bool processLine(const std::string& line, int num, IptcData& iptcData) {
switch (line.at(0)) {
case 'a':
case 'A':
processAdd(line, num, iptcData);
break;
case 'r':
case 'R':
processRemove(line, num, iptcData);
break;
case 'm':
case 'M':
processModify(line, num, iptcData);
break;
case 'q':
case 'Q':
return false;
default:
std::ostringstream os;
os << "Unknown command (" << line.at(0) << ") at line " << num;
throw Error(ErrorCode::kerErrorMessage, os.str());
}
return true;
}
void processAdd(const std::string& line, int num, IptcData &iptcData)
{
std::string::size_type keyStart = line.find_first_not_of(" \t", 1);
std::string::size_type keyEnd = line.find_first_of(" \t", keyStart+1);
std::string::size_type dataStart = line.find_first_not_of(" \t", keyEnd+1);
if (keyStart == std::string::npos ||
keyEnd == std::string::npos ||
dataStart == std::string::npos) {
std::ostringstream os;
os << "Invalid \'a\' command at line " << num;
throw Error(ErrorCode::kerErrorMessage, os.str());
}
std::string key(line.substr(keyStart, keyEnd-keyStart));
IptcKey iptcKey(key);
std::string data(line.substr(dataStart));
// if data starts and ends with quotes, remove them
if (data.at(0) == '\"' && data.at(data.size()-1) == '\"') {
data = data.substr(1, data.size()-2);
}
TypeId type = IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record());
Value::UniquePtr value = Value::create(type);
value->read(data);
int rc = iptcData.add(iptcKey, value.get());
if (rc) {
throw Error(ErrorCode::kerErrorMessage, "Iptc dataset already exists and is not repeatable");
}
void processAdd(const std::string& line, int num, IptcData& iptcData) {
std::string::size_type keyStart = line.find_first_not_of(" \t", 1);
std::string::size_type keyEnd = line.find_first_of(" \t", keyStart + 1);
std::string::size_type dataStart = line.find_first_not_of(" \t", keyEnd + 1);
if (keyStart == std::string::npos || keyEnd == std::string::npos || dataStart == std::string::npos) {
std::ostringstream os;
os << "Invalid \'a\' command at line " << num;
throw Error(ErrorCode::kerErrorMessage, os.str());
}
std::string key(line.substr(keyStart, keyEnd - keyStart));
IptcKey iptcKey(key);
std::string data(line.substr(dataStart));
// if data starts and ends with quotes, remove them
if (data.at(0) == '\"' && data.at(data.size() - 1) == '\"') {
data = data.substr(1, data.size() - 2);
}
TypeId type = IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record());
Value::UniquePtr value = Value::create(type);
value->read(data);
int rc = iptcData.add(iptcKey, value.get());
if (rc) {
throw Error(ErrorCode::kerErrorMessage, "Iptc dataset already exists and is not repeatable");
}
}
void processRemove(const std::string& line, int num, IptcData &iptcData)
{
std::string::size_type keyStart = line.find_first_not_of(" \t", 1);
void processRemove(const std::string& line, int num, IptcData& iptcData) {
std::string::size_type keyStart = line.find_first_not_of(" \t", 1);
if (keyStart == std::string::npos) {
std::ostringstream os;
os << "Invalid \'r\' command at line " << num;
throw Error(ErrorCode::kerErrorMessage, os.str());
}
if (keyStart == std::string::npos) {
std::ostringstream os;
os << "Invalid \'r\' command at line " << num;
throw Error(ErrorCode::kerErrorMessage, os.str());
}
const std::string key( line.substr(keyStart) );
IptcKey iptcKey(key);
const std::string key(line.substr(keyStart));
IptcKey iptcKey(key);
auto iter = iptcData.findKey(iptcKey);
if (iter != iptcData.end()) {
iptcData.erase(iter);
}
auto iter = iptcData.findKey(iptcKey);
if (iter != iptcData.end()) {
iptcData.erase(iter);
}
}
void processModify(const std::string& line, int num, IptcData &iptcData)
{
std::string::size_type keyStart = line.find_first_not_of(" \t", 1);
std::string::size_type keyEnd = line.find_first_of(" \t", keyStart+1);
std::string::size_type dataStart = line.find_first_not_of(" \t", keyEnd+1);
if (keyStart == std::string::npos ||
keyEnd == std::string::npos ||
dataStart == std::string::npos) {
std::ostringstream os;
os << "Invalid \'m\' command at line " << num;
throw Error(ErrorCode::kerErrorMessage, os.str());
}
std::string key(line.substr(keyStart, keyEnd-keyStart));
IptcKey iptcKey(key);
std::string data(line.substr(dataStart));
// if data starts and ends with quotes, remove them
if (data.at(0) == '\"' && data.at(data.size()-1) == '\"') {
data = data.substr(1, data.size()-2);
}
TypeId type = IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record());
Value::UniquePtr value = Value::create(type);
value->read(data);
auto iter = iptcData.findKey(iptcKey);
if (iter != iptcData.end()) {
iter->setValue(value.get());
}
else {
int rc = iptcData.add(iptcKey, value.get());
if (rc) {
throw Error(ErrorCode::kerErrorMessage, "Iptc dataset already exists and is not repeatable");
}
void processModify(const std::string& line, int num, IptcData& iptcData) {
std::string::size_type keyStart = line.find_first_not_of(" \t", 1);
std::string::size_type keyEnd = line.find_first_of(" \t", keyStart + 1);
std::string::size_type dataStart = line.find_first_not_of(" \t", keyEnd + 1);
if (keyStart == std::string::npos || keyEnd == std::string::npos || dataStart == std::string::npos) {
std::ostringstream os;
os << "Invalid \'m\' command at line " << num;
throw Error(ErrorCode::kerErrorMessage, os.str());
}
std::string key(line.substr(keyStart, keyEnd - keyStart));
IptcKey iptcKey(key);
std::string data(line.substr(dataStart));
// if data starts and ends with quotes, remove them
if (data.at(0) == '\"' && data.at(data.size() - 1) == '\"') {
data = data.substr(1, data.size() - 2);
}
TypeId type = IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record());
Value::UniquePtr value = Value::create(type);
value->read(data);
auto iter = iptcData.findKey(iptcKey);
if (iter != iptcData.end()) {
iter->setValue(value.get());
} else {
int rc = iptcData.add(iptcKey, value.get());
if (rc) {
throw Error(ErrorCode::kerErrorMessage, "Iptc dataset already exists and is not repeatable");
}
}
}

@ -6,188 +6,185 @@
using namespace Exiv2;
int main()
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main() {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
int tc = 0;
int rc = 0;
std::string key("Exif.Iop.InteroperabilityVersion");
ExifKey ek(key);
// operator<<
tc += 1;
std::ostringstream os;
os << ek;
if (os.str() != key) {
std::cout << "Testcase failed (operator<<)" << std::endl;
rc += 1;
}
// familyName
tc += 1;
if (std::string(ek.familyName()) != "Exif") {
std::cout << "Testcase failed (familyName)" << std::endl;
rc += 1;
}
// groupName
tc += 1;
if (ek.groupName() != "Iop") {
std::cout << "Testcase failed (groupName)" << std::endl;
rc += 1;
}
// tagName
tc += 1;
if (ek.tagName() != "InteroperabilityVersion") {
std::cout << "Testcase failed (tagName)" << std::endl;
rc += 1;
}
// tagName
tc += 1;
if (ek.tag() != 0x0002) {
std::cout << "Testcase failed (tag)" << std::endl;
rc += 1;
}
// ifdName
tc += 1;
if (std::string(ExifTags::ifdName(ek.groupName())) != "Iop") {
std::cout << "Testcase failed (ifdName: " << std::endl;
rc += 1;
}
// sectionName
tc += 1;
if (strcmp(ExifTags::sectionName(ek), "Interoperability") != 0) {
std::cout << "Testcase failed (sectionName)" << std::endl;
rc += 1;
}
// -----
// Copy constructor
const ExifKey& ek2(ek);
// operator<<
tc += 1;
std::ostringstream os2;
os2 << ek2;
if (os2.str() != key) {
std::cout << "Testcase failed (operator<<)" << std::endl;
rc += 1;
}
// familyName
tc += 1;
if (std::string(ek2.familyName()) != "Exif") {
std::cout << "Testcase failed (familyName)" << std::endl;
rc += 1;
}
// groupName
tc += 1;
if (ek2.groupName() != "Iop") {
std::cout << "Testcase failed (groupName)" << std::endl;
rc += 1;
}
// tagName
tc += 1;
if (ek2.tagName() != "InteroperabilityVersion") {
std::cout << "Testcase failed (tagName)" << std::endl;
rc += 1;
}
// tagName
tc += 1;
if (ek2.tag() != 0x0002) {
std::cout << "Testcase failed (tag)" << std::endl;
rc += 1;
}
// ifdName
tc += 1;
if (std::string(ExifTags::ifdName(ek2.groupName())) != "Iop") {
std::cout << "Testcase failed (ifdName: " << std::endl;
rc += 1;
}
// sectionName
tc += 1;
if (strcmp(ExifTags::sectionName(ek2), "Interoperability") != 0) {
std::cout << "Testcase failed (sectionName)" << std::endl;
rc += 1;
}
// -----
ExifKey ek4("Exif.Image.0x0110");
tc += 1;
if (ek4.key() != "Exif.Image.Model") {
std::cout << "Testcase failed (converted key)" << std::endl;
rc += 1;
}
tc += 1;
if (ek4.tagName() != "Model") {
std::cout << "Testcase failed (converted tagName)" << std::endl;
rc += 1;
}
// -----
ExifKey ek5("Exif.Nikon3.0x0007");
tc += 1;
if (ek5.key() != "Exif.Nikon3.Focus") {
std::cout << "Testcase failed (converted key)" << std::endl;
rc += 1;
}
tc += 1;
if (ek5.tagName() != "Focus") {
std::cout << "Testcase failed (converted tagName)" << std::endl;
rc += 1;
}
// -----
IptcKey ik1("Iptc.Envelope.0x0005");
tc += 1;
if (ik1.key() != "Iptc.Envelope.Destination") {
std::cout << "Testcase failed (converted Iptc key)" << std::endl;
rc += 1;
}
tc += 1;
if (ik1.tagName() != "Destination") {
std::cout << "Testcase failed (converted tagName)" << std::endl;
rc += 1;
}
tc += 1;
if (ik1.recordName() != "Envelope") {
std::cout << "Testcase failed (converted recordName)" << std::endl;
rc += 1;
}
// -----
IptcKey ik2(0xabcd, 0x1234);
tc += 1;
if (ik2.key() != "Iptc.0x1234.0xabcd") {
std::cout << "Testcase failed (unknown Iptc key)" << std::endl;
rc += 1;
}
tc += 1;
if (ik2.tagName() != "0xabcd") {
std::cout << "Testcase failed (converted tagName)" << std::endl;
rc += 1;
}
tc += 1;
if (ik2.recordName() != "0x1234") {
std::cout << "Testcase failed (converted recordName)" << std::endl;
rc += 1;
}
// -----
if (rc == 0) {
std::cout << "All " << tc << " testcases passed." << std::endl;
}
else {
std::cout << rc << " of " << tc << " testcases failed." << std::endl;
}
int tc = 0;
int rc = 0;
std::string key("Exif.Iop.InteroperabilityVersion");
ExifKey ek(key);
// operator<<
tc += 1;
std::ostringstream os;
os << ek;
if (os.str() != key) {
std::cout << "Testcase failed (operator<<)" << std::endl;
rc += 1;
}
// familyName
tc += 1;
if (std::string(ek.familyName()) != "Exif") {
std::cout << "Testcase failed (familyName)" << std::endl;
rc += 1;
}
// groupName
tc += 1;
if (ek.groupName() != "Iop") {
std::cout << "Testcase failed (groupName)" << std::endl;
rc += 1;
}
// tagName
tc += 1;
if (ek.tagName() != "InteroperabilityVersion") {
std::cout << "Testcase failed (tagName)" << std::endl;
rc += 1;
}
// tagName
tc += 1;
if (ek.tag() != 0x0002) {
std::cout << "Testcase failed (tag)" << std::endl;
rc += 1;
}
// ifdName
tc += 1;
if (std::string(ExifTags::ifdName(ek.groupName())) != "Iop") {
std::cout << "Testcase failed (ifdName: " << std::endl;
rc += 1;
}
// sectionName
tc += 1;
if (strcmp(ExifTags::sectionName(ek), "Interoperability") != 0) {
std::cout << "Testcase failed (sectionName)" << std::endl;
rc += 1;
}
// -----
// Copy constructor
const ExifKey& ek2(ek);
// operator<<
tc += 1;
std::ostringstream os2;
os2 << ek2;
if (os2.str() != key) {
std::cout << "Testcase failed (operator<<)" << std::endl;
rc += 1;
}
// familyName
tc += 1;
if (std::string(ek2.familyName()) != "Exif") {
std::cout << "Testcase failed (familyName)" << std::endl;
rc += 1;
}
// groupName
tc += 1;
if (ek2.groupName() != "Iop") {
std::cout << "Testcase failed (groupName)" << std::endl;
rc += 1;
}
// tagName
tc += 1;
if (ek2.tagName() != "InteroperabilityVersion") {
std::cout << "Testcase failed (tagName)" << std::endl;
rc += 1;
}
// tagName
tc += 1;
if (ek2.tag() != 0x0002) {
std::cout << "Testcase failed (tag)" << std::endl;
rc += 1;
}
// ifdName
tc += 1;
if (std::string(ExifTags::ifdName(ek2.groupName())) != "Iop") {
std::cout << "Testcase failed (ifdName: " << std::endl;
rc += 1;
}
// sectionName
tc += 1;
if (strcmp(ExifTags::sectionName(ek2), "Interoperability") != 0) {
std::cout << "Testcase failed (sectionName)" << std::endl;
rc += 1;
}
// -----
ExifKey ek4("Exif.Image.0x0110");
tc += 1;
if (ek4.key() != "Exif.Image.Model") {
std::cout << "Testcase failed (converted key)" << std::endl;
rc += 1;
}
tc += 1;
if (ek4.tagName() != "Model") {
std::cout << "Testcase failed (converted tagName)" << std::endl;
rc += 1;
}
// -----
ExifKey ek5("Exif.Nikon3.0x0007");
tc += 1;
if (ek5.key() != "Exif.Nikon3.Focus") {
std::cout << "Testcase failed (converted key)" << std::endl;
rc += 1;
}
tc += 1;
if (ek5.tagName() != "Focus") {
std::cout << "Testcase failed (converted tagName)" << std::endl;
rc += 1;
}
// -----
IptcKey ik1("Iptc.Envelope.0x0005");
tc += 1;
if (ik1.key() != "Iptc.Envelope.Destination") {
std::cout << "Testcase failed (converted Iptc key)" << std::endl;
rc += 1;
}
tc += 1;
if (ik1.tagName() != "Destination") {
std::cout << "Testcase failed (converted tagName)" << std::endl;
rc += 1;
}
tc += 1;
if (ik1.recordName() != "Envelope") {
std::cout << "Testcase failed (converted recordName)" << std::endl;
rc += 1;
}
// -----
IptcKey ik2(0xabcd, 0x1234);
tc += 1;
if (ik2.key() != "Iptc.0x1234.0xabcd") {
std::cout << "Testcase failed (unknown Iptc key)" << std::endl;
rc += 1;
}
tc += 1;
if (ik2.tagName() != "0xabcd") {
std::cout << "Testcase failed (converted tagName)" << std::endl;
rc += 1;
}
tc += 1;
if (ik2.recordName() != "0x1234") {
std::cout << "Testcase failed (converted recordName)" << std::endl;
rc += 1;
}
// -----
if (rc == 0) {
std::cout << "All " << tc << " testcases passed." << std::endl;
} else {
std::cout << rc << " of " << tc << " testcases failed." << std::endl;
}
}

@ -3,77 +3,76 @@
// Test for large (>65535 bytes) IPTC buffer
// ***************************************************************** -*- C++ -*-
#include <exiv2/exiv2.hpp>
#include <cassert>
#include <exiv2/exiv2.hpp>
#include <iostream>
int main(int argc, char* const argv[])
{
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) {
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
if (argc != 3) {
std::cout << "Usage: " << argv[0] << " image datafile\n";
return 1;
}
std::string file(argv[1]);
std::string data(argv[2]);
if (argc != 3) {
std::cout << "Usage: " << argv[0] << " image datafile\n";
return 1;
}
std::string file(argv[1]);
std::string data(argv[2]);
// Read data file into data buffer
Exiv2::FileIo io(data);
if (io.open() != 0) {
throw Exiv2::Error(Exiv2::ErrorCode::kerDataSourceOpenFailed, io.path(), Exiv2::strError());
}
// Read data file into data buffer
Exiv2::FileIo io(data);
if (io.open() != 0) {
throw Exiv2::Error(Exiv2::ErrorCode::kerDataSourceOpenFailed, io.path(), Exiv2::strError());
}
Exiv2::DataBuf buf(io.size());
std::cout << "Reading " << buf.size() << " bytes from " << data << "\n";
const size_t readBytes = io.read(buf.data(), buf.size());
if (readBytes != buf.size() || io.error() || io.eof()) {
throw Exiv2::Error(Exiv2::ErrorCode::kerFailedToReadImageData);
}
Exiv2::DataBuf buf(io.size());
std::cout << "Reading " << buf.size() << " bytes from " << data << "\n";
const size_t readBytes = io.read(buf.data(), buf.size());
if (readBytes != buf.size() || io.error() || io.eof()) {
throw Exiv2::Error(Exiv2::ErrorCode::kerFailedToReadImageData);
}
// Read metadata from file
auto image = Exiv2::ImageFactory::open(file);
image->readMetadata();
// Read metadata from file
auto image = Exiv2::ImageFactory::open(file);
image->readMetadata();
// Set Preview field to the content of the data file
Exiv2::DataValue value;
value.read(buf.data(), buf.size());
Exiv2::IptcData& iptcData = image->iptcData();
std::cout << "IPTC fields: " << iptcData.size() << "\n";
iptcData["Iptc.Application2.Preview"] = value;
std::cout << "IPTC fields: " << iptcData.size() << "\n";
// Set Preview field to the content of the data file
Exiv2::DataValue value;
value.read(buf.data(), buf.size());
Exiv2::IptcData& iptcData = image->iptcData();
std::cout << "IPTC fields: " << iptcData.size() << "\n";
iptcData["Iptc.Application2.Preview"] = value;
std::cout << "IPTC fields: " << iptcData.size() << "\n";
// Set IRB, compare with IPTC raw data
Exiv2::DataBuf irb = Exiv2::Photoshop::setIptcIrb(nullptr, 0, iptcData);
std::cout << "IRB buffer : " << irb.size() << "\n";
const Exiv2::byte* record;
uint32_t sizeHdr = 0;
uint32_t sizeData = 0;
Exiv2::Photoshop::locateIptcIrb(irb.data(), irb.size(), &record, &sizeHdr, &sizeData);
Exiv2::DataBuf rawIptc = Exiv2::IptcParser::encode(iptcData);
std::cout << "Comparing IPTC and IRB size... ";
if (static_cast<uint32_t>(rawIptc.size()) != sizeData) {
std::cout << "not ";
}
std::cout << "ok\n";
// Set IRB, compare with IPTC raw data
Exiv2::DataBuf irb = Exiv2::Photoshop::setIptcIrb(nullptr, 0, iptcData);
std::cout << "IRB buffer : " << irb.size() << "\n";
const Exiv2::byte* record;
uint32_t sizeHdr = 0;
uint32_t sizeData = 0;
Exiv2::Photoshop::locateIptcIrb(irb.data(), irb.size(), &record, &sizeHdr, &sizeData);
Exiv2::DataBuf rawIptc = Exiv2::IptcParser::encode(iptcData);
std::cout << "Comparing IPTC and IRB size... ";
if (static_cast<uint32_t>(rawIptc.size()) != sizeData) {
std::cout << "not ";
}
std::cout << "ok\n";
std::cout << "Comparing IPTC and IRB data... ";
if (0 != rawIptc.cmpBytes(0, record + sizeHdr, sizeData)) {
std::cout << "not ";
}
std::cout << "ok\n";
std::cout << "Comparing IPTC and IRB data... ";
if (0 != rawIptc.cmpBytes(0, record + sizeHdr, sizeData)) {
std::cout << "not ";
}
std::cout << "ok\n";
// Set Iptc data and write it to the file
image->writeMetadata();
// Set Iptc data and write it to the file
image->writeMetadata();
return 0;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
return 0;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
}

@ -1,17 +1,14 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <exiv2/exiv2.hpp>
#include <iostream>
// include local header files which are not part of libexiv2
#include "getopt.hpp"
#include "metacopy.hpp"
// *****************************************************************************
// Main
int main(int argc, char* const argv[])
{
try {
int main(int argc, char* const argv[]) {
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
@ -21,12 +18,12 @@ try {
// Handle command line arguments
Params params;
if (params.getopt(argc, argv)) {
params.usage();
return 1;
params.usage();
return 1;
}
if (params.help_) {
params.help();
return 2;
params.help();
return 2;
}
// Use MemIo to increase test coverage.
@ -39,130 +36,135 @@ try {
auto writeImg = Exiv2::ImageFactory::open(params.write_);
if (params.preserve_) {
writeImg->readMetadata();
writeImg->readMetadata();
}
if (params.iptc_) {
writeImg->setIptcData(readImg->iptcData());
writeImg->setIptcData(readImg->iptcData());
}
if (params.exif_) {
writeImg->setExifData(readImg->exifData());
writeImg->setExifData(readImg->exifData());
}
if (params.comment_) {
writeImg->setComment(readImg->comment());
writeImg->setComment(readImg->comment());
}
if (params.xmp_) {
writeImg->setXmpData(readImg->xmpData());
writeImg->setXmpData(readImg->xmpData());
}
try {
writeImg->writeMetadata();
}
catch (const Exiv2::Error&) {
std::cerr << params.progname() <<
": Could not write metadata to (" << params.write_ << ")\n";
return 8;
writeImg->writeMetadata();
} catch (const Exiv2::Error&) {
std::cerr << params.progname() << ": Could not write metadata to (" << params.write_ << ")\n";
return 8;
}
return 0;
}
catch (Exiv2::Error& e) {
} catch (Exiv2::Error& e) {
std::cerr << "Caught Exiv2 exception '" << e << "'\n";
return 10;
}
}
}
int Params::option(int opt, const std::string& /*optarg*/, int optopt)
{
int rc = 0;
switch (opt) {
case 'h': {help_ = true; break;}
case 'i': {iptc_ = true; break;}
case 'e': {exif_ = true; break;}
case 'c': {comment_ = true; break;}
case 'x': {xmp_ = true; break;}
case 'p': {preserve_ = true; break;}
case 'a':{
iptc_ =true;
exif_ =true;
comment_ =true;
xmp_ =true;
break;
}
case ':':{
std::cerr << progname() << ": Option -" << static_cast<char>(optopt)
<< " requires an argument\n";
rc = 1;
break;
}
case '?':{
std::cerr << progname() << ": Unrecognized option -"
<< static_cast<char>(optopt) << "\n";
rc = 1;
break;
}
default:{
std::cerr << progname()
<< ": getopt returned unexpected character code "
<< std::hex << opt << "\n";
rc = 1;
break;
}
}
return rc;
int Params::option(int opt, const std::string& /*optarg*/, int optopt) {
int rc = 0;
switch (opt) {
case 'h': {
help_ = true;
break;
}
case 'i': {
iptc_ = true;
break;
}
case 'e': {
exif_ = true;
break;
}
case 'c': {
comment_ = true;
break;
}
case 'x': {
xmp_ = true;
break;
}
case 'p': {
preserve_ = true;
break;
}
case 'a': {
iptc_ = true;
exif_ = true;
comment_ = true;
xmp_ = true;
break;
}
case ':': {
std::cerr << progname() << ": Option -" << static_cast<char>(optopt) << " requires an argument\n";
rc = 1;
break;
}
case '?': {
std::cerr << progname() << ": Unrecognized option -" << static_cast<char>(optopt) << "\n";
rc = 1;
break;
}
default: {
std::cerr << progname() << ": getopt returned unexpected character code " << std::hex << opt << "\n";
rc = 1;
break;
}
}
return rc;
}
int Params::nonoption(const std::string& argv)
{
if (!write_.empty()) {
std::cerr << progname() << ": Unexpected extra argument (" << argv << ")\n";
return 1;
}
if (first_) read_ = argv;
else write_ = argv;
first_ = false;
return 0;
int Params::nonoption(const std::string& argv) {
if (!write_.empty()) {
std::cerr << progname() << ": Unexpected extra argument (" << argv << ")\n";
return 1;
}
if (first_)
read_ = argv;
else
write_ = argv;
first_ = false;
return 0;
}
int Params::getopt(int argc, char* const argv[])
{
int rc = Util::Getopt::getopt(argc, argv, optstring_);
// Further consistency checks
if (!help_) {
if (rc==0 && read_.empty() ) {
std::cerr << progname() << ": Read and write files must be specified\n";
rc = 1;
}
if (rc==0 && write_.empty() ) {
std::cerr << progname() << ": Write file must be specified\n";
rc = 1;
}
if (preserve_ && iptc_ && exif_ && comment_ && xmp_ ) {
std::cerr << progname() << ": Option -p has no effect when all metadata types are specified.\n";
rc = 1;
}
}
return rc;
} // Params::getopt
void Params::usage(std::ostream& os) const
{
os << "\nReads and writes raw metadata. Use -h option for help.\n"
<< "Usage: " << progname()
<< " [-iecxaph] readfile writefile\n";
int Params::getopt(int argc, char* const argv[]) {
int rc = Util::Getopt::getopt(argc, argv, optstring_);
// Further consistency checks
if (!help_) {
if (rc == 0 && read_.empty()) {
std::cerr << progname() << ": Read and write files must be specified\n";
rc = 1;
}
if (rc == 0 && write_.empty()) {
std::cerr << progname() << ": Write file must be specified\n";
rc = 1;
}
if (preserve_ && iptc_ && exif_ && comment_ && xmp_) {
std::cerr << progname() << ": Option -p has no effect when all metadata types are specified.\n";
rc = 1;
}
}
return rc;
} // Params::getopt
void Params::usage(std::ostream& os) const {
os << "\nReads and writes raw metadata. Use -h option for help.\n"
<< "Usage: " << progname() << " [-iecxaph] readfile writefile\n";
}
void Params::help(std::ostream& os) const
{
usage(os);
os << "\nOptions:\n"
<< " -i Read Iptc data from readfile and write to writefile.\n"
<< " -e Read Exif data from readfile and write to writefile.\n"
<< " -c Read Jpeg comment from readfile and write to writefile.\n"
<< " -x Read XMP data from readfile and write to writefile.\n"
<< " -a Read all metadata from readfile and write to writefile.\n"
<< " -p Preserve existing metadata in writefile if not replaced.\n"
<< " -h Display this help and exit.\n\n";
} // Params::help
void Params::help(std::ostream& os) const {
usage(os);
os << "\nOptions:\n"
<< " -i Read Iptc data from readfile and write to writefile.\n"
<< " -e Read Exif data from readfile and write to writefile.\n"
<< " -c Read Jpeg comment from readfile and write to writefile.\n"
<< " -x Read XMP data from readfile and write to writefile.\n"
<< " -a Read all metadata from readfile and write to writefile.\n"
<< " -p Preserve existing metadata in writefile if not replaced.\n"
<< " -h Display this help and exit.\n\n";
} // Params::help

@ -1,72 +1,58 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2021 Exiv2 authors
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef METACOPY_HPP_
#define METACOPY_HPP_
class Params : public Util::Getopt {
private:
std::string optstring_;
bool first_{true};
public:
bool help_{false}; //!< Help option flag.
bool iptc_{false}; //!< Iptc option flag.
bool exif_{false}; //!< Exif option flag.
bool comment_{false}; //!< JPEG comment option flag.
bool xmp_{false}; //!< XMP option flag.
bool preserve_{false}; //!< Preserve existing metadata option flag.
std::string read_; //!< Source file
std::string write_; //!< Destination file
public:
/*!
@brief Default constructor. Note that optstring_ is initialized here.
*/
Params() : optstring_(":iecxaph")
{
}
/*!
@brief Call Getopt::getopt() with optstring, to initiate command line
argument parsing, perform consistency checks after all command line
arguments are parsed.
@param argc Argument count as passed to main() on program invocation.
@param argv Argument array as passed to main() on program invocation.
#include "getopt.hpp"
@return 0 if successful, >0 in case of errors.
*/
int getopt(int argc, char* const argv[]);
#include <iostream>
//! Handle options and their arguments.
int option(int opt, const std::string& optarg, int optopt) override;
//! Handle non-option parameters.
int nonoption(const std::string& argv) override;
//! Print a minimal usage note to an output stream.
void usage(std::ostream& os =std::cout) const;
//! Print further usage explanations to an output stream.
void help(std::ostream& os =std::cout) const;
}; // class Params
#endif // METACOPY_HPP_
class Params : public Util::Getopt {
private:
std::string optstring_;
bool first_{true};
public:
bool help_{false}; //!< Help option flag.
bool iptc_{false}; //!< Iptc option flag.
bool exif_{false}; //!< Exif option flag.
bool comment_{false}; //!< JPEG comment option flag.
bool xmp_{false}; //!< XMP option flag.
bool preserve_{false}; //!< Preserve existing metadata option flag.
std::string read_; //!< Source file
std::string write_; //!< Destination file
public:
/*!
@brief Default constructor. Note that optstring_ is initialized here.
*/
Params() : optstring_(":iecxaph") {
}
/*!
@brief Call Getopt::getopt() with optstring, to initiate command line
argument parsing, perform consistency checks after all command line
arguments are parsed.
@param argc Argument count as passed to main() on program invocation.
@param argv Argument array as passed to main() on program invocation.
@return 0 if successful, >0 in case of errors.
*/
int getopt(int argc, char* const argv[]);
//! Handle options and their arguments.
int option(int opt, const std::string& optarg, int optopt) override;
//! Handle non-option parameters.
int nonoption(const std::string& argv) override;
//! Print a minimal usage note to an output stream.
void usage(std::ostream& os = std::cout) const;
//! Print further usage explanations to an output stream.
void help(std::ostream& os = std::cout) const;
}; // class Params
#endif // METACOPY_HPP_

@ -7,38 +7,36 @@
using namespace Exiv2;
int main(int argc, char* const argv[])
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
const char* path = argv[1];
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
const char* path = argv[1];
FileIo file(path);
// Open the file in read mode
if (file.open("rb") != 0) {
throw Error(ErrorCode::kerFileOpenFailed, path, "rb", strError());
}
// Map it to memory
const Exiv2::byte* pData = file.mmap();
DataBuf buf(file.size());
// Read from the memory mapped region
buf.copyBytes(0, pData, buf.size());
// Reopen file in write mode and write to it
file.write(buf.c_data(), buf.size());
// Read from the mapped region again
buf.copyBytes(0, pData, buf.size());
file.close();
FileIo file(path);
// Open the file in read mode
if (file.open("rb") != 0) {
throw Error(ErrorCode::kerFileOpenFailed, path, "rb", strError());
}
// Map it to memory
const Exiv2::byte* pData = file.mmap();
DataBuf buf(file.size());
// Read from the memory mapped region
buf.copyBytes(0, pData, buf.size());
// Reopen file in write mode and write to it
file.write(buf.c_data(), buf.size());
// Read from the mapped region again
buf.copyBytes(0, pData, buf.size());
file.close();
return 0;
}
catch (const Error& e) {
std::cout << e << "\n";
return 0;
} catch (const Error& e) {
std::cout << e << "\n";
}

@ -1,53 +1,52 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Sample program to extract a Minolta thumbnail from the makernote
#include <exiv2/exiv2.hpp>
#include <cassert>
#include <exiv2/exiv2.hpp>
#include <iostream>
int main(int argc, char* const argv[])
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
try {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
auto image = Exiv2::ImageFactory::open(argv[1]);
image->readMetadata();
try {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
Exiv2::ExifData& exifData = image->exifData();
if (exifData.empty()) {
std::string error(argv[1]);
error += ": No Exif data found in the file";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
auto image = Exiv2::ImageFactory::open(argv[1]);
image->readMetadata();
Exiv2::ExifKey key("Exif.Minolta.ThumbnailOffset");
auto format = exifData.findKey(key);
Exiv2::ExifData& exifData = image->exifData();
if (exifData.empty()) {
std::string error(argv[1]);
error += ": No Exif data found in the file";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
if (format != exifData.end()) {
Exiv2::DataBuf buf = format->dataArea();
Exiv2::ExifKey key("Exif.Minolta.ThumbnailOffset");
auto format = exifData.findKey(key);
// The first byte of the buffer needs to be patched
buf.write_uint8(0, 0xff);
if (format != exifData.end()) {
Exiv2::DataBuf buf = format->dataArea();
Exiv2::FileIo file("img_thumb.jpg");
// The first byte of the buffer needs to be patched
buf.write_uint8(0, 0xff);
file.open("wb");
file.write(buf.c_data(), buf.size());
file.close();
}
Exiv2::FileIo file("img_thumb.jpg");
return 0;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
file.open("wb");
file.write(buf.c_data(), buf.size());
file.close();
}
return 0;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
}

@ -3,42 +3,40 @@
#include <exiv2/exiv2.hpp>
#include <filesystem>
#include <iostream>
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;
int main(int argc, char* const argv[])
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
std::ifstream file(argv[1]);
if (!file) {
std::cerr << *argv[1] << ": Failed to open file for reading\n";
return 1;
}
std::string line;
while (std::getline(file, line)) {
std::string path, dir, base;
std::istringstream is(line);
is >> path >> dir >> base;
auto p = fs::path(path);
std::string d = p.parent_path().string();
std::string b = p.filename().string();
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
std::ifstream file(argv[1]);
if (!file) {
std::cerr << *argv[1] << ": Failed to open file for reading\n";
return 1;
}
std::string line;
while (std::getline(file, line)) {
std::string path, dir, base;
std::istringstream is(line);
is >> path >> dir >> base;
auto p = fs::path(path);
std::string d = p.parent_path().string();
std::string b = p.filename().string();
if (d != dir || b != base) {
std::cout << path << "\t'" << d << "'\t '" << b
<< "'\t ==> Testcase failed\n";
}
if (d != dir || b != base) {
std::cout << path << "\t'" << d << "'\t '" << b << "'\t ==> Testcase failed\n";
}
}
return 0;
return 0;
}

@ -5,40 +5,38 @@
#include <iostream>
int main(int argc, char* const argv[])
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
std::string filename(argv[1]);
auto image = Exiv2::ImageFactory::open(filename);
image->readMetadata();
Exiv2::PreviewManager loader(*image);
Exiv2::PreviewPropertiesList list = loader.getPreviewProperties();
for (auto&& pos : list) {
std::cout << pos.mimeType_ << " preview, type " << pos.id_ << ", " << pos.size_ << " bytes, " << pos.width_
<< 'x' << pos.height_ << " pixels"
<< "\n";
Exiv2::PreviewImage preview = loader.getPreviewImage(pos);
preview.writeFile(filename + "_" + Exiv2::toString(pos.width_) + "x" + Exiv2::toString(pos.height_));
}
// Cleanup
Exiv2::XmpParser::terminate();
return 0;
}
catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
std::string filename(argv[1]);
auto image = Exiv2::ImageFactory::open(filename);
image->readMetadata();
Exiv2::PreviewManager loader(*image);
Exiv2::PreviewPropertiesList list = loader.getPreviewProperties();
for (auto&& pos : list) {
std::cout << pos.mimeType_ << " preview, type " << pos.id_ << ", " << pos.size_ << " bytes, " << pos.width_ << 'x'
<< pos.height_ << " pixels"
<< "\n";
Exiv2::PreviewImage preview = loader.getPreviewImage(pos);
preview.writeFile(filename + "_" + Exiv2::toString(pos.width_) + "x" + Exiv2::toString(pos.height_));
}
// Cleanup
Exiv2::XmpParser::terminate();
return 0;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}

@ -3,105 +3,101 @@
// It makes some modifications on the metadata of remote file, reads new metadata from that file
// and reset the metadata back to the original status.
#include <cassert>
#include <exiv2/exiv2.hpp>
#include <iostream>
#include <iomanip>
#include <cassert>
#include <iostream>
int main(int argc, char* const argv[])
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " file {--nocurl | --curl}\n\n";
return 1;
}
bool useCurlFromExiv2TestApps = true;
for ( int a = 1 ; a < argc ; a++ ) {
std::string arg(argv[a]);
if (arg == "--nocurl") useCurlFromExiv2TestApps = false;
else if (arg == "--curl") useCurlFromExiv2TestApps = true;
}
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " file {--nocurl | --curl}\n\n";
return 1;
}
std::string file(argv[1]);
bool useCurlFromExiv2TestApps = true;
for (int a = 1; a < argc; a++) {
std::string arg(argv[a]);
if (arg == "--nocurl")
useCurlFromExiv2TestApps = false;
else if (arg == "--curl")
useCurlFromExiv2TestApps = true;
}
// set/add metadata
std::cout << "Modify the metadata ...\n";
Exiv2::ExifData exifData;
exifData["Exif.Photo.UserComment"] = "Hello World"; // AsciiValue
exifData["Exif.Image.Software"] = "Exiv2"; // AsciiValue
exifData["Exif.Image.Copyright"] = "Exiv2"; // AsciiValue
exifData["Exif.Image.Make"] = "Canon"; // AsciiValue
exifData["Exif.Canon.OwnerName"] = "Tuan"; // UShortValue
exifData["Exif.CanonCs.LensType"] = uint16_t(65535); // LongValue
Exiv2::Value::UniquePtr v = Exiv2::Value::create(Exiv2::asciiString);
v->read("2013:06:09 14:30:30");
Exiv2::ExifKey key("Exif.Image.DateTime");
exifData.add(key, v.get());
std::string file(argv[1]);
auto writeTest = Exiv2::ImageFactory::open(file, useCurlFromExiv2TestApps);
writeTest->setExifData(exifData);
writeTest->writeMetadata();
// set/add metadata
std::cout << "Modify the metadata ...\n";
Exiv2::ExifData exifData;
exifData["Exif.Photo.UserComment"] = "Hello World"; // AsciiValue
exifData["Exif.Image.Software"] = "Exiv2"; // AsciiValue
exifData["Exif.Image.Copyright"] = "Exiv2"; // AsciiValue
exifData["Exif.Image.Make"] = "Canon"; // AsciiValue
exifData["Exif.Canon.OwnerName"] = "Tuan"; // UShortValue
exifData["Exif.CanonCs.LensType"] = uint16_t(65535); // LongValue
Exiv2::Value::UniquePtr v = Exiv2::Value::create(Exiv2::asciiString);
v->read("2013:06:09 14:30:30");
Exiv2::ExifKey key("Exif.Image.DateTime");
exifData.add(key, v.get());
// read the result to make sure everything fine
std::cout << "Print out the new metadata ...\n";
auto readTest = Exiv2::ImageFactory::open(file, useCurlFromExiv2TestApps);
readTest->readMetadata();
Exiv2::ExifData &exifReadData = readTest->exifData();
if (exifReadData.empty()) {
std::string error(argv[1]);
error += ": No Exif data found in the file";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
auto end = exifReadData.end();
for (auto i = exifReadData.begin(); i != end; ++i) {
const char* tn = i->typeName();
std::cout << std::setw(44) << std::setfill(' ') << std::left
<< i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right
<< std::hex << i->tag() << " "
<< std::setw(9) << std::setfill(' ') << std::left
<< (tn ? tn : "Unknown") << " "
<< std::dec << std::setw(3)
<< std::setfill(' ') << std::right
<< i->count() << " "
<< std::dec << i->value()
<< "\n";
}
auto writeTest = Exiv2::ImageFactory::open(file, useCurlFromExiv2TestApps);
writeTest->setExifData(exifData);
writeTest->writeMetadata();
// read the result to make sure everything fine
std::cout << "Print out the new metadata ...\n";
auto readTest = Exiv2::ImageFactory::open(file, useCurlFromExiv2TestApps);
readTest->readMetadata();
Exiv2::ExifData& exifReadData = readTest->exifData();
if (exifReadData.empty()) {
std::string error(argv[1]);
error += ": No Exif data found in the file";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
auto end = exifReadData.end();
for (auto i = exifReadData.begin(); i != end; ++i) {
const char* tn = i->typeName();
std::cout << std::setw(44) << std::setfill(' ') << std::left << i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " " << std::setw(9)
<< std::setfill(' ') << std::left << (tn ? tn : "Unknown") << " " << std::dec << std::setw(3)
<< std::setfill(' ') << std::right << i->count() << " " << std::dec << i->value() << "\n";
}
// del, reset the metadata
std::cout << "Reset ...\n";
exifReadData["Exif.Photo.UserComment"] = "Have a nice day"; // AsciiValue
exifReadData["Exif.Image.Software"] = "Exiv2.org"; // AsciiValue
exifReadData["Exif.Image.Copyright"] = "Exiv2.org"; // AsciiValue
key = Exiv2::ExifKey("Exif.Image.Make");
auto pos = exifReadData.findKey(key);
if (pos == exifReadData.end()) throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Exif.Image.Make not found");
exifReadData.erase(pos);
key = Exiv2::ExifKey("Exif.Image.DateTime");
pos = exifReadData.findKey(key);
if (pos == exifReadData.end()) throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Exif.Image.DateTime not found");
exifReadData.erase(pos);
key = Exiv2::ExifKey("Exif.Canon.OwnerName");
pos = exifReadData.findKey(key);
if (pos == exifReadData.end()) throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Exif.Canon.OwnerName not found");
exifReadData.erase(pos);
key = Exiv2::ExifKey("Exif.CanonCs.LensType");
pos = exifReadData.findKey(key);
if (pos == exifReadData.end()) throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Exif.CanonCs.LensType not found");
exifReadData.erase(pos);
readTest->setExifData(exifReadData);
readTest->writeMetadata();
// del, reset the metadata
std::cout << "Reset ...\n";
exifReadData["Exif.Photo.UserComment"] = "Have a nice day"; // AsciiValue
exifReadData["Exif.Image.Software"] = "Exiv2.org"; // AsciiValue
exifReadData["Exif.Image.Copyright"] = "Exiv2.org"; // AsciiValue
key = Exiv2::ExifKey("Exif.Image.Make");
auto pos = exifReadData.findKey(key);
if (pos == exifReadData.end())
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Exif.Image.Make not found");
exifReadData.erase(pos);
key = Exiv2::ExifKey("Exif.Image.DateTime");
pos = exifReadData.findKey(key);
if (pos == exifReadData.end())
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Exif.Image.DateTime not found");
exifReadData.erase(pos);
key = Exiv2::ExifKey("Exif.Canon.OwnerName");
pos = exifReadData.findKey(key);
if (pos == exifReadData.end())
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Exif.Canon.OwnerName not found");
exifReadData.erase(pos);
key = Exiv2::ExifKey("Exif.CanonCs.LensType");
pos = exifReadData.findKey(key);
if (pos == exifReadData.end())
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Exif.CanonCs.LensType not found");
exifReadData.erase(pos);
readTest->setExifData(exifReadData);
readTest->writeMetadata();
return 0;
}
catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
return 0;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}

@ -36,55 +36,54 @@ static constexpr const char* testcases[] = {
"text",
};
int main()
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main() {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
std::cout << std::setfill(' ');
std::cout << std::setfill(' ');
std::cout << std::setw(12) << std::left << "string";
std::cout << std::setw(12) << std::left << "long";
std::cout << std::setw(12) << std::left << "float";
std::cout << std::setw(12) << std::left << "Rational";
std::cout << std::setw(12) << std::left << "string";
std::cout << std::setw(12) << std::left << "long";
std::cout << std::setw(12) << std::left << "float";
std::cout << std::setw(12) << std::left << "Rational";
std::cout << std::endl;
std::cout << std::endl;
for (auto&& testcase : testcases) {
try {
std::string s(testcase);
std::cout << std::setw(12) << std::left << s;
bool ok = false;
for (auto&& testcase : testcases) {
try {
std::string s(testcase);
std::cout << std::setw(12) << std::left << s;
bool ok = false;
const auto l = Exiv2::parseInt64(s, ok);
std::cout << std::setw(12) << std::left;
if (ok)
std::cout << l;
else
std::cout << "nok";
const auto l = Exiv2::parseInt64(s, ok);
std::cout << std::setw(12) << std::left;
if (ok)
std::cout << l;
else
std::cout << "nok";
float f = Exiv2::parseFloat(s, ok);
std::cout << std::setw(12) << std::left;
if (ok)
std::cout << f;
else
std::cout << "nok";
float f = Exiv2::parseFloat(s, ok);
std::cout << std::setw(12) << std::left;
if (ok)
std::cout << f;
else
std::cout << "nok";
Exiv2::Rational r = Exiv2::parseRational(s, ok);
if (ok)
std::cout << r.first << "/" << r.second;
else
std::cout << "nok";
Exiv2::Rational r = Exiv2::parseRational(s, ok);
if (ok)
std::cout << r.first << "/" << r.second;
else
std::cout << "nok";
std::cout << std::endl;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
std::cout << std::endl;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
}
return 0;
return 0;
}

@ -6,138 +6,134 @@
using namespace Exiv2;
int main(int argc, char* argv[])
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* argv[]) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
int rc = EXIT_SUCCESS;
std::ostringstream out;
try {
bool bHelp = false;
int rc = EXIT_SUCCESS;
std::ostringstream out;
try {
bool bHelp = false;
switch (argc) {
case 2: {
std::string item(argv[1]);
switch (argc) {
case 2: {
std::string item(argv[1]);
if ( item == "--help" ) {
bHelp = true;
break;
}
if (item == "Groups") {
const GroupInfo* groupList = ExifTags::groupList();
if (groupList) {
while (groupList->tagList_) {
std::cout << groupList->groupName_ << std::endl;
groupList++;
}
}
break;
}
if (item == "--help") {
bHelp = true;
break;
}
if (item == "all" || item == "ALL" ) {
const GroupInfo* groupList = ExifTags::groupList();
if (groupList) {
std::string line;
while (groupList->tagList_) {
std::ostringstream tags;
ExifTags::taglist(tags,groupList->groupName_);
std::istringstream input(tags.str()) ;
while (std::getline(input, line)) {
std::cout << groupList->groupName_ << "."
<< (item == "all" ? line.substr(0, line.find(',')) : line) << std::endl;
}
groupList++;
}
}
break;
}
if (item == "Groups") {
const GroupInfo* groupList = ExifTags::groupList();
if (groupList) {
while (groupList->tagList_) {
std::cout << groupList->groupName_ << std::endl;
groupList++;
}
}
break;
}
if (item == "all" || item == "ALL") {
const GroupInfo* groupList = ExifTags::groupList();
if (groupList) {
std::string line;
while (groupList->tagList_) {
std::ostringstream tags;
ExifTags::taglist(tags, groupList->groupName_);
std::istringstream input(tags.str());
while (std::getline(input, line)) {
std::cout << groupList->groupName_ << "." << (item == "all" ? line.substr(0, line.find(',')) : line)
<< std::endl;
}
groupList++;
}
}
break;
}
if (item == "Exif") {
ExifTags::taglist(std::cout);
break;
}
if (item == "Exif") {
ExifTags::taglist(std::cout);
break;
}
if (item == "Iptc") {
IptcDataSets::dataSetList(std::cout);
break;
}
if (item == "Iptc") {
IptcDataSets::dataSetList(std::cout);
break;
}
if (ExifTags::isExifGroup(item) || ExifTags::isMakerGroup(item)) {
ExifTags::taglist(std::cout, item);
break;
}
if (ExifTags::isExifGroup(item) || ExifTags::isMakerGroup(item)) {
ExifTags::taglist(std::cout, item);
break;
}
try {
XmpProperties::printProperties(std::cout, item);
break;
} catch (const Error&) {
rc = 2;
try {
XmpProperties::printProperties(std::cout, item);
break;
} catch (const Error&) {
rc = 2;
}
std::cerr << "Unexpected argument " << argv[1] << std::endl;
break;
}
case 1:
ExifTags::taglist(std::cout);
break;
case 3: {
std::string item(argv[1]);
std::string name(argv[2]);
rc = EXIT_FAILURE; // assume unhappy ending!
if (item == "--group") {
if (ExifTags::isExifGroup(name)) {
ExifTags::taglist(std::cout, name);
rc = EXIT_SUCCESS; // result is good
} else {
std::cerr << "warning:" << name << " is not a valid Exif group name " << std::endl;
const GroupInfo* groupList = ExifTags::groupList();
if (groupList) {
while (rc && groupList->tagList_) {
if (name == groupList->groupName_) {
const Exiv2::TagInfo* tagInfo = groupList->tagList_();
while (tagInfo->tag_ != 0xFFFF) {
std::cout << tagInfo->name_ << std::endl;
tagInfo++;
}
rc = EXIT_SUCCESS; // result is good
}
std::cerr << "Unexpected argument " << argv[1] << std::endl;
break;
groupList++;
}
}
case 1:
ExifTags::taglist(std::cout);
break;
case 3: {
std::string item(argv[1]);
std::string name(argv[2]);
rc = EXIT_FAILURE; // assume unhappy ending!
if (item == "--group") {
if ( ExifTags::isExifGroup(name) ) {
ExifTags::taglist(std::cout,name);
rc = EXIT_SUCCESS; // result is good
} else {
std::cerr << "warning:"
<< name
<< " is not a valid Exif group name "
<< std::endl
;
const GroupInfo* groupList = ExifTags::groupList();
if (groupList) {
while (rc && groupList->tagList_) {
if (name == groupList->groupName_) {
const Exiv2::TagInfo* tagInfo = groupList->tagList_();
while (tagInfo->tag_ != 0xFFFF) {
std::cout << tagInfo->name_ << std::endl;
tagInfo++;
}
rc = EXIT_SUCCESS; // result is good
}
groupList++;
}
}
}
}
} break;
default:
rc = EXIT_FAILURE;
break;
}
}
} break;
if (rc || bHelp) {
std::cout << "Usage: taglist [--help]" << std::endl
<< " [--group name|" << std::endl
<< " Groups|Exif|Canon|CanonCs|CanonSi|CanonCf|CanonHdr|Fujifilm|Minolta|Nikon1|Nikon2|Nikon3|Olympus|" << std::endl
<< " Panasonic|Pentax|Sigma|Sony|Iptc|" << std::endl
<< " dc|xmp|xmpRights|xmpMM|xmpBJ|xmpTPg|xmpDM|pdf|photoshop|crs|tiff|exif|aux|iptc|all|ALL" << std::endl
<< " ]" << std::endl
<< "Print Exif tags, MakerNote tags, or Iptc datasets" << std::endl
;
}
} catch (Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
rc = EXIT_FAILURE ;
default:
rc = EXIT_FAILURE;
break;
}
if (rc || bHelp) {
std::cout << "Usage: taglist [--help]" << std::endl
<< " [--group name|" << std::endl
<< " "
"Groups|Exif|Canon|CanonCs|CanonSi|CanonCf|CanonHdr|Fujifilm|Minolta|Nikon1|Nikon2|Nikon3|Olympus|"
<< std::endl
<< " Panasonic|Pentax|Sigma|Sony|Iptc|" << std::endl
<< " dc|xmp|xmpRights|xmpMM|xmpBJ|xmpTPg|xmpDM|pdf|photoshop|crs|tiff|exif|aux|iptc|all|ALL"
<< std::endl
<< " ]" << std::endl
<< "Print Exif tags, MakerNote tags, or Iptc datasets" << std::endl;
}
return rc;
} catch (Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
rc = EXIT_FAILURE;
}
return rc;
}

@ -1,13 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// First and very simple TIFF write test.
#include <exiv2/exiv2.hpp>
#include <enforce.hpp>
#include <exiv2/exiv2.hpp>
#include <string>
#include <iostream>
#include <iomanip>
#include <cassert>
#include <iomanip>
#include <iostream>
#include <string>
using namespace Exiv2;
@ -16,97 +16,85 @@ void print(const ExifData& exifData);
void mini1(const char* path);
void mini9(const char* path);
int main(int argc, char* const argv[])
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
const char* path = argv[1];
mini1(path);
mini9(path);
const char* path = argv[1];
mini1(path);
mini9(path);
return 0;
}
catch (const Error& e) {
std::cout << e << "\n";
return 0;
} catch (const Error& e) {
std::cout << e << "\n";
}
void mini1(const char* path)
{
ExifData exifData;
Blob blob;
WriteMethod wm;
// Write nothing to a new structure, without a previous binary image
wm = ExifParser::encode(blob, nullptr, 0, bigEndian, exifData);
enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value");
assert(blob.empty());
std::cout << "Test 1: Writing empty Exif data without original binary data: ok.\n";
// Write nothing, this time with a previous binary image
DataBuf buf = readFile(path);
wm = ExifParser::encode(blob, buf.c_data(), buf.size(), bigEndian, exifData);
enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value");
assert(blob.empty());
std::cout << "Test 2: Writing empty Exif data with original binary data: ok.\n";
// Write something to a new structure, without a previous binary image
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
wm = ExifParser::encode(blob, nullptr, 0, bigEndian, exifData);
enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value");
std::cout << "Test 3: Wrote non-empty Exif data without original binary data:\n";
exifData.clear();
ByteOrder bo = ExifParser::decode(exifData, &blob[0], blob.size());
enforce(bo == bigEndian, Exiv2::ErrorCode::kerErrorMessage, "decode returned an unexpected value");
print(exifData);
void mini1(const char* path) {
ExifData exifData;
Blob blob;
WriteMethod wm;
// Write nothing to a new structure, without a previous binary image
wm = ExifParser::encode(blob, nullptr, 0, bigEndian, exifData);
enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value");
assert(blob.empty());
std::cout << "Test 1: Writing empty Exif data without original binary data: ok.\n";
// Write nothing, this time with a previous binary image
DataBuf buf = readFile(path);
wm = ExifParser::encode(blob, buf.c_data(), buf.size(), bigEndian, exifData);
enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value");
assert(blob.empty());
std::cout << "Test 2: Writing empty Exif data with original binary data: ok.\n";
// Write something to a new structure, without a previous binary image
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
wm = ExifParser::encode(blob, nullptr, 0, bigEndian, exifData);
enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value");
std::cout << "Test 3: Wrote non-empty Exif data without original binary data:\n";
exifData.clear();
ByteOrder bo = ExifParser::decode(exifData, &blob[0], blob.size());
enforce(bo == bigEndian, Exiv2::ErrorCode::kerErrorMessage, "decode returned an unexpected value");
print(exifData);
}
void mini9(const char* path)
{
TiffImage tiffImage(std::make_unique<FileIo>(path), false);
tiffImage.readMetadata();
void mini9(const char* path) {
TiffImage tiffImage(std::make_unique<FileIo>(path), false);
tiffImage.readMetadata();
std::cout << "MIME type: " << tiffImage.mimeType() << "\n";
std::cout << "Image size: " << tiffImage.pixelWidth() << " x " << tiffImage.pixelHeight() << "\n";
std::cout << "MIME type: " << tiffImage.mimeType() << "\n";
std::cout << "Image size: " << tiffImage.pixelWidth() << " x " << tiffImage.pixelHeight() << "\n";
ExifData& exifData = tiffImage.exifData();
std::cout << "Before\n";
print(exifData);
std::cout << "======\n";
ExifData& exifData = tiffImage.exifData();
std::cout << "Before\n";
print(exifData);
std::cout << "======\n";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
std::cout << "After\n";
print(exifData);
tiffImage.writeMetadata();
std::cout << "After\n";
print(exifData);
tiffImage.writeMetadata();
}
void print(const ExifData& exifData)
{
if (exifData.empty()) {
std::string error("No Exif data found in the file");
throw Exiv2::Error(ErrorCode::kerErrorMessage, error);
}
auto end = exifData.end();
for (auto i = exifData.begin(); i != end; ++i) {
std::cout << std::setw(44) << std::setfill(' ') << std::left
<< i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right
<< std::hex << i->tag() << " "
<< std::setw(9) << std::setfill(' ') << std::left
<< i->typeName() << " "
<< std::dec << std::setw(3)
<< std::setfill(' ') << std::right
<< i->count() << " "
<< std::dec << i->value()
<< "\n";
}
void print(const ExifData& exifData) {
if (exifData.empty()) {
std::string error("No Exif data found in the file");
throw Exiv2::Error(ErrorCode::kerErrorMessage, error);
}
auto end = exifData.end();
for (auto i = exifData.begin(); i != end; ++i) {
std::cout << std::setw(44) << std::setfill(' ') << std::left << i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " " << std::setw(9)
<< std::setfill(' ') << std::left << i->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ')
<< std::right << i->count() << " " << std::dec << i->value() << "\n";
}
}

@ -9,29 +9,24 @@
using namespace Exiv2;
void testCase(const std::string& file1,
const std::string& file2,
const std::string& thumb,
const std::string& key,
void testCase(const std::string& file1, const std::string& file2, const std::string& thumb, const std::string& key,
const std::string& value);
void exifPrint(const ExifData& exifData);
// *****************************************************************************
// Main
int main(int argc, char* const argv[])
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
try {
try {
if (argc != 3) {
std::cout << "Usage: write-test file case\n\n"
<< "where case is an integer between 1 and 11\n";
return 1;
std::cout << "Usage: write-test file case\n\n"
<< "where case is an integer between 1 and 11\n";
return 1;
}
std::string testFile = argv[1];
@ -41,89 +36,69 @@ int main(int argc, char* const argv[])
int rc = 0;
switch (testNo) {
case 1:
case 1:
std::cerr << "Case 1: ";
std::cerr << "Non-intrusive change to the standard Exif metadata\n";
testCase(testFile, "test1.jpg", "thumb1",
"Exif.Photo.DateTimeOriginal",
"1999:11:22 00:11:22");
testCase(testFile, "test1.jpg", "thumb1", "Exif.Photo.DateTimeOriginal", "1999:11:22 00:11:22");
break;
case 2:
case 2:
std::cerr << "Case 2: ";
std::cerr << "Non-intrusive change to the makernote metadata\n";
testCase(testFile, "test2.jpg", "thumb2",
"Exif.Canon.OwnerName",
"Chan YeeSend");
testCase(testFile, "test2.jpg", "thumb2", "Exif.Canon.OwnerName", "Chan YeeSend");
break;
case 3:
case 3:
std::cerr << "Case 3: ";
std::cerr << "Non-intrusive change to the Exif metadata (w/o makernote)\n";
testCase(testFile, "test3.jpg", "thumb3",
"Exif.Photo.DateTimeOriginal",
"1999:11:22 00:11:22");
testCase(testFile, "test3.jpg", "thumb3", "Exif.Photo.DateTimeOriginal", "1999:11:22 00:11:22");
break;
case 4:
case 4:
std::cerr << "Case 4: ";
std::cerr << "Intrusive change to the standard Exif metadata\n";
testCase(testFile, "test4.jpg", "thumb4",
"Exif.Photo.DateTimeOriginal",
testCase(testFile, "test4.jpg", "thumb4", "Exif.Photo.DateTimeOriginal",
"1999:11:22 00:11:22 and twenty seconds");
break;
case 5:
case 5:
std::cerr << "Case 5: ";
std::cerr << "Intrusive change to the Canon makernote metadata\n";
testCase(testFile, "test5.jpg", "thumb5",
"Exif.Canon.OwnerName",
"Frau Chan YeeSend und Herr Andreas Huggel");
testCase(testFile, "test5.jpg", "thumb5", "Exif.Canon.OwnerName", "Frau Chan YeeSend und Herr Andreas Huggel");
break;
case 6:
case 6:
std::cerr << "Case 6: ";
std::cerr << "Intrusive change to the Exif metadata (w/o makernote)\n";
testCase(testFile, "test6.jpg", "thumb6",
"Exif.Photo.DateTimeOriginal",
testCase(testFile, "test6.jpg", "thumb6", "Exif.Photo.DateTimeOriginal",
"1999:11:22 00:11:22 and twenty seconds");
break;
case 7:
case 7:
std::cerr << "Case 7: ";
std::cerr << "Intrusive change to the Fujifilm makernote metadata\n";
testCase(testFile, "test7.jpg", "thumb7",
"Exif.Fujifilm.Quality",
"Typical Fujifilm Quality");
testCase(testFile, "test7.jpg", "thumb7", "Exif.Fujifilm.Quality", "Typical Fujifilm Quality");
break;
case 8:
case 8:
std::cerr << "Case 8: ";
std::cerr << "Intrusive change to the Sigma makernote metadata\n";
testCase(testFile, "test8.jpg", "thumb8",
"Exif.Sigma.ResolutionMode",
"Sigma HI resolution");
testCase(testFile, "test8.jpg", "thumb8", "Exif.Sigma.ResolutionMode", "Sigma HI resolution");
break;
case 9:
case 9:
std::cerr << "Case 9: ";
std::cerr << "Intrusive change to the Nikon1 makernote metadata\n";
testCase(testFile, "test9.jpg", "thumb9",
"Exif.Nikon1.Quality",
"Typical Nikon1 Quality");
testCase(testFile, "test9.jpg", "thumb9", "Exif.Nikon1.Quality", "Typical Nikon1 Quality");
break;
case 10:
case 10:
std::cerr << "Case 10: ";
std::cerr << "Intrusive change to the Nikon2 makernote metadata\n";
testCase(testFile, "test10.jpg", "thumb10",
"Exif.Nikon2.0x0002",
"Nikon2 Version 2");
testCase(testFile, "test10.jpg", "thumb10", "Exif.Nikon2.0x0002", "Nikon2 Version 2");
break;
case 11:
case 11:
std::cerr << "Case 11: ";
std::cerr << "Intrusive change to the Nikon3 makernote metadata\n";
testCase(testFile, "test11.jpg", "thumb11",
"Exif.Nikon3.Quality",
"Typical Nikon3 Quality");
testCase(testFile, "test11.jpg", "thumb11", "Exif.Nikon3.Quality", "Typical Nikon3 Quality");
break;
// ToDo: Erase Sigma thumbnail
// ToDo: Write to a broken (truncated) IFD entry
default:
default:
std::cout << "Usage: exiftest file case\n\n"
<< "where case is an integer between 1 and 11\n";
rc = 1;
@ -131,72 +106,59 @@ int main(int argc, char* const argv[])
}
return rc;
}
catch (Error& e) {
} catch (Error& e) {
std::cerr << "Caught Exiv2 exception '" << e << "'\n";
return 1;
}
}
}
// *****************************************************************************
void testCase(const std::string& file1,
const std::string& file2,
const std::string& thumb,
const std::string& key,
const std::string& value)
{
ExifKey ek(key);
//Open first image
auto image1 = ImageFactory::open(file1);
// Load existing metadata
std::cerr << "---> Reading file " << file1 << "\n";
image1->readMetadata();
Exiv2::ExifData &ed1 = image1->exifData();
std::cerr << "---> Modifying Exif data\n";
auto pos = ed1.findKey(ek);
if (pos == ed1.end()) {
throw Error(ErrorCode::kerErrorMessage, "Metadatum with key = " + ek.key() + " not found");
}
pos->setValue(value);
void testCase(const std::string& file1, const std::string& file2, const std::string& thumb, const std::string& key,
const std::string& value) {
ExifKey ek(key);
// Open second image
auto image2 = ImageFactory::open(file2);
// Open first image
auto image1 = ImageFactory::open(file1);
image2->setExifData(image1->exifData());
// Load existing metadata
std::cerr << "---> Reading file " << file1 << "\n";
image1->readMetadata();
std::cerr << "---> Writing Exif data to file " << file2 << "\n";
image2->writeMetadata();
Exiv2::ExifData& ed1 = image1->exifData();
std::cerr << "---> Modifying Exif data\n";
auto pos = ed1.findKey(ek);
if (pos == ed1.end()) {
throw Error(ErrorCode::kerErrorMessage, "Metadatum with key = " + ek.key() + " not found");
}
pos->setValue(value);
std::cerr << "---> Reading file " << file2 << "\n";
image2->readMetadata();
// Open second image
auto image2 = ImageFactory::open(file2);
Exiv2::ExifData &ed2 = image2->exifData();
exifPrint(ed2);
image2->setExifData(image1->exifData());
std::cerr << "---> Writing Exif thumbnail to file " << thumb << ".*\n";
ExifThumbC et2(ed2);
et2.writeFile(thumb);
std::cerr << "---> Writing Exif data to file " << file2 << "\n";
image2->writeMetadata();
std::cerr << "---> Reading file " << file2 << "\n";
image2->readMetadata();
Exiv2::ExifData& ed2 = image2->exifData();
exifPrint(ed2);
std::cerr << "---> Writing Exif thumbnail to file " << thumb << ".*\n";
ExifThumbC et2(ed2);
et2.writeFile(thumb);
}
// *****************************************************************************
void exifPrint(const ExifData& exifData)
{
auto i = exifData.begin();
for (; i != exifData.end(); ++i) {
std::cout << std::setw(44) << std::setfill(' ') << std::left
<< i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right
<< std::hex << i->tag() << " "
<< std::setw(9) << std::setfill(' ') << std::left
<< i->typeName() << " "
<< std::dec << std::setw(3)
<< std::setfill(' ') << std::right
<< i->count() << " "
<< std::dec << i->value()
<< "\n";
}
void exifPrint(const ExifData& exifData) {
auto i = exifData.begin();
for (; i != exifData.end(); ++i) {
std::cout << std::setw(44) << std::setfill(' ') << std::left << i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " " << std::setw(9)
<< std::setfill(' ') << std::left << i->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ')
<< std::right << i->count() << " " << std::dec << i->value() << "\n";
}
}

@ -8,22 +8,21 @@ void print(const std::string& file);
// *****************************************************************************
// Main
int main(int argc, char* const argv[])
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
try {
try {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
std::string file(argv[1]);
std::cout <<"----- Some IFD0 tags\n";
std::cout << "----- Some IFD0 tags\n";
Exiv2::ExifData ed1;
ed1["Exif.Image.Model"] = "Test 1";
@ -46,16 +45,16 @@ int main(int argc, char* const argv[])
write(file, ed1);
print(file);
std::cout <<"\n----- One Exif tag\n";
std::cout << "\n----- One Exif tag\n";
Exiv2::ExifData ed2;
ed2["Exif.Photo.DateTimeOriginal"] = "Test 2";
write(file, ed2);
print(file);
std::cout <<"\n----- Canon MakerNote tags\n";
std::cout << "\n----- Canon MakerNote tags\n";
Exiv2::ExifData edMn1;
edMn1["Exif.Image.Make"] = "Canon";
edMn1["Exif.Image.Model"] = "Canon PowerShot S40";
edMn1["Exif.Image.Make"] = "Canon";
edMn1["Exif.Image.Model"] = "Canon PowerShot S40";
edMn1["Exif.Canon.0xabcd"] = "A Canon makernote tag";
edMn1["Exif.CanonCs.0x0002"] = uint16_t(41);
edMn1["Exif.CanonSi.0x0005"] = uint16_t(42);
@ -65,7 +64,7 @@ int main(int argc, char* const argv[])
write(file, edMn1);
print(file);
std::cout <<"\n----- Non-intrusive writing of special Canon MakerNote tags\n";
std::cout << "\n----- Non-intrusive writing of special Canon MakerNote tags\n";
auto image = Exiv2::ImageFactory::open(file);
image->readMetadata();
@ -75,74 +74,74 @@ int main(int argc, char* const argv[])
image->writeMetadata();
print(file);
std::cout <<"\n----- One Fujifilm MakerNote tag\n";
std::cout << "\n----- One Fujifilm MakerNote tag\n";
Exiv2::ExifData edMn2;
edMn2["Exif.Image.Make"] = "FUJIFILM";
edMn2["Exif.Image.Model"] = "FinePixS2Pro";
edMn2["Exif.Image.Make"] = "FUJIFILM";
edMn2["Exif.Image.Model"] = "FinePixS2Pro";
edMn2["Exif.Fujifilm.0x1000"] = "A Fujifilm QUALITY tag";
write(file, edMn2);
print(file);
std::cout <<"\n----- One Sigma/Foveon MakerNote tag\n";
std::cout << "\n----- One Sigma/Foveon MakerNote tag\n";
Exiv2::ExifData edMn3;
edMn3["Exif.Image.Make"] = "SIGMA";
edMn3["Exif.Image.Model"] = "SIGMA SD10";
edMn3["Exif.Image.Make"] = "SIGMA";
edMn3["Exif.Image.Model"] = "SIGMA SD10";
edMn3["Exif.Sigma.0x0018"] = "Software? Exiv2!";
write(file, edMn3);
print(file);
std::cout <<"\n----- One Nikon1 MakerNote tag\n";
std::cout << "\n----- One Nikon1 MakerNote tag\n";
Exiv2::ExifData edMn4;
edMn4["Exif.Image.Make"] = "NIKON";
edMn4["Exif.Image.Model"] = "E990";
edMn4["Exif.Image.Make"] = "NIKON";
edMn4["Exif.Image.Model"] = "E990";
edMn4["Exif.Nikon1.0x0080"] = "ImageAdjustment by Exiv2";
write(file, edMn4);
print(file);
std::cout <<"\n----- One Nikon2 MakerNote tag\n";
std::cout << "\n----- One Nikon2 MakerNote tag\n";
Exiv2::ExifData edMn5;
edMn5["Exif.Image.Make"] = "NIKON";
edMn5["Exif.Image.Model"] = "E950";
edMn5["Exif.Image.Make"] = "NIKON";
edMn5["Exif.Image.Model"] = "E950";
edMn5["Exif.Nikon2.0xffff"] = "An obscure Nikon2 tag";
write(file, edMn5);
print(file);
std::cout <<"\n----- One Nikon3 MakerNote tag\n";
std::cout << "\n----- One Nikon3 MakerNote tag\n";
Exiv2::ExifData edMn6;
edMn6["Exif.Image.Make"] = "NIKON CORPORATION";
edMn6["Exif.Image.Model"] = "NIKON D70";
edMn6["Exif.Image.Make"] = "NIKON CORPORATION";
edMn6["Exif.Image.Model"] = "NIKON D70";
edMn6["Exif.Nikon3.0x0004"] = "A boring Nikon3 Quality tag";
write(file, edMn6);
print(file);
std::cout <<"\n----- One Olympus MakerNote tag\n";
std::cout << "\n----- One Olympus MakerNote tag\n";
Exiv2::ExifData edMn7;
edMn7["Exif.Image.Make"] = "OLYMPUS CORPORATION";
edMn7["Exif.Image.Model"] = "C8080WZ";
edMn7["Exif.Image.Make"] = "OLYMPUS CORPORATION";
edMn7["Exif.Image.Model"] = "C8080WZ";
edMn7["Exif.Olympus.0x0201"] = uint16_t(1);
write(file, edMn7);
print(file);
std::cout <<"\n----- One Panasonic MakerNote tag\n";
std::cout << "\n----- One Panasonic MakerNote tag\n";
Exiv2::ExifData edMn8;
edMn8["Exif.Image.Make"] = "Panasonic";
edMn8["Exif.Image.Model"] = "DMC-FZ5";
edMn8["Exif.Image.Make"] = "Panasonic";
edMn8["Exif.Image.Model"] = "DMC-FZ5";
edMn8["Exif.Panasonic.0x0001"] = uint16_t(1);
write(file, edMn8);
print(file);
std::cout <<"\n----- One Sony1 MakerNote tag\n";
std::cout << "\n----- One Sony1 MakerNote tag\n";
Exiv2::ExifData edMn9;
edMn9["Exif.Image.Make"] = "SONY";
edMn9["Exif.Image.Model"] = "DSC-W7";
edMn9["Exif.Image.Make"] = "SONY";
edMn9["Exif.Image.Model"] = "DSC-W7";
edMn9["Exif.Sony1.0x2000"] = "0 1 2 3 4 5";
write(file, edMn9);
print(file);
std::cout <<"\n----- Minolta MakerNote tags\n";
std::cout << "\n----- Minolta MakerNote tags\n";
Exiv2::ExifData edMn10;
edMn10["Exif.Image.Make"] = "Minolta";
edMn10["Exif.Image.Model"] = "A fancy Minolta camera";
edMn10["Exif.Image.Make"] = "Minolta";
edMn10["Exif.Image.Model"] = "A fancy Minolta camera";
edMn10["Exif.Minolta.ColorMode"] = uint32_t(1);
edMn10["Exif.MinoltaCsNew.WhiteBalance"] = uint32_t(2);
edMn10["Exif.MinoltaCs5D.WhiteBalance"] = uint16_t(3);
@ -153,32 +152,32 @@ int main(int argc, char* const argv[])
write(file, edMn10);
print(file);
std::cout <<"\n----- One IOP tag\n";
std::cout << "\n----- One IOP tag\n";
Exiv2::ExifData ed3;
ed3["Exif.Iop.InteroperabilityIndex"] = "Test 3";
write(file, ed3);
print(file);
std::cout <<"\n----- One GPS tag\n";
std::cout << "\n----- One GPS tag\n";
Exiv2::ExifData ed4;
ed4["Exif.GPSInfo.GPSVersionID"] = "19 20";
write(file, ed4);
print(file);
std::cout <<"\n----- One IFD1 tag\n";
std::cout << "\n----- One IFD1 tag\n";
Exiv2::ExifData ed5;
ed5["Exif.Thumbnail.Artist"] = "Test 5";
write(file, ed5);
print(file);
std::cout <<"\n----- One IOP and one IFD1 tag\n";
std::cout << "\n----- One IOP and one IFD1 tag\n";
Exiv2::ExifData ed6;
ed6["Exif.Iop.InteroperabilityIndex"] = "Test 6 Iop tag";
ed6["Exif.Thumbnail.Artist"] = "Test 6 Ifd1 tag";
write(file, ed6);
print(file);
std::cout <<"\n----- One IFD0 and one IFD1 tag\n";
std::cout << "\n----- One IFD0 and one IFD1 tag\n";
Exiv2::ExifData ed7;
ed7["Exif.Thumbnail.Artist"] = "Test 7";
Exiv2::Value::UniquePtr v5 = Exiv2::Value::create(Exiv2::unsignedShort);
@ -188,42 +187,30 @@ int main(int argc, char* const argv[])
print(file);
return 0;
}
catch (Exiv2::Error& e) {
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
}
}
void write(const std::string& file, Exiv2::ExifData& ed)
{
auto image = Exiv2::ImageFactory::open(file);
void write(const std::string& file, Exiv2::ExifData& ed) {
auto image = Exiv2::ImageFactory::open(file);
image->setExifData(ed);
image->writeMetadata();
image->setExifData(ed);
image->writeMetadata();
}
void print(const std::string& file)
{
auto image = Exiv2::ImageFactory::open(file);
image->readMetadata();
Exiv2::ExifData &ed = image->exifData();
auto end = ed.end();
for (auto i = ed.begin(); i != end; ++i) {
std::cout << std::setw(45) << std::setfill(' ') << std::left
<< i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right
<< std::hex << i->tag() << " "
<< std::setw(12) << std::setfill(' ') << std::left
<< i->ifdName() << " "
<< std::setw(9) << std::setfill(' ') << std::left
<< i->typeName() << " "
<< std::dec << std::setw(3)
<< std::setfill(' ') << std::right
<< i->count() << " "
<< std::dec << i->value()
<< "\n";
}
void print(const std::string& file) {
auto image = Exiv2::ImageFactory::open(file);
image->readMetadata();
Exiv2::ExifData& ed = image->exifData();
auto end = ed.end();
for (auto i = ed.begin(); i != end; ++i) {
std::cout << std::setw(45) << std::setfill(' ') << std::left << i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " " << std::setw(12)
<< std::setfill(' ') << std::left << i->ifdName() << " " << std::setw(9) << std::setfill(' ') << std::left
<< i->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << i->count()
<< " " << std::dec << i->value() << "\n";
}
}

@ -4,34 +4,33 @@
#include <exiv2/exiv2.hpp>
#include <iostream>
int main(int argc, char* const argv[])
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
try {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
auto image = Exiv2::ImageFactory::open(argv[1]);
image->readMetadata();
try {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
const std::string& xmpPacket = image->xmpPacket();
if (xmpPacket.empty()) {
std::string error(argv[1]);
error += ": No XMP packet found in the file";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
std::cout << xmpPacket << "\n";
auto image = Exiv2::ImageFactory::open(argv[1]);
image->readMetadata();
return 0;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
const std::string& xmpPacket = image->xmpPacket();
if (xmpPacket.empty()) {
std::string error(argv[1]);
error += ": No XMP packet found in the file";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
std::cout << xmpPacket << "\n";
return 0;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
}

@ -4,42 +4,40 @@
#include <exiv2/exiv2.hpp>
#include <iostream>
int main(int argc, char* const argv[])
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
Exiv2::DataBuf buf = Exiv2::readFile(argv[1]);
std::string xmpPacket;
xmpPacket.assign(buf.c_str(), buf.size());
Exiv2::XmpData xmpData;
if (0 != Exiv2::XmpParser::decode(xmpData, xmpPacket)) {
std::string error(argv[1]);
error += ": Failed to parse file contents (XMP packet)";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
if (xmpData.empty()) {
std::string error(argv[1]);
error += ": No XMP properties found in the XMP packet";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
for (auto&& md : xmpData) {
std::cout << std::setfill(' ') << std::left << std::setw(44) << md.key() << " " << std::setw(9)
<< std::setfill(' ') << std::left << md.typeName() << " " << std::dec << std::setw(3)
<< std::setfill(' ') << std::right << md.count() << " " << std::dec << md.toString() << std::endl;
}
Exiv2::XmpParser::terminate();
return 0;
}
catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
Exiv2::DataBuf buf = Exiv2::readFile(argv[1]);
std::string xmpPacket;
xmpPacket.assign(buf.c_str(), buf.size());
Exiv2::XmpData xmpData;
if (0 != Exiv2::XmpParser::decode(xmpData, xmpPacket)) {
std::string error(argv[1]);
error += ": Failed to parse file contents (XMP packet)";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
if (xmpData.empty()) {
std::string error(argv[1]);
error += ": No XMP properties found in the XMP packet";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
for (auto&& md : xmpData) {
std::cout << std::setfill(' ') << std::left << std::setw(44) << md.key() << " " << std::setw(9) << std::setfill(' ')
<< std::left << md.typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right
<< md.count() << " " << std::dec << md.toString() << std::endl;
}
Exiv2::XmpParser::terminate();
return 0;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}

@ -4,57 +4,55 @@
#include <exiv2/exiv2.hpp>
#include <iostream>
int main(int argc, char* const argv[])
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main(int argc, char* const argv[]) try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
std::string filename(argv[1]);
Exiv2::DataBuf buf = Exiv2::readFile(filename);
std::string xmpPacket;
xmpPacket.assign(buf.c_str(), buf.size());
std::cerr << "-----> Decoding XMP data read from " << filename << " <-----\n";
Exiv2::XmpData xmpData;
if (0 != Exiv2::XmpParser::decode(xmpData, xmpPacket)) {
std::string error(argv[1]);
error += ": Failed to parse file contents (XMP packet)";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
if (xmpData.empty()) {
std::string error(argv[1]);
error += ": No XMP properties found in the XMP packet";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
for (auto&& md : xmpData) {
std::cout << std::setfill(' ') << std::left << std::setw(44) << md.key() << " " << std::setw(9)
<< std::setfill(' ') << std::left << md.typeName() << " " << std::dec << std::setw(3)
<< std::setfill(' ') << std::right << md.count() << " " << std::dec << md.toString() << std::endl;
}
filename += "-new";
std::cerr << "-----> Encoding XMP data to write to " << filename << " <-----\n";
if (0 != Exiv2::XmpParser::encode(xmpPacket, xmpData)) {
std::string error(argv[1]);
error += ": Failed to encode the XMP data";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
Exiv2::FileIo file(filename);
if (file.open("wb") != 0) {
throw Exiv2::Error(Exiv2::ErrorCode::kerFileOpenFailed, filename, "wb", Exiv2::strError());
}
if (file.write(reinterpret_cast<const Exiv2::byte*>(xmpPacket.data()), xmpPacket.size()) == 0) {
throw Exiv2::Error(Exiv2::ErrorCode::kerCallFailed, filename, Exiv2::strError(), "FileIo::write");
}
Exiv2::XmpParser::terminate();
return 0;
}
catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
std::string filename(argv[1]);
Exiv2::DataBuf buf = Exiv2::readFile(filename);
std::string xmpPacket;
xmpPacket.assign(buf.c_str(), buf.size());
std::cerr << "-----> Decoding XMP data read from " << filename << " <-----\n";
Exiv2::XmpData xmpData;
if (0 != Exiv2::XmpParser::decode(xmpData, xmpPacket)) {
std::string error(argv[1]);
error += ": Failed to parse file contents (XMP packet)";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
if (xmpData.empty()) {
std::string error(argv[1]);
error += ": No XMP properties found in the XMP packet";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
for (auto&& md : xmpData) {
std::cout << std::setfill(' ') << std::left << std::setw(44) << md.key() << " " << std::setw(9) << std::setfill(' ')
<< std::left << md.typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right
<< md.count() << " " << std::dec << md.toString() << std::endl;
}
filename += "-new";
std::cerr << "-----> Encoding XMP data to write to " << filename << " <-----\n";
if (0 != Exiv2::XmpParser::encode(xmpPacket, xmpData)) {
std::string error(argv[1]);
error += ": Failed to encode the XMP data";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
Exiv2::FileIo file(filename);
if (file.open("wb") != 0) {
throw Exiv2::Error(Exiv2::ErrorCode::kerFileOpenFailed, filename, "wb", Exiv2::strError());
}
if (file.write(reinterpret_cast<const Exiv2::byte*>(xmpPacket.data()), xmpPacket.size()) == 0) {
throw Exiv2::Error(Exiv2::ErrorCode::kerCallFailed, filename, Exiv2::strError(), "FileIo::write");
}
Exiv2::XmpParser::terminate();
return 0;
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}

@ -1,58 +1,51 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Read an XMP from a video or graphic file, parse it and print all (known) properties.
#include <cassert>
#include <exiv2/exiv2.hpp>
#include <string>
#include <iostream>
#include <iomanip>
#include <cassert>
#include <iostream>
#include <string>
int main(int argc, char** argv)
{
int main(int argc, char** argv) {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
try
{
if (argc != 2)
{
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
try {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
auto image = Exiv2::ImageFactory::open(argv[1]);
image->readMetadata();
Exiv2::XmpData &xmpData = image->xmpData();
Exiv2::XmpData& xmpData = image->xmpData();
if (xmpData.empty()) {
std::string error(argv[1]);
error += ": No XMP data found in the file";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
std::string error(argv[1]);
error += ": No XMP data found in the file";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
if (xmpData.empty()) {
std::string error(argv[1]);
error += ": No XMP properties found in the XMP packet";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
for (auto&& md : xmpData) {
std::cout << std::setfill(' ') << std::left << std::setw(44) << md.key() << " " << std::setw(9)
<< std::setfill(' ') << std::left << md.typeName() << " " << std::dec << std::setw(3)
<< std::setfill(' ') << std::right << md.count() << " " << std::dec << md.toString() << std::endl;
}
if (xmpData.empty())
{
std::string error(argv[1]);
error += ": No XMP properties found in the XMP packet";
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, error);
}
for (auto&& md : xmpData) {
std::cout << std::setfill(' ') << std::left << std::setw(44) << md.key() << " " << std::setw(9)
<< std::setfill(' ') << std::left << md.typeName() << " " << std::dec << std::setw(3)
<< std::setfill(' ') << std::right << md.count() << " " << std::dec << md.toString() << std::endl;
}
Exiv2::XmpParser::terminate();
return 0;
}
catch (Exiv2::Error& e)
{
} catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}
}

@ -7,205 +7,203 @@
#include <cmath>
#include <iostream>
bool isEqual(float a, float b)
{
double d = std::fabs(a - b);
return d < 0.00001;
bool isEqual(float a, float b) {
double d = std::fabs(a - b);
return d < 0.00001;
}
int main()
try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int main() try {
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF();
Exiv2::enableBMFF();
#endif
// The XMP property container
Exiv2::XmpData xmpData;
// -------------------------------------------------------------------------
// Teaser: Setting XMP properties doesn't get much easier than this:
xmpData["Xmp.dc.source"] = "xmpsample.cpp"; // a simple text value
xmpData["Xmp.dc.subject"] = "Palmtree"; // an array item
xmpData["Xmp.dc.subject"] = "Rubbertree"; // add a 2nd array item
// a language alternative with two entries and without default
xmpData["Xmp.dc.title"] = "lang=de-DE Sonnenuntergang am Strand";
xmpData["Xmp.dc.title"] = "lang=en-US Sunset on the beach";
// -------------------------------------------------------------------------
// Any properties can be set provided the namespace is known. Values of any
// type can be assigned to an Xmpdatum, if they have an output operator. The
// default XMP value type for unknown properties is a simple text value.
xmpData["Xmp.dc.one"] = -1;
xmpData["Xmp.dc.two"] = 3.1415;
xmpData["Xmp.dc.three"] = Exiv2::Rational(5, 7);
xmpData["Xmp.dc.four"] = uint16_t(255);
xmpData["Xmp.dc.five"] = 256;
xmpData["Xmp.dc.six"] = false;
// In addition, there is a dedicated assignment operator for Exiv2::Value
Exiv2::XmpTextValue val("Seven");
xmpData["Xmp.dc.seven"] = val;
xmpData["Xmp.dc.eight"] = true;
// Extracting values
assert(xmpData["Xmp.dc.one"].toInt64() == -1);
assert(xmpData["Xmp.dc.one"].value().ok());
[[maybe_unused]] const Exiv2::Value &getv1 = xmpData["Xmp.dc.one"].value();
assert(isEqual(getv1.toFloat(), -1));
assert(getv1.ok());
assert(getv1.toRational() == Exiv2::Rational(-1, 1));
assert(getv1.ok());
[[maybe_unused]] const Exiv2::Value &getv2 = xmpData["Xmp.dc.two"].value();
assert(isEqual(getv2.toFloat(), 3.1415f));
assert(getv2.ok());
assert(getv2.toInt64() == 3);
assert(getv2.ok());
[[maybe_unused]] Exiv2::Rational R = getv2.toRational();
assert(getv2.ok());
assert(isEqual(static_cast<float>(R.first) / R.second, 3.1415f ));
[[maybe_unused]] const Exiv2::Value &getv3 = xmpData["Xmp.dc.three"].value();
assert(isEqual(getv3.toFloat(), 5.0f/7.0f));
assert(getv3.ok());
assert(getv3.toInt64() == 0); // long(5.0 / 7.0)
assert(getv3.ok());
assert(getv3.toRational() == Exiv2::Rational(5, 7));
assert(getv3.ok());
[[maybe_unused]] const Exiv2::Value &getv6 = xmpData["Xmp.dc.six"].value();
assert(getv6.toInt64() == 0);
assert(getv6.ok());
assert(getv6.toFloat() == 0.0f);
assert(getv6.ok());
assert(getv6.toRational() == Exiv2::Rational(0, 1));
assert(getv6.ok());
const Exiv2::Value &getv7 = xmpData["Xmp.dc.seven"].value();
getv7.toInt64(); // this should fail
assert(!getv7.ok());
[[maybe_unused]] const Exiv2::Value &getv8 = xmpData["Xmp.dc.eight"].value();
assert(getv8.toInt64() == 1);
assert(getv8.ok());
assert(getv8.toFloat() == 1.0f);
assert(getv8.ok());
assert(getv8.toRational() == Exiv2::Rational(1, 1));
assert(getv8.ok());
// Deleting an XMP property
auto pos = xmpData.findKey(Exiv2::XmpKey("Xmp.dc.eight"));
if (pos == xmpData.end()) throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Key not found");
xmpData.erase(pos);
// -------------------------------------------------------------------------
// Exiv2 has specialized values for simple XMP properties, arrays of simple
// properties and language alternatives.
// Add a simple XMP property in a known namespace
auto v = Exiv2::Value::create(Exiv2::xmpText);
v->read("image/jpeg");
xmpData.add(Exiv2::XmpKey("Xmp.dc.format"), v.get());
// Add an ordered array of text values.
v = Exiv2::Value::create(Exiv2::xmpSeq); // or xmpBag or xmpAlt.
v->read("1) The first creator"); // The sequence in which the array
v->read("2) The second creator"); // elements are added is their
v->read("3) And another one"); // order in the array.
xmpData.add(Exiv2::XmpKey("Xmp.dc.creator"), v.get());
// Add a language alternative property
v = Exiv2::Value::create(Exiv2::langAlt);
v->read("lang=de-DE Hallo, Welt"); // The default doesn't need a
v->read("Hello, World"); // qualifier
xmpData.add(Exiv2::XmpKey("Xmp.dc.description"), v.get());
// According to the XMP specification, Xmp.tiff.ImageDescription is an
// alias for Xmp.dc.description. Exiv2 treats an alias just like any
// other property and leaves it to the application to implement specific
// behaviour if desired.
xmpData["Xmp.tiff.ImageDescription"] = "TIFF image description";
xmpData["Xmp.tiff.ImageDescription"] = "lang=de-DE TIFF Bildbeschreibung";
// -------------------------------------------------------------------------
// Register a namespace which Exiv2 doesn't know yet. This is only needed
// when properties are added manually. If the XMP metadata is read from an
// image, namespaces are decoded and registered at the same time.
Exiv2::XmpProperties::registerNs("myNamespace/", "ns");
// -------------------------------------------------------------------------
// Add a property in the new custom namespace.
xmpData["Xmp.ns.myProperty"] = "myValue";
// -------------------------------------------------------------------------
// There are no specialized values for structures, qualifiers and nested
// types. However, these can be added by using an XmpTextValue and a path as
// the key.
// Add a structure
Exiv2::XmpTextValue tv("16");
xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:w"), &tv);
tv.read("9");
xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:h"), &tv);
tv.read("inch");
xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:unit"), &tv);
// Add an element with a qualifier (using the namespace registered above)
xmpData["Xmp.dc.publisher"] = "James Bond"; // creates an unordered array
xmpData["Xmp.dc.publisher[1]/?ns:role"] = "secret agent";
// Add a qualifier to an array element of Xmp.dc.creator (added above)
tv.read("programmer");
xmpData.add(Exiv2::XmpKey("Xmp.dc.creator[2]/?ns:role"), &tv);
// Add an array of structures
tv.read(""); // Clear the value
tv.setXmpArrayType(Exiv2::XmpValue::xaBag);
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef"), &tv); // Set the array type.
tv.setXmpArrayType(Exiv2::XmpValue::xaNone);
tv.read("Birthday party");
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[1]/stJob:name"), &tv);
tv.read("Photographer");
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[1]/stJob:role"), &tv);
tv.read("Wedding ceremony");
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[2]/stJob:name"), &tv);
tv.read("Best man");
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[2]/stJob:role"), &tv);
// Add a creator contact info structure
xmpData["Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrCity"] = "Kuala Lumpur";
xmpData["Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrCtry"] = "Malaysia";
xmpData["Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiUrlWork"] = "http://www.exiv2.org";
// -------------------------------------------------------------------------
// Output XMP properties
for (auto &&md : xmpData) {
std::cout << std::setfill(' ') << std::left << std::setw(44) << md.key() << " " << std::setw(9)
<< std::setfill(' ') << std::left << md.typeName() << " " << std::dec << std::setw(3)
<< std::setfill(' ') << std::right << md.count() << " " << std::dec << md.value() << std::endl;
}
// -------------------------------------------------------------------------
// Serialize the XMP data and output the XMP packet
std::string xmpPacket;
if (0 != Exiv2::XmpParser::encode(xmpPacket, xmpData)) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Failed to serialize XMP data");
}
std::cout << xmpPacket << "\n";
// Cleanup
Exiv2::XmpParser::terminate();
return 0;
}
catch (Exiv2::Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
// The XMP property container
Exiv2::XmpData xmpData;
// -------------------------------------------------------------------------
// Teaser: Setting XMP properties doesn't get much easier than this:
xmpData["Xmp.dc.source"] = "xmpsample.cpp"; // a simple text value
xmpData["Xmp.dc.subject"] = "Palmtree"; // an array item
xmpData["Xmp.dc.subject"] = "Rubbertree"; // add a 2nd array item
// a language alternative with two entries and without default
xmpData["Xmp.dc.title"] = "lang=de-DE Sonnenuntergang am Strand";
xmpData["Xmp.dc.title"] = "lang=en-US Sunset on the beach";
// -------------------------------------------------------------------------
// Any properties can be set provided the namespace is known. Values of any
// type can be assigned to an Xmpdatum, if they have an output operator. The
// default XMP value type for unknown properties is a simple text value.
xmpData["Xmp.dc.one"] = -1;
xmpData["Xmp.dc.two"] = 3.1415;
xmpData["Xmp.dc.three"] = Exiv2::Rational(5, 7);
xmpData["Xmp.dc.four"] = uint16_t(255);
xmpData["Xmp.dc.five"] = 256;
xmpData["Xmp.dc.six"] = false;
// In addition, there is a dedicated assignment operator for Exiv2::Value
Exiv2::XmpTextValue val("Seven");
xmpData["Xmp.dc.seven"] = val;
xmpData["Xmp.dc.eight"] = true;
// Extracting values
assert(xmpData["Xmp.dc.one"].toInt64() == -1);
assert(xmpData["Xmp.dc.one"].value().ok());
[[maybe_unused]] const Exiv2::Value &getv1 = xmpData["Xmp.dc.one"].value();
assert(isEqual(getv1.toFloat(), -1));
assert(getv1.ok());
assert(getv1.toRational() == Exiv2::Rational(-1, 1));
assert(getv1.ok());
[[maybe_unused]] const Exiv2::Value &getv2 = xmpData["Xmp.dc.two"].value();
assert(isEqual(getv2.toFloat(), 3.1415f));
assert(getv2.ok());
assert(getv2.toInt64() == 3);
assert(getv2.ok());
[[maybe_unused]] Exiv2::Rational R = getv2.toRational();
assert(getv2.ok());
assert(isEqual(static_cast<float>(R.first) / R.second, 3.1415f));
[[maybe_unused]] const Exiv2::Value &getv3 = xmpData["Xmp.dc.three"].value();
assert(isEqual(getv3.toFloat(), 5.0f / 7.0f));
assert(getv3.ok());
assert(getv3.toInt64() == 0); // long(5.0 / 7.0)
assert(getv3.ok());
assert(getv3.toRational() == Exiv2::Rational(5, 7));
assert(getv3.ok());
[[maybe_unused]] const Exiv2::Value &getv6 = xmpData["Xmp.dc.six"].value();
assert(getv6.toInt64() == 0);
assert(getv6.ok());
assert(getv6.toFloat() == 0.0f);
assert(getv6.ok());
assert(getv6.toRational() == Exiv2::Rational(0, 1));
assert(getv6.ok());
const Exiv2::Value &getv7 = xmpData["Xmp.dc.seven"].value();
getv7.toInt64(); // this should fail
assert(!getv7.ok());
[[maybe_unused]] const Exiv2::Value &getv8 = xmpData["Xmp.dc.eight"].value();
assert(getv8.toInt64() == 1);
assert(getv8.ok());
assert(getv8.toFloat() == 1.0f);
assert(getv8.ok());
assert(getv8.toRational() == Exiv2::Rational(1, 1));
assert(getv8.ok());
// Deleting an XMP property
auto pos = xmpData.findKey(Exiv2::XmpKey("Xmp.dc.eight"));
if (pos == xmpData.end())
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Key not found");
xmpData.erase(pos);
// -------------------------------------------------------------------------
// Exiv2 has specialized values for simple XMP properties, arrays of simple
// properties and language alternatives.
// Add a simple XMP property in a known namespace
auto v = Exiv2::Value::create(Exiv2::xmpText);
v->read("image/jpeg");
xmpData.add(Exiv2::XmpKey("Xmp.dc.format"), v.get());
// Add an ordered array of text values.
v = Exiv2::Value::create(Exiv2::xmpSeq); // or xmpBag or xmpAlt.
v->read("1) The first creator"); // The sequence in which the array
v->read("2) The second creator"); // elements are added is their
v->read("3) And another one"); // order in the array.
xmpData.add(Exiv2::XmpKey("Xmp.dc.creator"), v.get());
// Add a language alternative property
v = Exiv2::Value::create(Exiv2::langAlt);
v->read("lang=de-DE Hallo, Welt"); // The default doesn't need a
v->read("Hello, World"); // qualifier
xmpData.add(Exiv2::XmpKey("Xmp.dc.description"), v.get());
// According to the XMP specification, Xmp.tiff.ImageDescription is an
// alias for Xmp.dc.description. Exiv2 treats an alias just like any
// other property and leaves it to the application to implement specific
// behaviour if desired.
xmpData["Xmp.tiff.ImageDescription"] = "TIFF image description";
xmpData["Xmp.tiff.ImageDescription"] = "lang=de-DE TIFF Bildbeschreibung";
// -------------------------------------------------------------------------
// Register a namespace which Exiv2 doesn't know yet. This is only needed
// when properties are added manually. If the XMP metadata is read from an
// image, namespaces are decoded and registered at the same time.
Exiv2::XmpProperties::registerNs("myNamespace/", "ns");
// -------------------------------------------------------------------------
// Add a property in the new custom namespace.
xmpData["Xmp.ns.myProperty"] = "myValue";
// -------------------------------------------------------------------------
// There are no specialized values for structures, qualifiers and nested
// types. However, these can be added by using an XmpTextValue and a path as
// the key.
// Add a structure
Exiv2::XmpTextValue tv("16");
xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:w"), &tv);
tv.read("9");
xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:h"), &tv);
tv.read("inch");
xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:unit"), &tv);
// Add an element with a qualifier (using the namespace registered above)
xmpData["Xmp.dc.publisher"] = "James Bond"; // creates an unordered array
xmpData["Xmp.dc.publisher[1]/?ns:role"] = "secret agent";
// Add a qualifier to an array element of Xmp.dc.creator (added above)
tv.read("programmer");
xmpData.add(Exiv2::XmpKey("Xmp.dc.creator[2]/?ns:role"), &tv);
// Add an array of structures
tv.read(""); // Clear the value
tv.setXmpArrayType(Exiv2::XmpValue::xaBag);
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef"), &tv); // Set the array type.
tv.setXmpArrayType(Exiv2::XmpValue::xaNone);
tv.read("Birthday party");
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[1]/stJob:name"), &tv);
tv.read("Photographer");
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[1]/stJob:role"), &tv);
tv.read("Wedding ceremony");
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[2]/stJob:name"), &tv);
tv.read("Best man");
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[2]/stJob:role"), &tv);
// Add a creator contact info structure
xmpData["Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrCity"] = "Kuala Lumpur";
xmpData["Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrCtry"] = "Malaysia";
xmpData["Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiUrlWork"] = "http://www.exiv2.org";
// -------------------------------------------------------------------------
// Output XMP properties
for (auto &&md : xmpData) {
std::cout << std::setfill(' ') << std::left << std::setw(44) << md.key() << " " << std::setw(9) << std::setfill(' ')
<< std::left << md.typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right
<< md.count() << " " << std::dec << md.value() << std::endl;
}
// -------------------------------------------------------------------------
// Serialize the XMP data and output the XMP packet
std::string xmpPacket;
if (0 != Exiv2::XmpParser::encode(xmpPacket, xmpData)) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Failed to serialize XMP data");
}
std::cout << xmpPacket << "\n";
// Cleanup
Exiv2::XmpParser::terminate();
return 0;
} catch (Exiv2::Error &e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -5,122 +5,110 @@
History: 05-Mar-2007, marco: created
*/
#include "basicio.hpp"
#include "bmpimage.hpp"
#include "basicio.hpp"
#include "error.hpp"
#include "futils.hpp"
#include "image.hpp"
// + standard includes
#include <cstring>
#include <string>
#include <iostream>
#include <string>
// *****************************************************************************
// class member definitions
namespace Exiv2
{
BmpImage::BmpImage(BasicIo::UniquePtr io) : Image(ImageType::bmp, mdNone, std::move(io))
{
}
namespace Exiv2 {
BmpImage::BmpImage(BasicIo::UniquePtr io) : Image(ImageType::bmp, mdNone, std::move(io)) {
}
std::string BmpImage::mimeType() const
{
// "image/bmp" is a Generic Bitmap
return "image/x-ms-bmp"; // Microsoft Bitmap
}
std::string BmpImage::mimeType() const {
// "image/bmp" is a Generic Bitmap
return "image/x-ms-bmp"; // Microsoft Bitmap
}
void BmpImage::setExifData(const ExifData& /*exifData*/)
{
throw(Error(ErrorCode::kerInvalidSettingForImage, "Exif metadata", "BMP"));
}
void BmpImage::setExifData(const ExifData& /*exifData*/) {
throw(Error(ErrorCode::kerInvalidSettingForImage, "Exif metadata", "BMP"));
}
void BmpImage::setIptcData(const IptcData& /*iptcData*/)
{
throw(Error(ErrorCode::kerInvalidSettingForImage, "IPTC metadata", "BMP"));
}
void BmpImage::setIptcData(const IptcData& /*iptcData*/) {
throw(Error(ErrorCode::kerInvalidSettingForImage, "IPTC metadata", "BMP"));
}
void BmpImage::setComment(std::string_view /*comment*/)
{
throw(Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "BMP"));
}
void BmpImage::setComment(std::string_view /*comment*/) {
throw(Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "BMP"));
}
void BmpImage::readMetadata()
{
void BmpImage::readMetadata() {
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "Exiv2::BmpImage::readMetadata: Reading Windows bitmap file " << io_->path() << "\n";
std::cerr << "Exiv2::BmpImage::readMetadata: Reading Windows bitmap file " << io_->path() << "\n";
#endif
if (io_->open() != 0) {
throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError());
}
IoCloser closer(*io_);
if (io_->open() != 0) {
throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError());
}
IoCloser closer(*io_);
// Ensure that this is the correct image type
if (!isBmpType(*io_, false)) {
if (io_->error() || io_->eof())
throw Error(ErrorCode::kerFailedToReadImageData);
throw Error(ErrorCode::kerNotAnImage, "BMP");
}
clearMetadata();
// Ensure that this is the correct image type
if (!isBmpType(*io_, false)) {
if (io_->error() || io_->eof())
throw Error(ErrorCode::kerFailedToReadImageData);
throw Error(ErrorCode::kerNotAnImage, "BMP");
}
clearMetadata();
/*
The Windows bitmap header goes as follows -- all numbers are in little-endian byte order:
/*
The Windows bitmap header goes as follows -- all numbers are in little-endian byte order:
offset length name description
====== ======= ===================== =======
0 2 bytes signature always 'BM'
2 4 bytes bitmap size
6 4 bytes reserved
10 4 bytes bitmap offset
14 4 bytes header size
18 4 bytes bitmap width
22 4 bytes bitmap height
26 2 bytes plane count
28 2 bytes depth
30 4 bytes compression 0 = none; 1 = RLE, 8 bits/pixel; 2 = RLE, 4 bits/pixel; 3 = bitfield; 4 = JPEG; 5 = PNG
34 4 bytes image size size of the raw bitmap data, in bytes
38 4 bytes horizontal resolution (in pixels per meter)
42 4 bytes vertical resolution (in pixels per meter)
46 4 bytes color count
50 4 bytes important colors number of "important" colors
*/
byte buf[26];
if (io_->read(buf, sizeof(buf)) == sizeof(buf)) {
pixelWidth_ = getLong(buf + 18, littleEndian);
pixelHeight_ = getLong(buf + 22, littleEndian);
}
}
offset length name description
====== ======= ===================== =======
0 2 bytes signature always 'BM'
2 4 bytes bitmap size
6 4 bytes reserved
10 4 bytes bitmap offset
14 4 bytes header size
18 4 bytes bitmap width
22 4 bytes bitmap height
26 2 bytes plane count
28 2 bytes depth
30 4 bytes compression 0 = none; 1 = RLE, 8 bits/pixel; 2 = RLE, 4 bits/pixel; 3 = bitfield;
4 = JPEG; 5 = PNG 34 4 bytes image size size of the raw bitmap data, in bytes 38 4
bytes horizontal resolution (in pixels per meter) 42 4 bytes vertical resolution (in pixels per
meter) 46 4 bytes color count 50 4 bytes important colors number of "important" colors
*/
byte buf[26];
if (io_->read(buf, sizeof(buf)) == sizeof(buf)) {
pixelWidth_ = getLong(buf + 18, littleEndian);
pixelHeight_ = getLong(buf + 22, littleEndian);
}
}
void BmpImage::writeMetadata()
{
/// \todo implement me!
throw(Error(ErrorCode::kerWritingImageFormatUnsupported, "BMP"));
}
void BmpImage::writeMetadata() {
/// \todo implement me!
throw(Error(ErrorCode::kerWritingImageFormatUnsupported, "BMP"));
}
// *************************************************************************
// free functions
Image::UniquePtr newBmpInstance(BasicIo::UniquePtr io, bool /*create*/)
{
auto image = std::make_unique<BmpImage>(std::move(io));
if (!image->good()) {
image.reset();
}
return image;
}
// *************************************************************************
// free functions
Image::UniquePtr newBmpInstance(BasicIo::UniquePtr io, bool /*create*/) {
auto image = std::make_unique<BmpImage>(std::move(io));
if (!image->good()) {
image.reset();
}
return image;
}
bool isBmpType(BasicIo& iIo, bool advance)
{
const int32_t len = 2;
const unsigned char BmpImageId[2] = {'B', 'M'};
byte buf[len];
iIo.read(buf, len);
if (iIo.error() || iIo.eof()) {
return false;
}
bool matched = (memcmp(buf, BmpImageId, len) == 0);
if (!advance || !matched) {
iIo.seek(-len, BasicIo::cur);
}
return matched;
}
bool isBmpType(BasicIo& iIo, bool advance) {
const int32_t len = 2;
const unsigned char BmpImageId[2] = {'B', 'M'};
byte buf[len];
iIo.read(buf, len);
if (iIo.error() || iIo.eof()) {
return false;
}
bool matched = (memcmp(buf, BmpImageId, len) == 0);
if (!advance || !matched) {
iIo.seek(-len, BasicIo::cur);
}
return matched;
}
} // namespace Exiv2

File diff suppressed because it is too large Load Diff

@ -3,7 +3,8 @@
@file canonmn_int.hpp
@brief Canon makernote tags.<BR>References:<BR>
[1] <a href="http://www.burren.cx/david/canon.html">EXIF MakerNote of Canon</a> by David Burren<br>
[2] <a href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html">Canon makernote tags</a> by Phil Harvey
[2] <a href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html">Canon makernote tags</a> by
Phil Harvey
@author <a href="mailto:ahuggel@gmx.net">Andreas Huggel (ahu)</a><br>
<a href="mailto:david@edeca.net">David Cannings (dc)</a>
<a href="mailto:andi.clemens@gmx.net">Andi Clemens (ac)</a>
@ -21,187 +22,183 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2::Internal {
// *****************************************************************************
// class definitions
// *****************************************************************************
// class definitions
//! MakerNote for Canon cameras
class CanonMakerNote {
public:
//! Return read-only list of built-in Canon tags
static const TagInfo* tagList();
//! Return read-only list of built-in Canon Camera Settings tags
static const TagInfo* tagListCs();
//! Return read-only list of built-in Canon Shot Info tags
static const TagInfo* tagListSi();
//! Return read-only list of built-in Canon Panorama tags
static const TagInfo* tagListPa();
//! Return read-only list of built-in Canon Custom Function tags
static const TagInfo* tagListCf();
//! Return read-only list of built-in Canon Picture Info tags
static const TagInfo* tagListPi();
//! Return read-only list of built-in Canon Time Info tags
static const TagInfo* tagListTi();
//! Return read-only list of built-in Canon File Info tags
static const TagInfo* tagListFi();
//! Return read-only list of built-in Canon Processing Info tags
static const TagInfo* tagListPr();
//! Return read-only list of built-in Canon Movie Info tags
static const TagInfo* tagListMv();
//! Return read-only list of built-in Canon My Colors Info tags
static const TagInfo* tagListMc();
//! Return read-only list of built-in Canon Face detection Info tags
static const TagInfo* tagListFcd3();
//! Return read-only list of built-in Canon White balance Info tags
static const TagInfo* tagListWbi();
//! Return read-only list of built-in Canon Contrast Info tags
static const TagInfo* tagListCo();
//! Return read-only list of built-in Canon Face detection 1 Info tags
static const TagInfo* tagListFcd2();
//! Return read-only list of built-in Canon Face detection 2 Info tags
static const TagInfo* tagListFcd1();
//! Return read-only list of built-in Canon Aspect Info tags
static const TagInfo* tagListAs();
//! Return read-only list of built-in Canon Balance Info tags
static const TagInfo* tagListCbi();
//! Return read-only list of built-in Canon Flags Info tags
static const TagInfo* tagListFl();
//! Return read-only list of built-in Canon Modified On Info tags
static const TagInfo* tagListMo();
//! Return read-only list of built-in Canon Preview Image Info tags
static const TagInfo* tagListPreI();
//! Return read-only list of built-in Canon Color Info tags
static const TagInfo* tagListCi();
//! Return read-only list of built-in Canon AFMicroAdjMode Quality Info tags
static const TagInfo* tagListAfMiAdj();
//! Return read-only list of built-in Canon VignettingCorr Info tags
static const TagInfo* tagListVigCor();
//! Return read-only list of built-in Canon VignettingCorr2 Info tags
static const TagInfo* tagListVigCor2();
//! Return read-only list of built-in Canon LightingOpt Info tags
static const TagInfo* tagListLiOp();
//! Return read-only list of built-in Canon LensInfo Info tags
static const TagInfo* tagListLe();
//! Return read-only list of built-in Canon Ambience Info tags
static const TagInfo* tagListAm();
//! Return read-only list of built-in Canon MultiExposureControl Info tags
static const TagInfo* tagListMe();
//! Return read-only list of built-in Canon Filter Info tags
static const TagInfo* tagListFil();
//! Return read-only list of built-in Canon HDR Info tags
static const TagInfo* tagListHdr();
//! Return read-only list of built-in Canon AFConfig Info tags
static const TagInfo* tagListAfC();
//! Return read-only list of built-in Canon RawBurstInfo Info tags
static const TagInfo* tagListRawB();
//! MakerNote for Canon cameras
class CanonMakerNote {
public:
//! Return read-only list of built-in Canon tags
static const TagInfo* tagList();
//! Return read-only list of built-in Canon Camera Settings tags
static const TagInfo* tagListCs();
//! Return read-only list of built-in Canon Shot Info tags
static const TagInfo* tagListSi();
//! Return read-only list of built-in Canon Panorama tags
static const TagInfo* tagListPa();
//! Return read-only list of built-in Canon Custom Function tags
static const TagInfo* tagListCf();
//! Return read-only list of built-in Canon Picture Info tags
static const TagInfo* tagListPi();
//! Return read-only list of built-in Canon Time Info tags
static const TagInfo* tagListTi();
//! Return read-only list of built-in Canon File Info tags
static const TagInfo* tagListFi();
//! Return read-only list of built-in Canon Processing Info tags
static const TagInfo* tagListPr();
//! Return read-only list of built-in Canon Movie Info tags
static const TagInfo* tagListMv();
//! Return read-only list of built-in Canon My Colors Info tags
static const TagInfo* tagListMc();
//! Return read-only list of built-in Canon Face detection Info tags
static const TagInfo* tagListFcd3();
//! Return read-only list of built-in Canon White balance Info tags
static const TagInfo* tagListWbi();
//! Return read-only list of built-in Canon Contrast Info tags
static const TagInfo* tagListCo();
//! Return read-only list of built-in Canon Face detection 1 Info tags
static const TagInfo* tagListFcd2();
//! Return read-only list of built-in Canon Face detection 2 Info tags
static const TagInfo* tagListFcd1();
//! Return read-only list of built-in Canon Aspect Info tags
static const TagInfo* tagListAs();
//! Return read-only list of built-in Canon Balance Info tags
static const TagInfo* tagListCbi();
//! Return read-only list of built-in Canon Flags Info tags
static const TagInfo* tagListFl();
//! Return read-only list of built-in Canon Modified On Info tags
static const TagInfo* tagListMo();
//! Return read-only list of built-in Canon Preview Image Info tags
static const TagInfo* tagListPreI();
//! Return read-only list of built-in Canon Color Info tags
static const TagInfo* tagListCi();
//! Return read-only list of built-in Canon AFMicroAdjMode Quality Info tags
static const TagInfo* tagListAfMiAdj();
//! Return read-only list of built-in Canon VignettingCorr Info tags
static const TagInfo* tagListVigCor();
//! Return read-only list of built-in Canon VignettingCorr2 Info tags
static const TagInfo* tagListVigCor2();
//! Return read-only list of built-in Canon LightingOpt Info tags
static const TagInfo* tagListLiOp();
//! Return read-only list of built-in Canon LensInfo Info tags
static const TagInfo* tagListLe();
//! Return read-only list of built-in Canon Ambience Info tags
static const TagInfo* tagListAm();
//! Return read-only list of built-in Canon MultiExposureControl Info tags
static const TagInfo* tagListMe();
//! Return read-only list of built-in Canon Filter Info tags
static const TagInfo* tagListFil();
//! Return read-only list of built-in Canon HDR Info tags
static const TagInfo* tagListHdr();
//! Return read-only list of built-in Canon AFConfig Info tags
static const TagInfo* tagListAfC();
//! Return read-only list of built-in Canon RawBurstInfo Info tags
static const TagInfo* tagListRawB();
//! @name Print functions for Canon %MakerNote tags
//@{
//! Print the FileInfo FileNumber
static std::ostream& printFiFileNumber(std::ostream& os, const Value& value, const ExifData* metadata);
//! Print the focal length
static std::ostream& printFocalLength(std::ostream& os, const Value& value, const ExifData*);
//! Print the image number
static std::ostream& print0x0008(std::ostream& os, const Value& value, const ExifData*);
//! Print the serial number of the camera
static std::ostream& print0x000c(std::ostream& os, const Value& value, const ExifData*);
//! Self timer
static std::ostream& printCs0x0002(std::ostream& os, const Value& value, const ExifData*);
//! Camera lens type. For some values, the exact type can only be determined if \em metadata is provided.
static std::ostream& printCsLensType(std::ostream& os, const Value& value, const ExifData* metadata);
//! Camera lens information
static std::ostream& printCsLens(std::ostream& os, const Value& value, const ExifData*);
//! AutoISO speed used
static std::ostream& printSi0x0001(std::ostream& os, const Value& value, const ExifData*);
//! ISO speed used
static std::ostream& printSi0x0002(std::ostream& os, const Value& value, const ExifData*);
//! MeasuredEV
static std::ostream& printSi0x0003(std::ostream& os, const Value& value, const ExifData*);
//! Sequence number
static std::ostream& printSi0x0009(std::ostream& os, const Value& value, const ExifData*);
//! Ambient Temperature
static std::ostream& printSi0x000c(std::ostream& os, const Value& value, const ExifData*);
//! Flash Guide Number
static std::ostream& printSi0x000d(std::ostream& os, const Value& value, const ExifData*);
//! AF point used
static std::ostream& printSi0x000e(std::ostream& os, const Value& value, const ExifData* pExifData);
//! Subject distance
static std::ostream& printSi0x0013(std::ostream& os, const Value& value, const ExifData*);
//! Aperture
static std::ostream& printSi0x0015(std::ostream& os, const Value& value, const ExifData*);
//! Shutter speed
static std::ostream& printSi0x0016(std::ostream& os, const Value& value, const ExifData*);
//! MeasuredEV2
static std::ostream& printSi0x0017(std::ostream& os, const Value& value, const ExifData*);
//! Bulb Duration
static std::ostream& printSi0x0018(std::ostream& os, const Value& value, const ExifData*);
//! Focus Distance
static std::ostream& printFiFocusDistance(std::ostream& os, const Value& value, const ExifData*);
//@}
//! @name Print functions for Canon %MakerNote tags
//@{
//! Print the FileInfo FileNumber
static std::ostream& printFiFileNumber(std::ostream& os, const Value& value, const ExifData* metadata);
//! Print the focal length
static std::ostream& printFocalLength(std::ostream& os, const Value& value, const ExifData*);
//! Print the image number
static std::ostream& print0x0008(std::ostream& os, const Value& value, const ExifData*);
//! Print the serial number of the camera
static std::ostream& print0x000c(std::ostream& os, const Value& value, const ExifData*);
//! Self timer
static std::ostream& printCs0x0002(std::ostream& os, const Value& value, const ExifData*);
//! Camera lens type. For some values, the exact type can only be determined if \em metadata is provided.
static std::ostream& printCsLensType(std::ostream& os, const Value& value, const ExifData* metadata);
//! Camera lens information
static std::ostream& printCsLens(std::ostream& os, const Value& value, const ExifData*);
//! AutoISO speed used
static std::ostream& printSi0x0001(std::ostream& os, const Value& value, const ExifData*);
//! ISO speed used
static std::ostream& printSi0x0002(std::ostream& os, const Value& value, const ExifData*);
//! MeasuredEV
static std::ostream& printSi0x0003(std::ostream& os, const Value& value, const ExifData*);
//! Sequence number
static std::ostream& printSi0x0009(std::ostream& os, const Value& value, const ExifData*);
//! Ambient Temperature
static std::ostream& printSi0x000c(std::ostream& os, const Value& value, const ExifData*);
//! Flash Guide Number
static std::ostream& printSi0x000d(std::ostream& os, const Value& value, const ExifData*);
//! AF point used
static std::ostream& printSi0x000e(std::ostream& os, const Value& value, const ExifData* pExifData);
//! Subject distance
static std::ostream& printSi0x0013(std::ostream& os, const Value& value, const ExifData*);
//! Aperture
static std::ostream& printSi0x0015(std::ostream& os, const Value& value, const ExifData*);
//! Shutter speed
static std::ostream& printSi0x0016(std::ostream& os, const Value& value, const ExifData*);
//! MeasuredEV2
static std::ostream& printSi0x0017(std::ostream& os, const Value& value, const ExifData*);
//! Bulb Duration
static std::ostream& printSi0x0018(std::ostream& os, const Value& value, const ExifData*);
//! Focus Distance
static std::ostream& printFiFocusDistance(std::ostream& os, const Value& value, const ExifData*);
//@}
private:
// DATA
private:
// DATA
//! Tag information
static const TagInfo tagInfo_[];
static const TagInfo tagInfoAfC_[];
static const TagInfo tagInfoAfMiAdj_[];
static const TagInfo tagInfoAm_[];
static const TagInfo tagInfoAs_[];
static const TagInfo tagInfoCs_[];
static const TagInfo tagInfoCbi_[];
static const TagInfo tagInfoSi_[];
static const TagInfo tagInfoCf_[];
static const TagInfo tagInfoCi_[];
static const TagInfo tagInfoCo_[];
static const TagInfo tagInfoFl_[];
static const TagInfo tagInfoFil_[];
static const TagInfo tagInfoLiOp_[];
static const TagInfo tagInfoLe_[];
static const TagInfo tagInfoHdr_[];
static const TagInfo tagInfoMe_[];
static const TagInfo tagInfoMo_[];
static const TagInfo tagInfoMv_[];
static const TagInfo tagInfoMc_[];
static const TagInfo tagInfoFcd1_[];
static const TagInfo tagInfoFcd2_[];
static const TagInfo tagInfoFcd3_[];
static const TagInfo tagInfoPi_[];
static const TagInfo tagInfoTi_[];
static const TagInfo tagInfoFi_[];
static const TagInfo tagInfoPa_[];
static const TagInfo tagInfoPr_[];
static const TagInfo tagInfoPreI_[];
static const TagInfo tagInfoVigCor_[];
static const TagInfo tagInfoVigCor2_[];
static const TagInfo tagInfoWbi_[];
static const TagInfo tagInfoRawB_ [];
//! Tag information
static const TagInfo tagInfo_[];
static const TagInfo tagInfoAfC_[];
static const TagInfo tagInfoAfMiAdj_[];
static const TagInfo tagInfoAm_[];
static const TagInfo tagInfoAs_[];
static const TagInfo tagInfoCs_[];
static const TagInfo tagInfoCbi_[];
static const TagInfo tagInfoSi_[];
static const TagInfo tagInfoCf_[];
static const TagInfo tagInfoCi_[];
static const TagInfo tagInfoCo_[];
static const TagInfo tagInfoFl_[];
static const TagInfo tagInfoFil_[];
static const TagInfo tagInfoLiOp_[];
static const TagInfo tagInfoLe_[];
static const TagInfo tagInfoHdr_[];
static const TagInfo tagInfoMe_[];
static const TagInfo tagInfoMo_[];
static const TagInfo tagInfoMv_[];
static const TagInfo tagInfoMc_[];
static const TagInfo tagInfoFcd1_[];
static const TagInfo tagInfoFcd2_[];
static const TagInfo tagInfoFcd3_[];
static const TagInfo tagInfoPi_[];
static const TagInfo tagInfoTi_[];
static const TagInfo tagInfoFi_[];
static const TagInfo tagInfoPa_[];
static const TagInfo tagInfoPr_[];
static const TagInfo tagInfoPreI_[];
static const TagInfo tagInfoVigCor_[];
static const TagInfo tagInfoVigCor2_[];
static const TagInfo tagInfoWbi_[];
static const TagInfo tagInfoRawB_[];
}; // class CanonMakerNote
}; // class CanonMakerNote
// *****************************************************************************
// template, inline and free functions
/*!
@brief Convert Canon hex-based EV (modulo 0x20) to real number
Ported from Phil Harvey's Image::ExifTool::Canon::CanonEv
by Will Stokes
/*!
@brief Convert Canon hex-based EV (modulo 0x20) to real number
Ported from Phil Harvey's Image::ExifTool::Canon::CanonEv
by Will Stokes
0x00 -> 0
0x0c -> 0.33333
0x10 -> 0.5
0x14 -> 0.66666
0x20 -> 1
..
160 -> 5
128 -> 4
143 -> 4.46875
*/
float canonEv(int64_t val);
0x00 -> 0
0x0c -> 0.33333
0x10 -> 0.5
0x14 -> 0.66666
0x20 -> 1
..
160 -> 5
128 -> 4
143 -> 4.46875
*/
float canonEv(int64_t val);
} // namespace Exiv2::Internal
#endif // #ifndef CANONMN_INT_HPP_
#endif // #ifndef CANONMN_INT_HPP_

@ -5,571 +5,413 @@
Credits: See header file
*/
// included header files
#include "types.hpp"
#include "casiomn_int.hpp"
#include "i18n.h" // NLS support.
#include "tags_int.hpp"
#include "types.hpp"
#include "value.hpp"
#include "i18n.h" // NLS support.
// + standard includes
#include <sstream>
#include <iomanip>
#include <cstring>
#include <iomanip>
#include <sstream>
#include <vector>
// *****************************************************************************
// class member definitions
namespace Exiv2::Internal {
//! RecordingMode, tag 0x0001
constexpr TagDetails casioRecordingMode[] = {
{ 1, N_("Single Shutter") },
{ 2, N_("Panorama") },
{ 3, N_("Night Scene") },
{ 4, N_("Portrait") },
{ 5, N_("Landscape") },
{ 7, N_("Panorama") },
{ 10, N_("Night Scene") },
{ 15, N_("Portrait") },
{ 16, N_("Landscape") }
};
//! Quality, tag 0x0002
constexpr TagDetails casioQuality[] = {
{ 1, N_("Economy") },
{ 2, N_("Normal") },
{ 3, N_("Fine") }
};
//! Focus Mode, tag 0x0003
constexpr TagDetails casioFocusMode[] = {
{ 2, N_("Macro") },
{ 3, N_("Auto") },
{ 4, N_("Manual") },
{ 5, N_("Infinity") },
{ 7, N_("Sport AF") }
};
//! FlashMode, tag 0x0004
constexpr TagDetails casioFlashMode[] = {
{ 1, N_("Auto") },
{ 2, N_("On") },
{ 3, N_("Off") },
{ 4, N_("Off") },
{ 5, N_("Red-eye Reduction") }
};
//! Flash intensity, tag 0x0005
constexpr TagDetails casioFlashIntensity[] = {
{ 11, N_("Weak") },
{ 12, N_("Low") },
{ 13, N_("Normal") },
{ 14, N_("High") },
{ 15, N_("Strong") }
};
//! white balance, tag 0x0007
constexpr TagDetails casioWhiteBalance[] = {
{ 1, N_("Auto") },
{ 2, N_("Tungsten") },
{ 3, N_("Daylight") },
{ 4, N_("Fluorescent") },
{ 5, N_("Shade") },
{ 129, N_("Manual") }
};
//! Flash intensity, tag 0x0005
constexpr TagDetails casioDigitalZoom[] = {
{ 0x10000, N_("Off") },
{ 0x10001, N_("2x") },
{ 0x13333, N_("1.2x") },
{ 0x13ae1, N_("1.23x") },
{ 0x19999, N_("1.6x") },
{ 0x20000, N_("2x") },
{ 0x33333, N_("3.2x") },
{ 0x40000, N_("4x") }
};
//! Sharpness, tag 0x000b
constexpr TagDetails casioSharpness[] = {
{ 0, N_("Normal") },
{ 1, N_("Soft") },
{ 2, N_("Hard") },
{ 16, N_("Normal") },
{ 17, N_("+1") },
{ 18, N_("-1") }
};
//! Contrast, tag 0x000c
constexpr TagDetails casioContrast[] = {
{ 0, N_("Normal") },
{ 1, N_("Low") },
{ 2, N_("High") },
{ 16, N_("Normal") },
{ 17, N_("+1") },
{ 18, N_("-1") }
};
//! Saturation, tag 0x000d
constexpr TagDetails casioSaturation[] = {
{ 0, N_("Normal") },
{ 1, N_("Low") },
{ 2, N_("High") },
{ 16, N_("Normal") },
{ 17, N_("+1") },
{ 18, N_("-1") }
};
//! Enhancement, tag 0x0016
constexpr TagDetails casioEnhancement[] = {
{ 1, N_("Off") },
{ 2, N_("Red") },
{ 3, N_("Green") },
{ 4, N_("Blue") },
{ 5, N_("Flesh Tones") }
};
//! Color filter, tag 0x0017
constexpr TagDetails casioColorFilter[] = {
{ 1, N_("Off") },
{ 2, N_("Black & White") },
{ 3, N_("Sepia") },
{ 4, N_("Red") },
{ 5, N_("Green") },
{ 6, N_("Blue") },
{ 7, N_("Yellow") },
{ 8, N_("Pink") },
{ 9, N_("Purple") }
};
//! flash intensity 2, tag 0x0019
constexpr TagDetails casioFlashIntensity2[] = {
{ 1, N_("Normal") },
{ 2, N_("Weak") },
{ 3, N_("Strong") }
};
//! CCD Sensitivity intensity, tag 0x0020
constexpr TagDetails casioCCDSensitivity[] = {
{ 64, N_("Normal") },
{ 125, N_("+1.0") },
{ 250, N_("+2.0") },
{ 244, N_("+3.0") },
{ 80, N_("Normal (ISO 80 equivalent)") },
{ 100, N_("High") }
};
// Casio MakerNote Tag Info
constexpr TagInfo CasioMakerNote::tagInfo_[] = {
{0x0001, "RecodingMode", N_("RecodingMode"), N_("Recording Mode"), casioId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casioRecordingMode)},
{0x0002, "Quality", N_("Quality"), N_("Quality"), casioId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casioQuality)},
{0x0003, "FocusMode", N_("Focus Mode"), N_("Focus Mode"), casioId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casioFocusMode)},
{0x0004, "FlashMode", N_("Flash Mode"), N_("Flash Mode"), casioId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casioFlashMode)},
{0x0005, "FlashIntensity", N_("Flash Intensity"), N_("Flash Intensity"), casioId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casioFlashIntensity)},
{0x0006, "ObjectDistance", N_("Object Distance"), N_("Distance to object"), casioId, makerTags, unsignedLong, -1, print0x0006},
{0x0007, "WhiteBalance", N_("White Balance"), N_("White balance settings"), casioId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casioWhiteBalance)},
{0x000a, "DigitalZoom", N_("Digital Zoom"), N_("Digital zoom"), casioId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(casioDigitalZoom)},
{0x000b, "Sharpness", N_("Sharpness"), N_("Sharpness"), casioId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casioSharpness)},
{0x000c, "Contrast", N_("Contrast"), N_("Contrast"), casioId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casioContrast)},
{0x000d, "Saturation", N_("Saturation"), N_("Saturation"), casioId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casioSaturation)},
{0x0014, "ISO", N_("ISO"), N_("ISO"), casioId, makerTags, unsignedShort, -1, printValue},
{0x0015, "FirmwareDate", N_("Firmware date"), N_("Firmware date"), casioId, makerTags, asciiString, -1, print0x0015},
{0x0016, "Enhancement", N_("Enhancement"), N_("Enhancement"), casioId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casioEnhancement)},
{0x0017, "ColorFilter", N_("Color Filter"), N_("Color Filter"), casioId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casioColorFilter)},
{0x0018, "AFPoint", N_("AF Point"), N_("AF Point"), casioId, makerTags, unsignedShort, -1, printValue},
{0x0019, "FlashIntensity2", N_("Flash Intensity"), N_("Flash Intensity"), casioId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casioFlashIntensity2)},
{0x0020, "CCDSensitivity", N_("CCDSensitivity"), N_("CCDSensitivity"), casioId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casioCCDSensitivity)},
{0x0e00, "PrintIM", N_("Print IM"), N_("PrintIM information"), casioId, makerTags, undefined, -1, printValue},
{0xffff, "(UnknownCasioMakerNoteTag)", "(UnknownCasioMakerNoteTag)", N_("Unknown CasioMakerNote tag"), casioId, makerTags, asciiString, -1, printValue},
};
const TagInfo* CasioMakerNote::tagList()
{
return tagInfo_;
}
std::ostream& CasioMakerNote::print0x0006(std::ostream& os, const Value& value, const ExifData*)
{
std::ios::fmtflags f( os.flags() );
std::ostringstream oss;
oss.copyfmt(os);
os << std::fixed << std::setprecision(2) << value.toInt64() / 1000.0 << _(" m");
os.copyfmt(oss);
os.flags(f);
return os;
//! RecordingMode, tag 0x0001
constexpr TagDetails casioRecordingMode[] = {{1, N_("Single Shutter")}, {2, N_("Panorama")}, {3, N_("Night Scene")},
{4, N_("Portrait")}, {5, N_("Landscape")}, {7, N_("Panorama")},
{10, N_("Night Scene")}, {15, N_("Portrait")}, {16, N_("Landscape")}};
//! Quality, tag 0x0002
constexpr TagDetails casioQuality[] = {{1, N_("Economy")}, {2, N_("Normal")}, {3, N_("Fine")}};
//! Focus Mode, tag 0x0003
constexpr TagDetails casioFocusMode[] = {
{2, N_("Macro")}, {3, N_("Auto")}, {4, N_("Manual")}, {5, N_("Infinity")}, {7, N_("Sport AF")}};
//! FlashMode, tag 0x0004
constexpr TagDetails casioFlashMode[] = {
{1, N_("Auto")}, {2, N_("On")}, {3, N_("Off")}, {4, N_("Off")}, {5, N_("Red-eye Reduction")}};
//! Flash intensity, tag 0x0005
constexpr TagDetails casioFlashIntensity[] = {
{11, N_("Weak")}, {12, N_("Low")}, {13, N_("Normal")}, {14, N_("High")}, {15, N_("Strong")}};
//! white balance, tag 0x0007
constexpr TagDetails casioWhiteBalance[] = {{1, N_("Auto")}, {2, N_("Tungsten")}, {3, N_("Daylight")},
{4, N_("Fluorescent")}, {5, N_("Shade")}, {129, N_("Manual")}};
//! Flash intensity, tag 0x0005
constexpr TagDetails casioDigitalZoom[] = {{0x10000, N_("Off")}, {0x10001, N_("2x")}, {0x13333, N_("1.2x")},
{0x13ae1, N_("1.23x")}, {0x19999, N_("1.6x")}, {0x20000, N_("2x")},
{0x33333, N_("3.2x")}, {0x40000, N_("4x")}};
//! Sharpness, tag 0x000b
constexpr TagDetails casioSharpness[] = {{0, N_("Normal")}, {1, N_("Soft")}, {2, N_("Hard")},
{16, N_("Normal")}, {17, N_("+1")}, {18, N_("-1")}};
//! Contrast, tag 0x000c
constexpr TagDetails casioContrast[] = {{0, N_("Normal")}, {1, N_("Low")}, {2, N_("High")},
{16, N_("Normal")}, {17, N_("+1")}, {18, N_("-1")}};
//! Saturation, tag 0x000d
constexpr TagDetails casioSaturation[] = {{0, N_("Normal")}, {1, N_("Low")}, {2, N_("High")},
{16, N_("Normal")}, {17, N_("+1")}, {18, N_("-1")}};
//! Enhancement, tag 0x0016
constexpr TagDetails casioEnhancement[] = {
{1, N_("Off")}, {2, N_("Red")}, {3, N_("Green")}, {4, N_("Blue")}, {5, N_("Flesh Tones")}};
//! Color filter, tag 0x0017
constexpr TagDetails casioColorFilter[] = {{1, N_("Off")}, {2, N_("Black & White")}, {3, N_("Sepia")},
{4, N_("Red")}, {5, N_("Green")}, {6, N_("Blue")},
{7, N_("Yellow")}, {8, N_("Pink")}, {9, N_("Purple")}};
//! flash intensity 2, tag 0x0019
constexpr TagDetails casioFlashIntensity2[] = {{1, N_("Normal")}, {2, N_("Weak")}, {3, N_("Strong")}};
//! CCD Sensitivity intensity, tag 0x0020
constexpr TagDetails casioCCDSensitivity[] = {
{64, N_("Normal")}, {125, N_("+1.0")}, {250, N_("+2.0")}, {244, N_("+3.0")}, {80, N_("Normal (ISO 80 equivalent)")},
{100, N_("High")}};
// Casio MakerNote Tag Info
constexpr TagInfo CasioMakerNote::tagInfo_[] = {
{0x0001, "RecodingMode", N_("RecodingMode"), N_("Recording Mode"), casioId, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioRecordingMode)},
{0x0002, "Quality", N_("Quality"), N_("Quality"), casioId, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioQuality)},
{0x0003, "FocusMode", N_("Focus Mode"), N_("Focus Mode"), casioId, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioFocusMode)},
{0x0004, "FlashMode", N_("Flash Mode"), N_("Flash Mode"), casioId, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioFlashMode)},
{0x0005, "FlashIntensity", N_("Flash Intensity"), N_("Flash Intensity"), casioId, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioFlashIntensity)},
{0x0006, "ObjectDistance", N_("Object Distance"), N_("Distance to object"), casioId, makerTags, unsignedLong, -1,
print0x0006},
{0x0007, "WhiteBalance", N_("White Balance"), N_("White balance settings"), casioId, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioWhiteBalance)},
{0x000a, "DigitalZoom", N_("Digital Zoom"), N_("Digital zoom"), casioId, makerTags, unsignedLong, -1,
EXV_PRINT_TAG(casioDigitalZoom)},
{0x000b, "Sharpness", N_("Sharpness"), N_("Sharpness"), casioId, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioSharpness)},
{0x000c, "Contrast", N_("Contrast"), N_("Contrast"), casioId, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioContrast)},
{0x000d, "Saturation", N_("Saturation"), N_("Saturation"), casioId, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioSaturation)},
{0x0014, "ISO", N_("ISO"), N_("ISO"), casioId, makerTags, unsignedShort, -1, printValue},
{0x0015, "FirmwareDate", N_("Firmware date"), N_("Firmware date"), casioId, makerTags, asciiString, -1,
print0x0015},
{0x0016, "Enhancement", N_("Enhancement"), N_("Enhancement"), casioId, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioEnhancement)},
{0x0017, "ColorFilter", N_("Color Filter"), N_("Color Filter"), casioId, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioColorFilter)},
{0x0018, "AFPoint", N_("AF Point"), N_("AF Point"), casioId, makerTags, unsignedShort, -1, printValue},
{0x0019, "FlashIntensity2", N_("Flash Intensity"), N_("Flash Intensity"), casioId, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioFlashIntensity2)},
{0x0020, "CCDSensitivity", N_("CCDSensitivity"), N_("CCDSensitivity"), casioId, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioCCDSensitivity)},
{0x0e00, "PrintIM", N_("Print IM"), N_("PrintIM information"), casioId, makerTags, undefined, -1, printValue},
{0xffff, "(UnknownCasioMakerNoteTag)", "(UnknownCasioMakerNoteTag)", N_("Unknown CasioMakerNote tag"), casioId,
makerTags, asciiString, -1, printValue},
};
const TagInfo* CasioMakerNote::tagList() {
return tagInfo_;
}
std::ostream& CasioMakerNote::print0x0006(std::ostream& os, const Value& value, const ExifData*) {
std::ios::fmtflags f(os.flags());
std::ostringstream oss;
oss.copyfmt(os);
os << std::fixed << std::setprecision(2) << value.toInt64() / 1000.0 << _(" m");
os.copyfmt(oss);
os.flags(f);
return os;
}
std::ostream& CasioMakerNote::print0x0015(std::ostream& os, const Value& value, const ExifData*) {
// format is: "YYMM#00#00DDHH#00#00MM#00#00#00#00" or "YYMM#00#00DDHH#00#00MMSS#00#00#00"
std::vector<char> numbers;
for (size_t i = 0; i < value.size(); i++) {
const auto l = value.toInt64(i);
if (l != 0) {
numbers.push_back(static_cast<char>(l));
}
std::ostream& CasioMakerNote::print0x0015(std::ostream& os, const Value& value, const ExifData*)
{
// format is: "YYMM#00#00DDHH#00#00MM#00#00#00#00" or "YYMM#00#00DDHH#00#00MMSS#00#00#00"
std::vector<char> numbers;
for(size_t i=0; i<value.size(); i++)
{
const auto l = value.toInt64(i);
if(l!=0)
{
numbers.push_back(static_cast<char>(l));
}
}
if(numbers.size()>=10)
{
//year
long l=(numbers[0]-48)*10+(numbers[1]-48);
if(l<70)
{
l+=2000;
}
else
{
l+=1900;
};
os << l << ":";
// month, day, hour, minutes
os << numbers[2] << numbers[3] << ":" << numbers[4] << numbers[5] << " " << numbers[6] << numbers[7] << ":" << numbers[8] << numbers[9];
// optional seconds
if(numbers.size()==12)
{
os << ":" << numbers[10] << numbers[11];
};
}
else
{
os << value;
};
return os;
}
//Casio Makernotes, Type 2
//! Quality Mode, tag 0x0004
constexpr TagDetails casio2QualityMode[] = {
{ 0, N_("Economy") },
{ 1, N_("Normal") },
{ 2, N_("Fine") }
};
//! Image Size, tag 0x0009
constexpr TagDetails casio2ImageSize[] = {
{ 0, "640x480" },
{ 4, "1600x1200" },
{ 5, "2048x1536" },
{ 20, "2288x1712" },
{ 21, "2592x1944" },
{ 22, "2304x1728" },
{ 36, "3008x2008" }
};
//! Focus Mode, tag 0x000d
constexpr TagDetails casio2FocusMode[] = {
{ 0, N_("Normal") },
{ 1, N_("Macro") }
};
//! ISO Speed, tag 0x0014
constexpr TagDetails casio2IsoSpeed[] = {
{ 3, "50" },
{ 4, "64" },
{ 6, "100" },
{ 9, "200" }
};
//! White Balance, tag 0x0019
constexpr TagDetails casio2WhiteBalance[] = {
{ 0, N_("Auto") },
{ 1, N_("Daylight") },
{ 2, N_("Shade") },
{ 3, N_("Tungsten") },
{ 4, N_("Fluorescent") },
{ 5, N_("Manual") }
};
//! Saturation, tag 0x001f
constexpr TagDetails casio2Saturation[] = {
{ 0, N_("Low") },
{ 1, N_("Normal") },
{ 2, N_("High") }
};
//! Contrast, tag 0x0020
constexpr TagDetails casio2Contrast[] = {
{ 0, N_("Low") },
{ 1, N_("Normal") },
{ 2, N_("High") }
};
//! Sharpness, tag 0x0021
constexpr TagDetails casio2Sharpness[] = {
{ 0, N_("Soft") },
{ 1, N_("Normal") },
{ 2, N_("Hard") }
};
//! White Balance2, tag 0x2012
constexpr TagDetails casio2WhiteBalance2[] = {
{ 0, N_("Manual") },
{ 1, N_("Daylight") },
{ 2, N_("Cloudy") },
{ 3, N_("Shade") },
{ 4, N_("Flash") },
{ 6, N_("Fluorescent") },
{ 9, N_("Tungsten") },
{ 10, N_("Tungsten") },
{ 12, N_("Flash") }
};
//! Release Mode, tag 0x3001
constexpr TagDetails casio2ReleaseMode[] = {
{ 1, N_("Normal") },
{ 3, N_("AE Bracketing") },
{ 11, N_("WB Bracketing") },
{ 13, N_("Contrast Bracketing") },
{ 19, N_("High Speed Burst") }
};
//! Quality, tag 0x3002
constexpr TagDetails casio2Quality[] = {
{ 1, N_("Economy") },
{ 2, N_("Normal") },
{ 3, N_("Fine") }
};
//! Focus Mode 2, tag 0x3003
constexpr TagDetails casio2FocusMode2[] = {
{ 0, N_("Manual") },
{ 1, N_("Focus Lock") },
{ 2, N_("Macro") },
{ 3, N_("Single-Area Auto Focus") },
{ 5, N_("Infinity") },
{ 6, N_("Multi-Area Auto Focus") },
{ 8, N_("Super Macro") }
};
//! AutoISO, tag 0x3008
constexpr TagDetails casio2AutoISO[] = {
{ 1, N_("On") },
{ 2, N_("Off") },
{ 7, N_("On (high sensitivity)") },
{ 8, N_("On (anti-shake)") },
{ 10, N_("High Speed") }
};
//! AFMode, tag 0x3009
constexpr TagDetails casio2AFMode[] = {
{ 0, N_("Off") },
{ 1, N_("Spot") },
{ 2, N_("Multi") },
{ 3, N_("Face Detection") },
{ 4, N_("Tracking") },
{ 5, N_("Intelligent") }
};
//! ColorMode, tag 0x3015
constexpr TagDetails casio2ColorMode[] = {
{ 0, N_("Off") },
{ 2, N_("Black & White") },
{ 3, N_("Sepia") }
};
//! Enhancement, tag 0x3016
constexpr TagDetails casio2Enhancement[] = {
{ 0, N_("Off") },
{ 1, N_("Scenery") },
{ 3, N_("Green") },
{ 5, N_("Underwater") },
{ 9, N_("Flesh Tones") }
};
//! Color Filter, tag 0x3017
constexpr TagDetails casio2ColorFilter[] = {
{ 0, N_("Off") },
{ 1, N_("Blue") },
{ 3, N_("Green") },
{ 4, N_("Yellow") },
{ 5, N_("Red") },
{ 6, N_("Purple") },
{ 7, N_("Pink") }
};
//! Art Mode, tag 0x301b
constexpr TagDetails casio2ArtMode[] = {
{ 0, N_("Normal") },
{ 8, N_("Silent Movie") },
{ 39, N_("HDR") },
{ 45, N_("Premium Auto") },
{ 47, N_("Painting") },
{ 49, N_("Crayon Drawing") },
{ 51, N_("Panorama") },
{ 52, N_("Art HDR") },
{ 62, N_("High Speed Night Shot") },
{ 64, N_("Monochrome") },
{ 67, N_("Toy Camera") },
{ 68, N_("Pop Art") },
{ 69, N_("Light Tone") }
};
//! Lighting Mode, tag 0x302a
constexpr TagDetails casio2LightingMode[] = {
{ 0, N_("Off") },
{ 1, N_("High Dynamic Range") },
{ 5, N_("Shadow Enhance Low") },
{ 6, N_("Shadow Enhance High") }
};
//! Portrait Refiner, tag 0x302b
constexpr TagDetails casio2PortraitRefiner[] = {
{ 0, N_("Off") },
{ 1, N_("+1") },
{ 2, N_("+2") }
};
//! Special Effect Setting, tag 0x3031
constexpr TagDetails casio2SpecialEffectSetting[] = {
{ 0, N_("Off") },
{ 1, N_("Makeup") },
{ 2, N_("Mist Removal") },
{ 3, N_("Vivid Landscape") },
{ 16, N_("Art Shot") }
};
//! Drive Mode, tag 0x3103
constexpr TagDetails casio2DriveMode[] = {
{ 0, N_("Single Shot") },
{ 1, N_("Continuous Shooting") },
{ 2, N_("Continuous (2 fps)") },
{ 3, N_("Continuous (3 fps)") },
{ 4, N_("Continuous (4 fps)") },
{ 5, N_("Continuous (5 fps)") },
{ 6, N_("Continuous (6 fps)") },
{ 7, N_("Continuous (7 fps)") },
{ 10, N_("Continuous (10 fps)") },
{ 12, N_("Continuous (12 fps)") },
{ 15, N_("Continuous (15 fps)") },
{ 20, N_("Continuous (20 fps)") },
{ 30, N_("Continuous (30 fps)") },
{ 40, N_("Continuous (40 fps)") },
{ 60, N_("Continuous (60 fps)") },
{ 240, N_("Auto-N") }
};
//! Video Quality, tag 0x4003
constexpr TagDetails casio2VideoQuality[] = {
{ 1, N_("Standard") },
{ 3, N_("HD (720p)") },
{ 4, N_("Full HD (1080p)") },
{ 5, N_("Low") }
};
// Casio2 MakerNote Tag Info
constexpr TagInfo Casio2MakerNote::tagInfo_[] = {
{0x0002, "PreviewImageSize", N_("Preview Image Size"), N_("Preview Image Size"), casio2Id, makerTags, unsignedShort, -1, printValue},
{0x0003, "PreviewImageLength", N_("Preview Image Length"), N_("Preview Image Length"), casio2Id, makerTags, unsignedLong, -1, printValue},
{0x0004, "PreviewImageStart", N_("Preview Image Start"), N_("Preview Image Start"), casio2Id, makerTags, unsignedLong, -1, printValue},
{0x0008, "QualityMode", N_("Quality Mode"), N_("Quality Mode"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2QualityMode)},
{0x0009, "ImageSize", N_("Image Size"), N_("Image Size"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2ImageSize)},
{0x000d, "FocusMode", N_("Focus Mode"), N_("Focus Mode"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2FocusMode)},
{0x0014, "ISOSpeed", N_("ISO Speed"), N_("ISO Speed"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2IsoSpeed)},
{0x0019, "WhiteBalance", N_("White Balance"), N_("White Balance Setting"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2WhiteBalance)},
{0x001d, "FocalLength", N_("Focal Length"), N_("Focal Length"), casio2Id, makerTags, unsignedRational, -1, printValue},
{0x001f, "Saturation", N_("Saturation"), N_("Saturation"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2Saturation)},
{0x0020, "Contrast", N_("Contrast"), N_("Contrast"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2Contrast)},
{0x0021, "Sharpness", N_("Sharpness"), N_("Sharpness"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2Sharpness)},
{0x0e00, "PrintIM", N_("Print IM"), N_("PrintIM information"), casio2Id, makerTags, undefined, -1, printValue},
{0x2000, "PreviewImage", N_("Preview Image"), N_("Preview Image"), casio2Id, makerTags, undefined, -1, printValue},
{0x2001, "FirmwareDate", N_("Firmware Date"), N_("Firmware Date"), casio2Id, makerTags, asciiString, -1, print0x2001},
{0x2011, "WhiteBalanceBias", N_("White Balance Bias"), N_("White Balance Bias"), casio2Id, makerTags, unsignedShort, -1, printValue},
{0x2012, "WhiteBalance2", N_("White Balance"), N_("White Balance Setting"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2WhiteBalance2)},
{0x2021, "AFPointPosition", N_("AF Point Position"), N_("AF Point Position"), casio2Id, makerTags, unsignedShort, -1, printValue},
{0x2022, "ObjectDistance", N_("Object Distance"), N_("Object Distance"), casio2Id, makerTags, unsignedLong, -1, print0x2022},
{0x2034, "FlashDistance", N_("Flash Distance"), N_("Flash Distance"), casio2Id, makerTags, unsignedShort, -1, printValue},
{0x2076, "SpecialEffectMode", N_("Special Effect Mode"), N_("Special Effect Mode"), casio2Id, makerTags, unsignedByte, -1, printValue},
{0x2089, "FaceInfo", N_("Face Info"), N_("Face Info"), casio2Id, makerTags, undefined, -1, printValue},
{0x211c, "FacesDetected", N_("Faces detected"), N_("Faces detected"), casio2Id, makerTags, unsignedByte, -1, printValue},
{0x3000, "RecordMode", N_("Record Mode"), N_("Record Mode"), casio2Id, makerTags, unsignedShort, -1, printValue},
{0x3001, "ReleaseMode", N_("Release Mode"), N_("Release Mode"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2ReleaseMode)},
{0x3002, "Quality", N_("Quality"), N_("Quality"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2Quality)},
{0x3003, "FocusMode2", N_("Focus Mode2"), N_("Focus Mode2"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2FocusMode2)},
{0x3006, "HometownCity", N_("Home town city"), N_("Home town city"), casio2Id, makerTags, asciiString, -1, printValue},
{0x3007, "BestShotMode", N_("Best Shot Mode"), N_("Best Shot Mode"), casio2Id, makerTags, unsignedShort, -1, printValue},
{0x3008, "AutoISO", N_("Auto ISO"), N_("Auto ISO"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2AutoISO)},
{0x3009, "AFMode", N_("AF Mode"), N_("AF Mode"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2AFMode)},
{0x3011, "Sharpness2", N_("Sharpness"), N_("Sharpness"), casio2Id, makerTags, undefined, -1, printValue},
{0x3012, "Contrast2", N_("Contrast"), N_("Contrast"), casio2Id, makerTags, undefined, -1, printValue},
{0x3013, "Saturation2", N_("Saturation"), N_("Saturation"), casio2Id, makerTags, undefined, -1, printValue},
{0x3014, "ISO", N_("ISO"), N_("ISO"), casio2Id, makerTags, unsignedShort, -1, printValue},
{0x3015, "ColorMode", N_("Color Mode"), N_("Color Mode"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2ColorMode)},
{0x3016, "Enhancement", N_("Enhancement"), N_("Enhancement"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2Enhancement)},
{0x3017, "ColorFilter", N_("Color Filter"), N_("Color Filter"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2ColorFilter)},
{0x301b, "ArtMode", N_("Art Mode"), N_("Art Mode"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2ArtMode)},
{0x301c, "SequenceNumber", N_("Sequence Number"), N_("Sequence Number"), casio2Id, makerTags, unsignedShort, -1, printValue},
{0x3020, "ImageStabilization", N_("Image Stabilization"), N_("Image Stabilization"), casio2Id, makerTags, unsignedShort, -1, printValue},
{0x302a, "LightingMode", N_("Lighting Mode"), N_("Lighting Mode"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2LightingMode)},
{0x302b, "PortraitRefiner", N_("Portrait Refiner"), N_("Portrait Refiner settings"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2PortraitRefiner)},
{0x3030, "SpecialEffectLevel", N_("Special Effect Level"), N_("Special Effect Level"), casio2Id, makerTags, unsignedShort, -1, printValue},
{0x3031, "SpecialEffectSetting", N_("Special Effect Setting"), N_("Special Effect Setting"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2SpecialEffectSetting)},
{0x3103, "DriveMode", N_("Drive Mode"), N_("Drive Mode"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2DriveMode)},
{0x310b, "ArtModeParameters", N_("Art Mode Parameters"), N_("Art Mode Parameters"), casio2Id, makerTags, undefined, -1, printValue},
{0x4001, "CaptureFrameRate", N_("Capture Frame Rate"), N_("Capture Frame Rate"), casio2Id, makerTags, unsignedShort, -1, printValue},
{0x4003, "VideoQuality", N_("Video Quality"), N_("Video Quality"), casio2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2VideoQuality)},
{0xffff, "(UnknownCasio2MakerNoteTag)", "(UnknownCasio2MakerNoteTag)", N_("Unknown Casio2MakerNote tag"), casio2Id, makerTags, asciiString, -1, printValue},
};
const TagInfo* Casio2MakerNote::tagList()
{
return tagInfo_;
}
std::ostream& Casio2MakerNote::print0x2001(std::ostream& os, const Value& value, const ExifData*)
{
// format is: "YYMM#00#00DDHH#00#00MM#00#00#00#00"
std::vector<char> numbers;
for(size_t i=0; i<value.size(); i++)
{
const auto l = static_cast<char>(value.toInt64(i));
if(l!=0)
{
numbers.push_back(l);
}
}
if(numbers.size()>=10)
{
//year
long l=(numbers[0]-48)*10+(numbers[1]-48);
if(l<70)
{
l+=2000;
}
else
{
l+=1900;
};
os << l << ":";
// month, day, hour, minutes
os << numbers[2] << numbers[3] << ":" << numbers[4] << numbers[5] << " " << numbers[6] << numbers[7] << ":" << numbers[8] << numbers[9];
}
else
{
os << value;
};
return os;
}
std::ostream& Casio2MakerNote::print0x2022(std::ostream& os, const Value& value, const ExifData*)
{
std::ios::fmtflags f( os.flags() );
if(value.toInt64()>=0x20000000)
{
os << N_("Inf");
os.flags(f);
return os;
};
std::ostringstream oss;
oss.copyfmt(os);
os << std::fixed << std::setprecision(2) << value.toInt64() / 1000.0 << _(" m");
os.copyfmt(oss);
os.flags(f);
return os;
}
if (numbers.size() >= 10) {
// year
long l = (numbers[0] - 48) * 10 + (numbers[1] - 48);
if (l < 70) {
l += 2000;
} else {
l += 1900;
};
os << l << ":";
// month, day, hour, minutes
os << numbers[2] << numbers[3] << ":" << numbers[4] << numbers[5] << " " << numbers[6] << numbers[7] << ":"
<< numbers[8] << numbers[9];
// optional seconds
if (numbers.size() == 12) {
os << ":" << numbers[10] << numbers[11];
};
} else {
os << value;
};
return os;
}
// Casio Makernotes, Type 2
//! Quality Mode, tag 0x0004
constexpr TagDetails casio2QualityMode[] = {{0, N_("Economy")}, {1, N_("Normal")}, {2, N_("Fine")}};
//! Image Size, tag 0x0009
constexpr TagDetails casio2ImageSize[] = {{0, "640x480"}, {4, "1600x1200"}, {5, "2048x1536"}, {20, "2288x1712"},
{21, "2592x1944"}, {22, "2304x1728"}, {36, "3008x2008"}};
//! Focus Mode, tag 0x000d
constexpr TagDetails casio2FocusMode[] = {{0, N_("Normal")}, {1, N_("Macro")}};
//! ISO Speed, tag 0x0014
constexpr TagDetails casio2IsoSpeed[] = {{3, "50"}, {4, "64"}, {6, "100"}, {9, "200"}};
//! White Balance, tag 0x0019
constexpr TagDetails casio2WhiteBalance[] = {{0, N_("Auto")}, {1, N_("Daylight")}, {2, N_("Shade")},
{3, N_("Tungsten")}, {4, N_("Fluorescent")}, {5, N_("Manual")}};
//! Saturation, tag 0x001f
constexpr TagDetails casio2Saturation[] = {{0, N_("Low")}, {1, N_("Normal")}, {2, N_("High")}};
//! Contrast, tag 0x0020
constexpr TagDetails casio2Contrast[] = {{0, N_("Low")}, {1, N_("Normal")}, {2, N_("High")}};
//! Sharpness, tag 0x0021
constexpr TagDetails casio2Sharpness[] = {{0, N_("Soft")}, {1, N_("Normal")}, {2, N_("Hard")}};
//! White Balance2, tag 0x2012
constexpr TagDetails casio2WhiteBalance2[] = {{0, N_("Manual")}, {1, N_("Daylight")}, {2, N_("Cloudy")},
{3, N_("Shade")}, {4, N_("Flash")}, {6, N_("Fluorescent")},
{9, N_("Tungsten")}, {10, N_("Tungsten")}, {12, N_("Flash")}};
//! Release Mode, tag 0x3001
constexpr TagDetails casio2ReleaseMode[] = {{1, N_("Normal")},
{3, N_("AE Bracketing")},
{11, N_("WB Bracketing")},
{13, N_("Contrast Bracketing")},
{19, N_("High Speed Burst")}};
//! Quality, tag 0x3002
constexpr TagDetails casio2Quality[] = {{1, N_("Economy")}, {2, N_("Normal")}, {3, N_("Fine")}};
//! Focus Mode 2, tag 0x3003
constexpr TagDetails casio2FocusMode2[] = {{0, N_("Manual")}, {1, N_("Focus Lock")},
{2, N_("Macro")}, {3, N_("Single-Area Auto Focus")},
{5, N_("Infinity")}, {6, N_("Multi-Area Auto Focus")},
{8, N_("Super Macro")}};
//! AutoISO, tag 0x3008
constexpr TagDetails casio2AutoISO[] = {{1, N_("On")},
{2, N_("Off")},
{7, N_("On (high sensitivity)")},
{8, N_("On (anti-shake)")},
{10, N_("High Speed")}};
//! AFMode, tag 0x3009
constexpr TagDetails casio2AFMode[] = {{0, N_("Off")}, {1, N_("Spot")},
{2, N_("Multi")}, {3, N_("Face Detection")},
{4, N_("Tracking")}, {5, N_("Intelligent")}};
//! ColorMode, tag 0x3015
constexpr TagDetails casio2ColorMode[] = {{0, N_("Off")}, {2, N_("Black & White")}, {3, N_("Sepia")}};
//! Enhancement, tag 0x3016
constexpr TagDetails casio2Enhancement[] = {
{0, N_("Off")}, {1, N_("Scenery")}, {3, N_("Green")}, {5, N_("Underwater")}, {9, N_("Flesh Tones")}
};
//! Color Filter, tag 0x3017
constexpr TagDetails casio2ColorFilter[] = {{0, N_("Off")}, {1, N_("Blue")}, {3, N_("Green")}, {4, N_("Yellow")},
{5, N_("Red")}, {6, N_("Purple")}, {7, N_("Pink")}};
//! Art Mode, tag 0x301b
constexpr TagDetails casio2ArtMode[] = {
{0, N_("Normal")}, {8, N_("Silent Movie")}, {39, N_("HDR")},
{45, N_("Premium Auto")}, {47, N_("Painting")}, {49, N_("Crayon Drawing")},
{51, N_("Panorama")}, {52, N_("Art HDR")}, {62, N_("High Speed Night Shot")},
{64, N_("Monochrome")}, {67, N_("Toy Camera")}, {68, N_("Pop Art")},
{69, N_("Light Tone")}};
//! Lighting Mode, tag 0x302a
constexpr TagDetails casio2LightingMode[] = {
{0, N_("Off")}, {1, N_("High Dynamic Range")}, {5, N_("Shadow Enhance Low")}, {6, N_("Shadow Enhance High")}};
//! Portrait Refiner, tag 0x302b
constexpr TagDetails casio2PortraitRefiner[] = {{0, N_("Off")}, {1, N_("+1")}, {2, N_("+2")}};
//! Special Effect Setting, tag 0x3031
constexpr TagDetails casio2SpecialEffectSetting[] = {
{0, N_("Off")}, {1, N_("Makeup")}, {2, N_("Mist Removal")}, {3, N_("Vivid Landscape")}, {16, N_("Art Shot")}};
//! Drive Mode, tag 0x3103
constexpr TagDetails casio2DriveMode[] = {{0, N_("Single Shot")}, {1, N_("Continuous Shooting")},
{2, N_("Continuous (2 fps)")}, {3, N_("Continuous (3 fps)")},
{4, N_("Continuous (4 fps)")}, {5, N_("Continuous (5 fps)")},
{6, N_("Continuous (6 fps)")}, {7, N_("Continuous (7 fps)")},
{10, N_("Continuous (10 fps)")}, {12, N_("Continuous (12 fps)")},
{15, N_("Continuous (15 fps)")}, {20, N_("Continuous (20 fps)")},
{30, N_("Continuous (30 fps)")}, {40, N_("Continuous (40 fps)")},
{60, N_("Continuous (60 fps)")}, {240, N_("Auto-N")}};
//! Video Quality, tag 0x4003
constexpr TagDetails casio2VideoQuality[] = {
{1, N_("Standard")}, {3, N_("HD (720p)")}, {4, N_("Full HD (1080p)")}, {5, N_("Low")}};
// Casio2 MakerNote Tag Info
constexpr TagInfo Casio2MakerNote::tagInfo_[] = {
{0x0002, "PreviewImageSize", N_("Preview Image Size"), N_("Preview Image Size"), casio2Id, makerTags, unsignedShort,
-1, printValue},
{0x0003, "PreviewImageLength", N_("Preview Image Length"), N_("Preview Image Length"), casio2Id, makerTags,
unsignedLong, -1, printValue},
{0x0004, "PreviewImageStart", N_("Preview Image Start"), N_("Preview Image Start"), casio2Id, makerTags,
unsignedLong, -1, printValue},
{0x0008, "QualityMode", N_("Quality Mode"), N_("Quality Mode"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2QualityMode)},
{0x0009, "ImageSize", N_("Image Size"), N_("Image Size"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2ImageSize)},
{0x000d, "FocusMode", N_("Focus Mode"), N_("Focus Mode"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2FocusMode)},
{0x0014, "ISOSpeed", N_("ISO Speed"), N_("ISO Speed"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2IsoSpeed)},
{0x0019, "WhiteBalance", N_("White Balance"), N_("White Balance Setting"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2WhiteBalance)},
{0x001d, "FocalLength", N_("Focal Length"), N_("Focal Length"), casio2Id, makerTags, unsignedRational, -1,
printValue},
{0x001f, "Saturation", N_("Saturation"), N_("Saturation"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2Saturation)},
{0x0020, "Contrast", N_("Contrast"), N_("Contrast"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2Contrast)},
{0x0021, "Sharpness", N_("Sharpness"), N_("Sharpness"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2Sharpness)},
{0x0e00, "PrintIM", N_("Print IM"), N_("PrintIM information"), casio2Id, makerTags, undefined, -1, printValue},
{0x2000, "PreviewImage", N_("Preview Image"), N_("Preview Image"), casio2Id, makerTags, undefined, -1, printValue},
{0x2001, "FirmwareDate", N_("Firmware Date"), N_("Firmware Date"), casio2Id, makerTags, asciiString, -1,
print0x2001},
{0x2011, "WhiteBalanceBias", N_("White Balance Bias"), N_("White Balance Bias"), casio2Id, makerTags, unsignedShort,
-1, printValue},
{0x2012, "WhiteBalance2", N_("White Balance"), N_("White Balance Setting"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2WhiteBalance2)},
{0x2021, "AFPointPosition", N_("AF Point Position"), N_("AF Point Position"), casio2Id, makerTags, unsignedShort,
-1, printValue},
{0x2022, "ObjectDistance", N_("Object Distance"), N_("Object Distance"), casio2Id, makerTags, unsignedLong, -1,
print0x2022},
{0x2034, "FlashDistance", N_("Flash Distance"), N_("Flash Distance"), casio2Id, makerTags, unsignedShort, -1,
printValue},
{0x2076, "SpecialEffectMode", N_("Special Effect Mode"), N_("Special Effect Mode"), casio2Id, makerTags,
unsignedByte, -1, printValue},
{0x2089, "FaceInfo", N_("Face Info"), N_("Face Info"), casio2Id, makerTags, undefined, -1, printValue},
{0x211c, "FacesDetected", N_("Faces detected"), N_("Faces detected"), casio2Id, makerTags, unsignedByte, -1,
printValue},
{0x3000, "RecordMode", N_("Record Mode"), N_("Record Mode"), casio2Id, makerTags, unsignedShort, -1, printValue},
{0x3001, "ReleaseMode", N_("Release Mode"), N_("Release Mode"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2ReleaseMode)},
{0x3002, "Quality", N_("Quality"), N_("Quality"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2Quality)},
{0x3003, "FocusMode2", N_("Focus Mode2"), N_("Focus Mode2"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2FocusMode2)},
{0x3006, "HometownCity", N_("Home town city"), N_("Home town city"), casio2Id, makerTags, asciiString, -1,
printValue},
{0x3007, "BestShotMode", N_("Best Shot Mode"), N_("Best Shot Mode"), casio2Id, makerTags, unsignedShort, -1,
printValue},
{0x3008, "AutoISO", N_("Auto ISO"), N_("Auto ISO"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2AutoISO)},
{0x3009, "AFMode", N_("AF Mode"), N_("AF Mode"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2AFMode)},
{0x3011, "Sharpness2", N_("Sharpness"), N_("Sharpness"), casio2Id, makerTags, undefined, -1, printValue},
{0x3012, "Contrast2", N_("Contrast"), N_("Contrast"), casio2Id, makerTags, undefined, -1, printValue},
{0x3013, "Saturation2", N_("Saturation"), N_("Saturation"), casio2Id, makerTags, undefined, -1, printValue},
{0x3014, "ISO", N_("ISO"), N_("ISO"), casio2Id, makerTags, unsignedShort, -1, printValue},
{0x3015, "ColorMode", N_("Color Mode"), N_("Color Mode"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2ColorMode)},
{0x3016, "Enhancement", N_("Enhancement"), N_("Enhancement"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2Enhancement)},
{0x3017, "ColorFilter", N_("Color Filter"), N_("Color Filter"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2ColorFilter)},
{0x301b, "ArtMode", N_("Art Mode"), N_("Art Mode"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2ArtMode)},
{0x301c, "SequenceNumber", N_("Sequence Number"), N_("Sequence Number"), casio2Id, makerTags, unsignedShort, -1,
printValue},
{0x3020, "ImageStabilization", N_("Image Stabilization"), N_("Image Stabilization"), casio2Id, makerTags,
unsignedShort, -1, printValue},
{0x302a, "LightingMode", N_("Lighting Mode"), N_("Lighting Mode"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2LightingMode)},
{0x302b, "PortraitRefiner", N_("Portrait Refiner"), N_("Portrait Refiner settings"), casio2Id, makerTags,
unsignedShort, -1, EXV_PRINT_TAG(casio2PortraitRefiner)},
{0x3030, "SpecialEffectLevel", N_("Special Effect Level"), N_("Special Effect Level"), casio2Id, makerTags,
unsignedShort, -1, printValue},
{0x3031, "SpecialEffectSetting", N_("Special Effect Setting"), N_("Special Effect Setting"), casio2Id, makerTags,
unsignedShort, -1, EXV_PRINT_TAG(casio2SpecialEffectSetting)},
{0x3103, "DriveMode", N_("Drive Mode"), N_("Drive Mode"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2DriveMode)},
{0x310b, "ArtModeParameters", N_("Art Mode Parameters"), N_("Art Mode Parameters"), casio2Id, makerTags, undefined,
-1, printValue},
{0x4001, "CaptureFrameRate", N_("Capture Frame Rate"), N_("Capture Frame Rate"), casio2Id, makerTags, unsignedShort,
-1, printValue},
{0x4003, "VideoQuality", N_("Video Quality"), N_("Video Quality"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2VideoQuality)},
{0xffff, "(UnknownCasio2MakerNoteTag)", "(UnknownCasio2MakerNoteTag)", N_("Unknown Casio2MakerNote tag"), casio2Id,
makerTags, asciiString, -1, printValue},
};
const TagInfo* Casio2MakerNote::tagList() {
return tagInfo_;
}
std::ostream& Casio2MakerNote::print0x2001(std::ostream& os, const Value& value, const ExifData*) {
// format is: "YYMM#00#00DDHH#00#00MM#00#00#00#00"
std::vector<char> numbers;
for (size_t i = 0; i < value.size(); i++) {
const auto l = static_cast<char>(value.toInt64(i));
if (l != 0) {
numbers.push_back(l);
}
}
if (numbers.size() >= 10) {
// year
long l = (numbers[0] - 48) * 10 + (numbers[1] - 48);
if (l < 70) {
l += 2000;
} else {
l += 1900;
};
os << l << ":";
// month, day, hour, minutes
os << numbers[2] << numbers[3] << ":" << numbers[4] << numbers[5] << " " << numbers[6] << numbers[7] << ":"
<< numbers[8] << numbers[9];
} else {
os << value;
};
return os;
}
std::ostream& Casio2MakerNote::print0x2022(std::ostream& os, const Value& value, const ExifData*) {
std::ios::fmtflags f(os.flags());
if (value.toInt64() >= 0x20000000) {
os << N_("Inf");
os.flags(f);
return os;
};
std::ostringstream oss;
oss.copyfmt(os);
os << std::fixed << std::setprecision(2) << value.toInt64() / 1000.0 << _(" m");
os.copyfmt(oss);
os.flags(f);
return os;
}
} // namespace Exiv2::Internal

@ -3,9 +3,10 @@
/*!
@file casiomn_int.hpp
@brief Casio MakerNote implemented using the following references:
<a href="http://gvsoft.homedns.org/exif/makernote-casio-type1.html">Casio MakerNote Information</a> by GVsoft,
Casio.pm of <a href="http://www.sno.phy.queensu.ca/~phil/exiftool/">ExifTool</a> by Phil Harvey,
<a href="http://www.ozhiker.com/electronics/pjmt/jpeg_info/casio_mn.html#Casio_Type_1_Tags">Casio Makernote Format Specification</a> by Evan Hunter.
<a href="http://gvsoft.homedns.org/exif/makernote-casio-type1.html">Casio MakerNote Information</a> by
GVsoft, Casio.pm of <a href="http://www.sno.phy.queensu.ca/~phil/exiftool/">ExifTool</a> by Phil Harvey, <a
href="http://www.ozhiker.com/electronics/pjmt/jpeg_info/casio_mn.html#Casio_Type_1_Tags">Casio Makernote Format
Specification</a> by Evan Hunter.
@date 30-Oct-13, ahu: created
*/
#ifndef CASIOMN_INT_HPP_
@ -19,42 +20,41 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2::Internal {
// *****************************************************************************
// class definitions
//! MakerNote for Casio cameras
class CasioMakerNote {
public:
//! Return read-only list of built-in Casio tags
static const TagInfo* tagList();
//! Print ObjectDistance
static std::ostream& print0x0006(std::ostream& os, const Value& value, const ExifData*);
//! Print FirmwareDate
static std::ostream& print0x0015(std::ostream& os, const Value& value, const ExifData*);
private:
//! Makernote tag list
static const TagInfo tagInfo_[];
}; // class CasioMakerNote
//! MakerNote for Casio2 cameras
class Casio2MakerNote {
public:
//! Return read-only list of built-in Casio2 tags
static const TagInfo* tagList();
//! Print FirmwareDate
static std::ostream& print0x2001(std::ostream& os, const Value& value, const ExifData*);
//! Print ObjectDistance
static std::ostream& print0x2022(std::ostream& os, const Value& value, const ExifData*);
private:
//! Makernote tag list
static const TagInfo tagInfo_[];
}; // class Casio2MakerNote
// *****************************************************************************
// class definitions
//! MakerNote for Casio cameras
class CasioMakerNote {
public:
//! Return read-only list of built-in Casio tags
static const TagInfo* tagList();
//! Print ObjectDistance
static std::ostream& print0x0006(std::ostream& os, const Value& value, const ExifData*);
//! Print FirmwareDate
static std::ostream& print0x0015(std::ostream& os, const Value& value, const ExifData*);
private:
//! Makernote tag list
static const TagInfo tagInfo_[];
}; // class CasioMakerNote
//! MakerNote for Casio2 cameras
class Casio2MakerNote {
public:
//! Return read-only list of built-in Casio2 tags
static const TagInfo* tagList();
//! Print FirmwareDate
static std::ostream& print0x2001(std::ostream& os, const Value& value, const ExifData*);
//! Print ObjectDistance
static std::ostream& print0x2022(std::ostream& os, const Value& value, const ExifData*);
private:
//! Makernote tag list
static const TagInfo tagInfo_[];
}; // class Casio2MakerNote
} // namespace Exiv2::Internal
#endif // #ifndef CasioMN_INT_HPP_
#endif // #ifndef CasioMN_INT_HPP_

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save