-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathxmpengine.cpp
More file actions
173 lines (147 loc) · 5.78 KB
/
xmpengine.cpp
File metadata and controls
173 lines (147 loc) · 5.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include "xmpengine.h"
#include <QDebug>
#include <QFileInfo>
XMPEngine::XMPEngine()
{
QString filePath = "/Users/herwin/devel/test/_JS_HJS_001_TEST2.CR3";
// Write XMP sidecar file
// writeXmpSidecar(filePath);
openXmpFile(filePath);
dumpXmp();
addXmpBag("Xmp.dc.subject", "Test");
appendXmpBag("Xmp.dc.subject", "Testi2");
dumpXmp();
saveXmpFile();
}
void XMPEngine::writeXmpSidecar(const std::string &filePath)
{
try {
// Extract the directory and base filename, then append .xmp extension
std::filesystem::path path(filePath);
std::filesystem::path xmpFilePath = path.parent_path() / (path.stem().string() + ".xmp");
QString keywords;
if (std::filesystem::exists(xmpFilePath)) {
// Open the image file
Exiv2::Image::UniquePtr image = Exiv2::ImageFactory::open(xmpFilePath);
image->readMetadata();
// Get the existing XMP data
xmpData = image->xmpData();
if (!xmpData.empty()) {
// Print existing XMP data
std::cout << "Existing XMP data:" << std::endl;
for (Exiv2::XmpData::const_iterator md = xmpData.begin(); md != xmpData.end();
++md) {
std::cout << md->key() << " " << md->value() << std::endl;
}
// Check if the key exists
// Exiv2::XmpData::iterator pos = xmpData.findKey(
// Exiv2::XmpKey("Xmp.iptc.AltTextAccessibility"));
// if (pos != xmpData.end())
// xmpData.erase(pos);
Exiv2::XmpData::iterator pos = xmpData.findKey(Exiv2::XmpKey("Xmp.dc.subject"));
if (pos != xmpData.end()) {
keywords = QString::fromLocal8Bit(xmpData["Xmp.dc.subject"].toString());
qDebug() << keywords;
xmpData.erase(pos);
}
}
}
// Add a language alternative property
std::unique_ptr<Exiv2::Value> v = Exiv2::Value::create(Exiv2::xmpText);
v = Exiv2::Value::create(Exiv2::langAlt);
v->read("lang=x-default Check, World"); // qualifier
xmpData.add(Exiv2::XmpKey("Xmp.dc.description"), v.get());
v = Exiv2::Value::create(Exiv2::xmpBag);
v->read("Halo, Dit, is een, test, ");
xmpData.add(Exiv2::XmpKey("Xmp.dc.subject"), v.get());
// xmpData["Xmp.dc.subject"] = ""; // an array item
// xmpData["Xmp.dc.subject"] = "Rubbertree"; // add a 2nd array item
// Create the XMP packet
std::string xmpPacket;
if (Exiv2::XmpParser::encode(xmpPacket, xmpData) != 0) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Failed to encode XMP data");
}
// Write the XMP packet to a sidecar file
std::ofstream xmpFile(xmpFilePath);
if (!xmpFile.is_open()) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage,
"Failed to open XMP file for writing");
}
xmpFile << xmpPacket;
xmpFile.close();
std::cout << "XMP sidecar file created at: " << xmpFilePath << std::endl;
} catch (const Exiv2::Error &e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
void XMPEngine::openXmpFile(QString file)
{
// Exiv2::XmpParser::initialize();
QFileInfo fi(file);
fileName = fi.absolutePath() + "/" + fi.baseName() + ".xmp";
qDebug() << fileName.toStdString();
try {
if (std::filesystem::exists(fileName.toStdString())) {
// Open the image file
Exiv2::Image::UniquePtr image = Exiv2::ImageFactory::open(fileName.toStdString());
image->readMetadata();
// Get the existing XMP data
xmpData = image->xmpData();
}
} catch (const Exiv2::Error &e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
void XMPEngine::saveXmpFile()
{
// Create the XMP packet
std::string xmpPacket;
if (Exiv2::XmpParser::encode(xmpPacket, xmpData) != 0) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Failed to encode XMP data");
}
// Write the XMP packet to a sidecar file
std::ofstream xmpFile(fileName.toStdString());
if (!xmpFile.is_open()) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, "Failed to open XMP file for writing");
}
xmpFile << xmpPacket;
xmpFile.close();
}
void XMPEngine::dumpXmp()
{
if (!xmpData.empty()) {
// Print existing XMP data
std::cout << "Existing XMP data:" << std::endl;
for (Exiv2::XmpData::const_iterator md = xmpData.begin(); md != xmpData.end(); ++md) {
std::cout << md->key() << " " << md->value() << std::endl;
}
}
}
void XMPEngine::addLangAlt(QString key, QString value, bool _overwrite)
{
std::unique_ptr<Exiv2::Value> v = Exiv2::Value::create(Exiv2::langAlt);
v->read(value.toStdString());
xmpData.add(Exiv2::XmpKey(key.toStdString()), v.get());
}
void XMPEngine::addXmpBag(QString key, QString value, bool _overwrite)
{
std::unique_ptr<Exiv2::Value> v = Exiv2::Value::create(Exiv2::xmpBag);
v->read(value.toStdString());
xmpData.add(Exiv2::XmpKey(key.toStdString()), v.get());
}
void XMPEngine::appendXmpBag(QString key, QString value)
{
QString keywords = QString::fromLocal8Bit(xmpData[key.toStdString()].toString());
keywords = keywords.trimmed();
if (keywords.endsWith(',')) {
keywords.chop(1); // Remove the trailing comma
}
if (!keywords.isEmpty()) {
keywords.append(", " + value);
} else {
keywords = value;
}
std::unique_ptr<Exiv2::Value> v = Exiv2::Value::create(Exiv2::xmpBag);
v->read(keywords.toStdString());
xmpData.add(Exiv2::XmpKey(key.toStdString()), v.get());
}