/src/libkexiv2/src/kexiv2_p.h
Line | Count | Source |
1 | | /* |
2 | | SPDX-FileCopyrightText: 2006-2015 Gilles Caulier <caulier dot gilles at gmail dot com> |
3 | | SPDX-FileCopyrightText: 2006-2012 Marcel Wiesweg <marcel dot wiesweg at gmx dot de> |
4 | | |
5 | | SPDX-License-Identifier: GPL-2.0-or-later |
6 | | */ |
7 | | |
8 | | #ifndef KEXIV2PRIVATE_H |
9 | | #define KEXIV2PRIVATE_H |
10 | | |
11 | | #include "kexiv2.h" |
12 | | |
13 | | // C++ includes |
14 | | |
15 | | #include <cstdlib> |
16 | | #include <cstdio> |
17 | | #include <cassert> |
18 | | #include <cmath> |
19 | | #include <cfloat> |
20 | | #include <iostream> |
21 | | #include <iomanip> |
22 | | #include <string> |
23 | | |
24 | | // Qt includes |
25 | | |
26 | | #include <QFile> |
27 | | #include <QSize> |
28 | | #include <QLatin1String> |
29 | | #include <QFileInfo> |
30 | | #include <QSharedData> |
31 | | |
32 | | // Exiv2 includes ------------------------------------------------------- |
33 | | |
34 | | // NOTE: All Exiv2 header must be stay there to not expose external source code to Exiv2 API |
35 | | // and reduce Exiv2 dependency to client code. |
36 | | |
37 | | // The pragmas are required to be able to catch exceptions thrown by libexiv2: |
38 | | // See https://gcc.gnu.org/wiki/Visibility, the section about c++ exceptions. |
39 | | // They are needed for all libexiv2 versions that do not care about visibility. |
40 | | #ifdef __GNUC__ |
41 | | #pragma GCC visibility push(default) |
42 | | #endif |
43 | | |
44 | | #include <exiv2/exiv2.hpp> |
45 | | |
46 | | // Check if Exiv2 support XMP |
47 | | |
48 | | #ifdef EXV_HAVE_XMP_TOOLKIT |
49 | | # define _XMP_SUPPORT_ 1 |
50 | | #endif |
51 | | |
52 | | // With exiv2 > 0.20.0, all makernote header files have been removed to increase binary compatibility. |
53 | | // See Exiv2 bugzilla entry https://dev.exiv2.org/issues/719 |
54 | | // and wiki topic https://dev.exiv2.org/boards/3/topics/583 |
55 | | |
56 | | #ifdef __GNUC__ |
57 | | #pragma GCC visibility pop |
58 | | #endif |
59 | | |
60 | | // End of Exiv2 headers ------------------------------------------------------ |
61 | | |
62 | | namespace KExiv2Iface |
63 | | { |
64 | | |
65 | | class KExiv2DataPrivate : public QSharedData |
66 | | { |
67 | | public: |
68 | | |
69 | | void clear(); |
70 | | |
71 | | public: |
72 | | |
73 | | std::string imageComments; |
74 | | |
75 | | Exiv2::ExifData exifMetadata; |
76 | | |
77 | | Exiv2::IptcData iptcMetadata; |
78 | | |
79 | | #ifdef _XMP_SUPPORT_ |
80 | | Exiv2::XmpData xmpMetadata; |
81 | | #endif |
82 | | }; |
83 | | |
84 | | // -------------------------------------------------------------------------- |
85 | | |
86 | | class KExiv2Private |
87 | | { |
88 | | public: |
89 | | |
90 | | KExiv2Private(); |
91 | | ~KExiv2Private(); |
92 | | |
93 | | void copyPrivateData(const KExiv2Private* const other); |
94 | | |
95 | | bool saveToXMPSidecar(const QFileInfo& finfo) const; |
96 | | bool saveToFile(const QFileInfo& finfo) const; |
97 | | #if EXIV2_TEST_VERSION(0,28,0) |
98 | | bool saveOperations(const QFileInfo& finfo, Exiv2::Image::UniquePtr image) const; |
99 | | #else |
100 | | bool saveOperations(const QFileInfo& finfo, Exiv2::Image::AutoPtr image) const; |
101 | | #endif |
102 | | |
103 | | /** Wrapper method to convert a Comments content to a QString. |
104 | | */ |
105 | | QString convertCommentValue(const Exiv2::Exifdatum& exifDatum) const; |
106 | | |
107 | | /** Charset autodetection to convert a string to a QString. |
108 | | */ |
109 | | QString detectEncodingAndDecode(const std::string& value) const; |
110 | | |
111 | | /** UTF8 autodetection from a string. |
112 | | */ |
113 | | bool isUtf8(const char* const buffer) const; |
114 | | |
115 | | int getXMPTagsListFromPrefix(const QString& pf, KExiv2::TagsMap& tagsMap) const; |
116 | | |
117 | 0 | const Exiv2::ExifData& exifMetadata() const { return data.constData()->exifMetadata; } |
118 | 0 | const Exiv2::IptcData& iptcMetadata() const { return data.constData()->iptcMetadata; } |
119 | 0 | const std::string& imageComments() const { return data.constData()->imageComments; } |
120 | | |
121 | | #ifdef _XMP_SUPPORT_ |
122 | 0 | const Exiv2::XmpData& xmpMetadata() const { return data.constData()->xmpMetadata; } |
123 | | #endif |
124 | | |
125 | 50.7k | Exiv2::ExifData& exifMetadata() { return data.data()->exifMetadata; } |
126 | 17.0k | Exiv2::IptcData& iptcMetadata() { return data.data()->iptcMetadata; } |
127 | 17.0k | std::string& imageComments() { return data.data()->imageComments; } |
128 | | |
129 | | #ifdef _XMP_SUPPORT_ |
130 | 17.0k | Exiv2::XmpData& xmpMetadata() { return data.data()->xmpMetadata; } |
131 | | |
132 | | #if EXIV2_TEST_VERSION(0,28,0) |
133 | | void loadSidecarData(Exiv2::Image::UniquePtr xmpsidecar); |
134 | | #else |
135 | | void loadSidecarData(Exiv2::Image::AutoPtr xmpsidecar); |
136 | | #endif |
137 | | #endif |
138 | | |
139 | | public: |
140 | | |
141 | | /** Generic method to print the Exiv2 C++ Exception error message from 'e'. |
142 | | * 'msg' string is printed using kDebug rules.. |
143 | | */ |
144 | | static void printExiv2ExceptionError(const QString& msg, Exiv2::Error& e); |
145 | | |
146 | | /** Generic method to print debug message from Exiv2. |
147 | | * 'msg' string is printed using kDebug rules. 'lvl' is the debug level of Exiv2 message. |
148 | | */ |
149 | | static void printExiv2MessageHandler(int lvl, const char* msg); |
150 | | |
151 | | public: |
152 | | |
153 | | bool writeRawFiles; |
154 | | bool updateFileTimeStamp; |
155 | | |
156 | | bool useXMPSidecar4Reading; |
157 | | |
158 | | /// A mode from #MetadataWritingMode enum. |
159 | | int metadataWritingMode; |
160 | | |
161 | | /// XMP, and parts of EXIF/IPTC, were loaded from an XMP sidecar file |
162 | | bool loadedFromSidecar; |
163 | | |
164 | | QString filePath; |
165 | | QSize pixelSize; |
166 | | QString mimeType; |
167 | | |
168 | | QSharedDataPointer<KExiv2DataPrivate> data; |
169 | | }; |
170 | | |
171 | | // -------------------------------------------------------------------------------------------- |
172 | | |
173 | | template <class Data, class Key, class KeyString, class KeyStringList = QList<KeyString> > |
174 | | |
175 | | class MergeHelper |
176 | | { |
177 | | public: |
178 | | |
179 | | KeyStringList keys; |
180 | | |
181 | | MergeHelper& operator<<(const KeyString& key) |
182 | 0 | { |
183 | 0 | keys << key; |
184 | 0 | return *this; |
185 | 0 | } Unexecuted instantiation: KExiv2Iface::MergeHelper<Exiv2::ExifData, Exiv2::ExifKey, QLatin1String, QList<QLatin1String> >::operator<<(QLatin1String const&) Unexecuted instantiation: KExiv2Iface::MergeHelper<Exiv2::IptcData, Exiv2::IptcKey, QLatin1String, QList<QLatin1String> >::operator<<(QLatin1String const&) |
186 | | |
187 | | /** |
188 | | * Merge two (Exif,IPTC,Xmp)Data packages, where the result is stored in dest |
189 | | * and fields from src take precedence over existing data from dest. |
190 | | */ |
191 | | void mergeAll(const Data& src, Data& dest) |
192 | | { |
193 | | for (typename Data::const_iterator it = src.begin(); it != src.end(); ++it) |
194 | | { |
195 | | typename Data::iterator destIt = dest.findKey(Key(it->key())); |
196 | | |
197 | | if (destIt == dest.end()) |
198 | | { |
199 | | dest.add(*it); |
200 | | } |
201 | | else |
202 | | { |
203 | | *destIt = *it; |
204 | | } |
205 | | } |
206 | | } |
207 | | |
208 | | /** |
209 | | * Merge two (Exif,IPTC,Xmp)Data packages, the result is stored in dest. |
210 | | * Only keys in keys are considered for merging. |
211 | | * Fields from src take precedence over existing data from dest. |
212 | | */ |
213 | | void mergeFields(const Data& src, Data& dest) const |
214 | 0 | { |
215 | 0 | for (const KeyString& keyString : keys) |
216 | 0 | { |
217 | 0 | Key key(keyString.latin1()); |
218 | 0 | typename Data::const_iterator it = src.findKey(key); |
219 | |
|
220 | 0 | if (it == src.end()) |
221 | 0 | { |
222 | 0 | continue; |
223 | 0 | } |
224 | | |
225 | 0 | typename Data::iterator destIt = dest.findKey(key); |
226 | |
|
227 | 0 | if (destIt == dest.end()) |
228 | 0 | { |
229 | 0 | dest.add(*it); |
230 | 0 | } |
231 | 0 | else |
232 | 0 | { |
233 | 0 | *destIt = *it; |
234 | 0 | } |
235 | 0 | } |
236 | 0 | } Unexecuted instantiation: KExiv2Iface::MergeHelper<Exiv2::ExifData, Exiv2::ExifKey, QLatin1String, QList<QLatin1String> >::mergeFields(Exiv2::ExifData const&, Exiv2::ExifData&) const Unexecuted instantiation: KExiv2Iface::MergeHelper<Exiv2::IptcData, Exiv2::IptcKey, QLatin1String, QList<QLatin1String> >::mergeFields(Exiv2::IptcData const&, Exiv2::IptcData&) const |
237 | | |
238 | | /** |
239 | | * Merge two (Exif,IPTC,Xmp)Data packages, the result is stored in dest. |
240 | | * The following steps apply only to keys in "keys": |
241 | | * The result is determined by src. |
242 | | * Keys must exist in src to kept in dest. |
243 | | * Fields from src take precedence over existing data from dest. |
244 | | */ |
245 | | void exclusiveMerge(const Data& src, Data& dest) const |
246 | 0 | { |
247 | 0 | for (const KeyString& keyString : keys) |
248 | 0 | { |
249 | 0 | Key key(keyString.latin1()); |
250 | 0 | typename Data::const_iterator it = src.findKey(key); |
251 | 0 | typename Data::iterator destIt = dest.findKey(key); |
252 | |
|
253 | 0 | if (destIt == dest.end()) |
254 | 0 | { |
255 | 0 | if (it != src.end()) |
256 | 0 | { |
257 | 0 | dest.add(*it); |
258 | 0 | } |
259 | 0 | } |
260 | 0 | else |
261 | 0 | { |
262 | 0 | if (it == src.end()) |
263 | 0 | { |
264 | 0 | dest.erase(destIt); |
265 | 0 | } |
266 | 0 | else |
267 | 0 | { |
268 | 0 | *destIt = *it; |
269 | 0 | } |
270 | 0 | } |
271 | 0 | } |
272 | 0 | } Unexecuted instantiation: KExiv2Iface::MergeHelper<Exiv2::ExifData, Exiv2::ExifKey, QLatin1String, QList<QLatin1String> >::exclusiveMerge(Exiv2::ExifData const&, Exiv2::ExifData&) const Unexecuted instantiation: KExiv2Iface::MergeHelper<Exiv2::IptcData, Exiv2::IptcKey, QLatin1String, QList<QLatin1String> >::exclusiveMerge(Exiv2::IptcData const&, Exiv2::IptcData&) const |
273 | | }; |
274 | | |
275 | | class ExifMergeHelper : public MergeHelper<Exiv2::ExifData, Exiv2::ExifKey, QLatin1String> |
276 | | { |
277 | | }; |
278 | | |
279 | | class IptcMergeHelper : public MergeHelper<Exiv2::IptcData, Exiv2::IptcKey, QLatin1String> |
280 | | { |
281 | | }; |
282 | | |
283 | | #ifdef _XMP_SUPPORT_ |
284 | | class XmpMergeHelper : public MergeHelper<Exiv2::XmpData, Exiv2::XmpKey, QLatin1String> |
285 | | { |
286 | | }; |
287 | | #endif |
288 | | |
289 | | } // NameSpace KExiv2Iface |
290 | | |
291 | | #endif // KEXIV2PRIVATE_H |