Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_meta_data_merge_strategy_p.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2008 Cyrille Berger <cberger@cberger.net>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6
8#include <klocalizedstring.h>
9
10#include "kis_debug.h"
11
12#include "kis_meta_data_entry.h"
15#include "kis_meta_data_store.h"
16#include "kis_meta_data_value.h"
17
18using namespace KisMetaData;
19
20//-------------------------------------------//
21//------------ DropMergeStrategy ------------//
22//-------------------------------------------//
23
27
31
32QString DropMergeStrategy::id() const
33{
34 return "Drop";
35}
37{
38 return i18n("Drop");
39}
40
42{
43 return i18n("Drop all meta data");
44}
45
47{
48 Q_UNUSED(dst);
49 Q_UNUSED(srcs);
50 Q_UNUSED(score);
51 dbgMetaData << "Drop meta data";
52}
53
54//---------------------------------------//
55//---------- DropMergeStrategy ----------//
56//---------------------------------------//
57
61
65
67{
68 return "PriorityToFirst";
69}
71{
72 return i18n("Priority to first meta data");
73}
74
76{
77 return i18n("Use in priority the meta data from the layers at the bottom of the stack.");
78}
79
81{
82 Q_UNUSED(score);
83 dbgMetaData << "Priority to first meta data";
84
85 Q_FOREACH (const Store* store, srcs) {
86 QList<QString> keys = store->keys();
87 Q_FOREACH (const QString & key, keys) {
88 if (!dst->containsEntry(key)) {
89 dst->addEntry(store->getEntry(key));
90 }
91 }
92 }
93}
94//-------------------------------------------//
95//------ OnlyIdenticalMergeStrategy ---------//
96//-------------------------------------------//
97
101
105
107{
108 return "OnlyIdentical";
109}
111{
112 return i18n("Only identical");
113}
114
116{
117 return i18n("Keep only meta data that are identical");
118}
119
121{
122 Q_UNUSED(score);
123 dbgMetaData << "OnlyIdenticalMergeStrategy";
124 dbgMetaData << "Priority to first meta data";
125
126 Q_ASSERT(srcs.size() > 0);
127 QList<QString> keys = srcs[0]->keys();
128 Q_FOREACH (const QString & key, keys) {
129 bool keep = true;
130 const Entry& e = srcs[0]->getEntry(key);
131 const Value& v = e.value();
132 Q_FOREACH (const Store* store, srcs) {
133 if (!(store->containsEntry(key) && e.value() == v)) {
134 keep = false;
135 break;
136 }
137 }
138 if (keep) {
139 dst->addEntry(e);
140 }
141 }
142}
143
144//-------------------------------------------//
145//------------ SmartMergeStrategy -----------//
146//-------------------------------------------//
147
151
155
157{
158 return "Smart";
159}
161{
162 return i18n("Smart");
163}
164
166{
167 return i18n("This merge strategy attempts to find the best solution for merging, "
168 "for instance by merging the list of authors together, or keeping "
169 "identical photographic information.");
170}
171
173 double score;
175};
176
178{
179 QList<ScoreValue> scoreValues;
180 for (int i = 0; i < srcs.size(); i++) {
181 if (srcs[i]->containsEntry(key)) {
182 const Value& nv = srcs[i]->getEntry(key).value();
183 if (nv.type() != Value::Invalid) {
184 bool found = false;
185 for (int j = 0; j < scoreValues.size(); j++) {
186 ScoreValue& sv = scoreValues[j];
187 if (sv.value == nv) {
188 found = true;
189 sv.score += scores[i];
190 break;
191 }
192 }
193 if (!found) {
194 ScoreValue sv;
195 sv.score = scores[i];
196 sv.value = nv;
197 scoreValues.append(sv);
198 }
199 }
200 }
201 }
202 if (scoreValues.size() < 1) {
203 warnMetaData << "SmartMergeStrategy::election returned less than 1 score value";
204 return Value();
205 }
206 const ScoreValue* bestSv = 0;
207 double bestScore = -1.0;
208 Q_FOREACH (const ScoreValue& sv, scoreValues) {
209 if (sv.score > bestScore) {
210 bestScore = sv.score;
211 bestSv = &sv;
212 }
213 }
214 if (bestSv) {
215 return bestSv->value;
216 }
217 else {
218 return Value();
219 }
220}
221
222void SmartMergeStrategy::mergeEntry(Store* dst, QList<const Store*> srcs, const KisMetaData::Schema* schema, const QString & identifier) const
223{
224 bool foundOnce = false;
226 Q_FOREACH (const Store* store, srcs) {
227 if (store->containsEntry(schema, identifier)) {
228 v += store->getEntry(schema, identifier).value();
229 foundOnce = true;
230 }
231 }
232 if (foundOnce) {
233 dst->getEntry(schema, identifier).value() = v;
234 }
235}
236
238{
239 dbgMetaData << "Smart merging of meta data";
240 Q_ASSERT(srcs.size() == scores.size());
241 Q_ASSERT(srcs.size() > 0);
242 if (srcs.size() == 1) {
243 dst->copyFrom(srcs[0]);
244 return;
245 }
246 // Initialize some schema
248// const KisMetaData::Schema* psSchema = KisMetaData::SchemaRegistry::instance()->schemaFromUri(KisMetaData::Schema::PhotoshopSchemaUri);
251 // Sort the stores and scores
252 {
253 QMultiMap<double, const Store*> scores2srcs;
254 for (int i = 0; i < scores.size(); ++i) {
255 scores2srcs.insert(scores[i], srcs[i]);
256 }
257 srcs = scores2srcs.values();
258 scores = scores2srcs.keys();
259 }
260
261 // First attempt to see if one of the store has a higher score than the others
262 if (scores[0] > 2 * scores[1]) { // One of the store has a higher importance than the other ones
263 dst->copyFrom(srcs[0]);
264 } else {
265 // Merge exif info
266
267
268 // Election
269 Q_FOREACH (const Store* store, srcs) {
270 QList<QString> keys = store->keys();
271 Q_FOREACH (const QString & key, keys) {
272 if (!dst->containsEntry(key)) {
273 Value v = election(srcs, scores, key);
274 if (v.type() != Value::Invalid) {
275 dst->getEntry(key).value() = v;
276 }
277 }
278 }
279 }
280
281 // Compute rating
282 double rating = 0.0;
283 double norm = 0.0;
284 for (int i = 0; i < srcs.size(); i++) {
285 const Store* store = srcs[i];
286 if (store->containsEntry(XMPSchema, "Rating")) {
287 double score = scores[i];
288 rating += score * store->getEntry(XMPSchema, "Rating").value().asVariant().toDouble();
289 norm += score;
290 }
291 }
292 if (norm > 0.01) {
293 dst->getEntry(XMPSchema, "Rating").value() = QVariant((int)(rating / norm));
294 }
295 }
296 // Merge the list of authors and keywords and other stuff
297 mergeEntry(dst, srcs, dcSchema, "contributor");
298 mergeEntry(dst, srcs, dcSchema, "creator");
299 mergeEntry(dst, srcs, dcSchema, "publisher");
300 mergeEntry(dst, srcs, dcSchema, "subject");
301 mergeEntry(dst, srcs, XMPRightsSchema, "Owner");
302 mergeEntry(dst, srcs, XMPSchema, "Identifier");
303}
qreal v
void merge(Store *dst, QList< const Store * > srcs, QList< double > score) const override
const KisMetaData::Value & value() const
void merge(Store *dst, QList< const Store * > srcs, QList< double > score) const override
void merge(Store *dst, QList< const Store * > srcs, QList< double > score) const override
static KisMetaData::SchemaRegistry * instance()
const Schema * schemaFromUri(const QString &uri) const
static const QString XMPRightsSchemaUri
static const QString DublinCoreSchemaUri
static const QString XMPSchemaUri
Value election(QList< const Store * > srcs, QList< double > score, const QString &key) const
void mergeEntry(Store *dst, QList< const Store * > srcs, const Schema *schema, const QString &identifier) const
void merge(Store *dst, QList< const Store * > srcs, QList< double > score) const override
void copyFrom(const Store *store)
QList< QString > keys() const
bool addEntry(const Entry &entry)
bool containsEntry(const QString &entryKey) const
Entry & getEntry(const QString &entryKey)
QVariant asVariant() const
ValueType type() const
#define warnMetaData
Definition kis_debug.h:103
#define dbgMetaData
Definition kis_debug.h:61