Coverage Report

Created: 2026-10-28 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libkexiv2/src/kexiv2iptc.cpp
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
// Local includes
9
10
#include "kexiv2.h"
11
#include "kexiv2_p.h"
12
#include "libkexiv2_debug.h"
13
14
namespace KExiv2Iface
15
{
16
17
bool KExiv2::canWriteIptc(const QString& filePath)
18
0
{
19
0
    try
20
0
    {
21
0
#if EXIV2_TEST_VERSION(0,28,0)
22
0
        Exiv2::Image::UniquePtr image = 
23
#else
24
        Exiv2::Image::AutoPtr image = 
25
#endif
26
0
                                      Exiv2::ImageFactory::open((const char*)
27
0
                                      (QFile::encodeName(filePath).constData()));
28
29
0
        Exiv2::AccessMode mode = image->checkMode(Exiv2::mdIptc);
30
0
        return (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite);
31
0
    }
32
0
    catch(Exiv2::Error& e)
33
0
    {
34
0
        std::string s(e.what());
35
0
        qCCritical(LIBKEXIV2_LOG) << "Cannot check Iptc access mode using Exiv2 (Error #"
36
0
#if EXIV2_TEST_VERSION(0,28,0)
37
0
                                  << Exiv2::Error(e.code()).what()
38
#else
39
                                  << e.code() << ": " << s.c_str()
40
#endif
41
0
                                  << ")";
42
0
    }
43
0
    catch(...)
44
0
    {
45
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
46
0
    }
47
48
0
    return false;
49
0
}
50
51
bool KExiv2::hasIptc() const
52
0
{
53
0
    return !d->iptcMetadata().empty();
54
0
}
55
56
bool KExiv2::clearIptc() const
57
0
{
58
0
    try
59
0
    {
60
0
        d->iptcMetadata().clear();
61
0
        return true;
62
0
    }
63
0
    catch(Exiv2::Error& e)
64
0
    {
65
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot clear Iptc data using Exiv2 "), e);
66
0
    }
67
0
    catch(...)
68
0
    {
69
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
70
0
    }
71
72
0
    return false;
73
0
}
74
75
QByteArray KExiv2::getIptc(bool addIrbHeader) const
76
0
{
77
0
    try
78
0
    {
79
0
        if (!d->iptcMetadata().empty())
80
0
        {
81
0
            Exiv2::IptcData& iptc = d->iptcMetadata();
82
0
            Exiv2::DataBuf c2;
83
84
0
            if (addIrbHeader)
85
0
            {
86
0
                c2 = Exiv2::Photoshop::setIptcIrb(nullptr, 0, iptc);
87
0
            }
88
0
            else
89
0
            {
90
0
                c2 = Exiv2::IptcParser::encode(d->iptcMetadata());
91
0
            }
92
93
0
#if EXIV2_TEST_VERSION(0,28,0)
94
0
            QByteArray data((const char*)c2.c_data(), c2.size());
95
#else
96
            QByteArray data((const char*)c2.pData_, c2.size_);
97
#endif
98
0
            return data;
99
100
0
        }
101
0
    }
102
0
    catch(Exiv2::Error& e)
103
0
    {
104
0
        if (!d->filePath.isEmpty())
105
0
        {
106
0
            qCCritical(LIBKEXIV2_LOG) << "From file " << d->filePath.toLatin1().constData();
107
0
        }
108
109
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Iptc data using Exiv2 "), e);
110
0
    }
111
0
    catch(...)
112
0
    {
113
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
114
0
    }
115
116
0
    return QByteArray();
117
0
}
118
119
bool KExiv2::setIptc(const QByteArray& data) const
120
0
{
121
0
    try
122
0
    {
123
0
        if (!data.isEmpty())
124
0
        {
125
0
            Exiv2::IptcParser::decode(d->iptcMetadata(), (const Exiv2::byte*)data.data(), data.size());
126
0
            return (!d->iptcMetadata().empty());
127
0
        }
128
0
    }
129
0
    catch(Exiv2::Error& e)
130
0
    {
131
0
        if (!d->filePath.isEmpty())
132
0
        {
133
0
            qCCritical(LIBKEXIV2_LOG) << "From file " << d->filePath.toLatin1().constData();
134
0
        }
135
136
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc data using Exiv2 "), e);
137
0
    }
138
0
    catch(...)
139
0
    {
140
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
141
0
    }
142
143
0
    return false;
144
0
}
145
146
KExiv2::MetaDataMap KExiv2::getIptcTagsDataList(const QStringList& iptcKeysFilter, bool invertSelection) const
147
0
{
148
0
    if (d->iptcMetadata().empty())
149
0
       return MetaDataMap();
150
151
0
    try
152
0
    {
153
0
        Exiv2::IptcData iptcData = d->iptcMetadata();
154
0
        iptcData.sortByKey();
155
156
0
        QString     ifDItemName;
157
0
        MetaDataMap metaDataMap;
158
159
0
        for (Exiv2::IptcData::iterator md = iptcData.begin(); md != iptcData.end(); ++md)
160
0
        {
161
0
            QString key = QString::fromLocal8Bit(md->key().c_str());
162
163
            // Decode the tag value with a user friendly output.
164
0
            std::ostringstream os;
165
0
            os << *md;
166
167
0
            QString value;
168
169
0
            if (key == QString::fromLatin1("Iptc.Envelope.CharacterSet"))
170
0
            {
171
0
                value = QString::fromLatin1(iptcData.detectCharset());
172
0
            }
173
0
            else 
174
0
            {
175
0
                value = QString::fromUtf8(os.str().c_str());
176
0
            }
177
178
            // To make a string just on one line.
179
0
            value.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
180
181
            // Some Iptc key are redondancy. check if already one exist...
182
0
            MetaDataMap::iterator it = metaDataMap.find(key);
183
184
            // We apply a filter to get only the Iptc tags that we need.
185
186
0
            if (!iptcKeysFilter.isEmpty())
187
0
            {
188
0
                if (!invertSelection)
189
0
                {
190
0
                    if (iptcKeysFilter.contains(key.section(QString::fromLatin1("."), 1, 1)))
191
0
                    {
192
0
                        if (it == metaDataMap.end())
193
0
                        {
194
0
                            metaDataMap.insert(key, value);
195
0
                        }
196
0
                        else
197
0
                        {
198
0
                            QString v = *it;
199
0
                            v.append(QString::fromLatin1(", "));
200
0
                            v.append(value);
201
0
                            metaDataMap.insert(key, v);
202
0
                        }
203
0
                    }
204
0
                }
205
0
                else
206
0
                {
207
0
                    if (!iptcKeysFilter.contains(key.section(QString::fromLatin1("."), 1, 1)))
208
0
                    {
209
0
                        if (it == metaDataMap.end())
210
0
                        {
211
0
                            metaDataMap.insert(key, value);
212
0
                        }
213
0
                        else
214
0
                        {
215
0
                            QString v = *it;
216
0
                            v.append(QString::fromLatin1(", "));
217
0
                            v.append(value);
218
0
                            metaDataMap.insert(key, v);
219
0
                        }
220
0
                    }
221
0
                }
222
0
            }
223
0
            else // else no filter at all.
224
0
            {
225
0
                if (it == metaDataMap.end())
226
0
                {
227
0
                    metaDataMap.insert(key, value);
228
0
                }
229
0
                else
230
0
                {
231
0
                    QString v = *it;
232
0
                    v.append(QString::fromLatin1(", "));
233
0
                    v.append(value);
234
0
                    metaDataMap.insert(key, v);
235
0
                    }
236
0
            }
237
238
0
        }
239
240
0
        return metaDataMap;
241
0
    }
242
0
    catch (Exiv2::Error& e)
243
0
    {
244
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot parse Iptc metadata using Exiv2 "), e);
245
0
    }
246
0
    catch(...)
247
0
    {
248
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
249
0
    }
250
251
0
    return MetaDataMap();
252
0
}
253
254
QString KExiv2::getIptcTagTitle(const char* iptcTagName)
255
0
{
256
0
    try
257
0
    {
258
0
        std::string iptckey(iptcTagName);
259
0
        Exiv2::IptcKey ik(iptckey);
260
0
        return QString::fromLocal8Bit( Exiv2::IptcDataSets::dataSetTitle(ik.tag(), ik.record()) );
261
0
    }
262
0
    catch (Exiv2::Error& e)
263
0
    {
264
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot get metadata tag title using Exiv2 "), e);
265
0
    }
266
0
    catch(...)
267
0
    {
268
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
269
0
    }
270
271
0
    return QString();
272
0
}
273
274
QString KExiv2::getIptcTagDescription(const char* iptcTagName)
275
0
{
276
0
    try
277
0
    {
278
0
        std::string iptckey(iptcTagName);
279
0
        Exiv2::IptcKey ik(iptckey);
280
0
        return QString::fromLocal8Bit( Exiv2::IptcDataSets::dataSetDesc(ik.tag(), ik.record()) );
281
0
    }
282
0
    catch (Exiv2::Error& e)
283
0
    {
284
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot get metadata tag description using Exiv2 "), e);
285
0
    }
286
0
    catch(...)
287
0
    {
288
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
289
0
    }
290
291
0
    return QString();
292
0
}
293
294
bool KExiv2::removeIptcTag(const char* iptcTagName, bool setProgramName) const
295
0
{
296
0
    if (!setProgramId(setProgramName))
297
0
        return false;
298
299
0
    try
300
0
    {
301
0
        Exiv2::IptcData::iterator it = d->iptcMetadata().begin();
302
0
        int i                        = 0;
303
304
0
        while(it != d->iptcMetadata().end())
305
0
        {
306
0
            QString key = QString::fromLocal8Bit(it->key().c_str());
307
308
0
            if (key == QString::fromLatin1(iptcTagName))
309
0
            {
310
0
                it = d->iptcMetadata().erase(it);
311
0
                ++i;
312
0
            }
313
0
            else
314
0
            {
315
0
                ++it;
316
0
            }
317
0
        };
318
319
0
        if (i > 0)
320
0
            return true;
321
0
    }
322
0
    catch(Exiv2::Error& e)
323
0
    {
324
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot remove Iptc tag using Exiv2 "), e);
325
0
    }
326
0
    catch(...)
327
0
    {
328
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
329
0
    }
330
331
0
    return false;
332
0
}
333
334
bool KExiv2::setIptcTagData(const char* iptcTagName, const QByteArray& data, bool setProgramName) const
335
0
{
336
0
    if (data.isEmpty())
337
0
        return false;
338
339
0
    if (!setProgramId(setProgramName))
340
0
        return false;
341
342
0
    try
343
0
    {
344
0
        Exiv2::DataValue val((Exiv2::byte *)data.data(), data.size());
345
0
        d->iptcMetadata()[iptcTagName] = val;
346
0
        return true;
347
0
    }
348
0
    catch(Exiv2::Error& e)
349
0
    {
350
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc tag data into image using Exiv2 "), e);
351
0
    }
352
0
    catch(...)
353
0
    {
354
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
355
0
    }
356
357
0
    return false;
358
0
}
359
360
QByteArray KExiv2::getIptcTagData(const char* iptcTagName) const
361
0
{
362
0
    try
363
0
    {
364
0
        Exiv2::IptcKey  iptcKey(iptcTagName);
365
0
        Exiv2::IptcData iptcData(d->iptcMetadata());
366
0
        Exiv2::IptcData::iterator it = iptcData.findKey(iptcKey);
367
368
0
        if (it != iptcData.end())
369
0
        {
370
0
            char* const s = new char[(*it).size()];
371
0
            (*it).copy((Exiv2::byte*)s, Exiv2::bigEndian);
372
0
            QByteArray data(s, (*it).size());
373
0
            delete [] s;
374
0
            return data;
375
0
        }
376
0
    }
377
0
    catch(Exiv2::Error& e)
378
0
    {
379
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Iptc key '%1' into image using Exiv2 ").arg(QString::fromLatin1(iptcTagName)), e);
380
0
    }
381
0
    catch(...)
382
0
    {
383
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
384
0
    }
385
386
0
    return QByteArray();
387
0
}
388
389
QString KExiv2::getIptcTagString(const char* iptcTagName, bool escapeCR) const
390
0
{
391
0
    try
392
0
    {
393
0
        Exiv2::IptcKey  iptcKey(iptcTagName);
394
0
        Exiv2::IptcData iptcData(d->iptcMetadata());
395
0
        Exiv2::IptcData::iterator it = iptcData.findKey(iptcKey);
396
397
0
        if (it != iptcData.end())
398
0
        {
399
0
            std::ostringstream os;
400
0
            os << *it;
401
0
            QString tagValue(QString::fromLatin1(os.str().c_str()));
402
403
0
            if (escapeCR)
404
0
                tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
405
406
0
            return tagValue;
407
0
        }
408
0
    }
409
0
    catch(Exiv2::Error& e)
410
0
    {
411
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Iptc key '%1' into image using Exiv2 ").arg(QString::fromLatin1(iptcTagName)), e);
412
0
    }
413
0
    catch(...)
414
0
    {
415
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
416
0
    }
417
418
0
    return QString();
419
0
}
420
421
bool KExiv2::setIptcTagString(const char* iptcTagName, const QString& value, bool setProgramName) const
422
0
{
423
0
    if (!setProgramId(setProgramName))
424
0
        return false;
425
426
0
    try
427
0
    {
428
0
        d->iptcMetadata()[iptcTagName] = std::string(value.toUtf8().constData());
429
430
        // Make sure we have set the charset to UTF-8
431
0
        d->iptcMetadata()["Iptc.Envelope.CharacterSet"] = "\33%G";
432
0
        return true;
433
0
    }
434
0
    catch(Exiv2::Error& e)
435
0
    {
436
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc tag string into image using Exiv2 "), e);
437
0
    }
438
0
    catch(...)
439
0
    {
440
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
441
0
    }
442
443
0
    return false;
444
0
}
445
446
QStringList KExiv2::getIptcTagsStringList(const char* iptcTagName, bool escapeCR) const
447
0
{
448
0
    try
449
0
    {
450
0
        if (!d->iptcMetadata().empty())
451
0
        {
452
0
            QStringList values;
453
0
            Exiv2::IptcData iptcData(d->iptcMetadata());
454
455
0
            for (Exiv2::IptcData::iterator it = iptcData.begin(); it != iptcData.end(); ++it)
456
0
            {
457
0
                QString key = QString::fromLocal8Bit(it->key().c_str());
458
459
0
                if (key == QString::fromLatin1(iptcTagName))
460
0
                {
461
0
                    QString tagValue = QString::fromUtf8(it->toString().c_str());
462
463
0
                    if (escapeCR)
464
0
                        tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
465
466
0
                    values.append(tagValue);
467
0
                }
468
0
            }
469
470
0
            return values;
471
0
        }
472
0
    }
473
0
    catch(Exiv2::Error& e)
474
0
    {
475
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Iptc key '%1' into image using Exiv2 ").arg(QString::fromLatin1(iptcTagName)), e);
476
0
    }
477
0
    catch(...)
478
0
    {
479
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
480
0
    }
481
482
0
    return QStringList();
483
0
}
484
485
bool KExiv2::setIptcTagsStringList(const char* iptcTagName, int maxSize,
486
                                   const QStringList& oldValues, const QStringList& newValues,
487
                                   bool setProgramName) const
488
0
{
489
0
    if (!setProgramId(setProgramName))
490
0
        return false;
491
492
0
    try
493
0
    {
494
0
        QStringList oldvals = oldValues;
495
0
        QStringList newvals = newValues;
496
497
0
        qCDebug(LIBKEXIV2_LOG) << d->filePath.toLatin1().constData() << " : " << iptcTagName
498
0
                 << " => " << newvals.join(QString::fromLatin1(",")).toLatin1().constData();
499
500
        // Remove all old values.
501
0
        Exiv2::IptcData iptcData(d->iptcMetadata());
502
0
        Exiv2::IptcData::iterator it = iptcData.begin();
503
504
0
        while(it != iptcData.end())
505
0
        {
506
0
            QString key = QString::fromLocal8Bit(it->key().c_str());
507
0
            QString val = QString::fromUtf8(it->toString().c_str());
508
509
            // Also remove new values to avoid duplicates. They will be added again below.
510
0
            if ( key == QString::fromLatin1(iptcTagName) &&
511
0
                 (oldvals.contains(val) || newvals.contains(val))
512
0
               )
513
0
                it = iptcData.erase(it);
514
0
            else
515
0
                ++it;
516
0
        };
517
518
        // Add new values.
519
520
0
        Exiv2::IptcKey iptcTag(iptcTagName);
521
522
0
        for (QStringList::iterator it = newvals.begin(); it != newvals.end(); ++it)
523
0
        {
524
0
            QString key = *it;
525
0
            key.truncate(maxSize);
526
527
0
#if EXIV2_TEST_VERSION(0,28,0)
528
0
            Exiv2::Value::UniquePtr val = Exiv2::Value::create(Exiv2::string);
529
#else
530
            Exiv2::Value::AutoPtr val = Exiv2::Value::create(Exiv2::string);
531
#endif
532
0
            val->read(key.toUtf8().constData());
533
0
            iptcData.add(iptcTag, val.get());
534
0
        }
535
536
0
        d->iptcMetadata() = iptcData;
537
538
        // Make sure character set is UTF-8
539
0
        setIptcTagString("Iptc.Envelope.CharacterSet", QString::fromLatin1("\33%G"), false);
540
541
0
        return true;
542
0
    }
543
0
    catch(Exiv2::Error& e)
544
0
    {
545
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc key '%1' into image using Exiv2 ").arg(QString::fromLatin1(iptcTagName)), e);
546
0
    }
547
0
    catch(...)
548
0
    {
549
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
550
0
    }
551
552
0
    return false;
553
0
}
554
555
QStringList KExiv2::getIptcKeywords() const
556
0
{
557
0
    try
558
0
    {
559
0
        if (!d->iptcMetadata().empty())
560
0
        {
561
0
            QStringList keywords;
562
0
            Exiv2::IptcData iptcData(d->iptcMetadata());
563
564
0
            for (Exiv2::IptcData::iterator it = iptcData.begin(); it != iptcData.end(); ++it)
565
0
            {
566
0
                QString key = QString::fromLocal8Bit(it->key().c_str());
567
568
0
                if (key == QString::fromLatin1("Iptc.Application2.Keywords"))
569
0
                {
570
0
                    QString val = QString::fromUtf8(it->toString().c_str());
571
0
                    keywords.append(val);
572
0
                }
573
0
            }
574
575
0
            qCDebug(LIBKEXIV2_LOG) << d->filePath << " ==> Read Iptc Keywords: " << keywords;
576
577
0
            return keywords;
578
0
        }
579
0
    }
580
0
    catch(Exiv2::Error& e)
581
0
    {
582
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Iptc Keywords from image using Exiv2 "), e);
583
0
    }
584
0
    catch(...)
585
0
    {
586
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
587
0
    }
588
589
0
    return QStringList();
590
0
}
591
592
bool KExiv2::setIptcKeywords(const QStringList& oldKeywords, const QStringList& newKeywords,
593
                             bool setProgramName) const
594
0
{
595
0
    if (!setProgramId(setProgramName))
596
0
        return false;
597
598
0
    try
599
0
    {
600
0
        QStringList oldkeys = oldKeywords;
601
0
        QStringList newkeys = newKeywords;
602
603
0
        qCDebug(LIBKEXIV2_LOG) << d->filePath << " ==> New Iptc Keywords: " << newkeys;
604
605
        // Remove all old keywords.
606
0
        Exiv2::IptcData iptcData(d->iptcMetadata());
607
0
        Exiv2::IptcData::iterator it = iptcData.begin();
608
609
0
        while(it != iptcData.end())
610
0
        {
611
0
            QString key = QString::fromLocal8Bit(it->key().c_str());
612
0
            QString val = QString::fromUtf8(it->toString().c_str());
613
614
            // Also remove new keywords to avoid duplicates. They will be added again below.
615
0
            if ( key == QString::fromLatin1("Iptc.Application2.Keywords") &&
616
0
                 (oldKeywords.contains(val) || newKeywords.contains(val))
617
0
               )
618
0
                it = iptcData.erase(it);
619
0
            else
620
0
                ++it;
621
0
        };
622
623
        // Add new keywords. Note that Keywords Iptc tag is limited to 64 char but can be redondant.
624
625
0
        Exiv2::IptcKey iptcTag("Iptc.Application2.Keywords");
626
627
0
        for (QStringList::iterator it = newkeys.begin(); it != newkeys.end(); ++it)
628
0
        {
629
0
            QString key = *it;
630
0
            key.truncate(64);
631
632
0
#if EXIV2_TEST_VERSION(0,28,0)
633
0
            Exiv2::Value::UniquePtr val = Exiv2::Value::create(Exiv2::string);
634
#else
635
            Exiv2::Value::AutoPtr val = Exiv2::Value::create(Exiv2::string);
636
#endif
637
0
            val->read(key.toUtf8().constData());
638
0
            iptcData.add(iptcTag, val.get());
639
0
        }
640
641
0
        d->iptcMetadata() = iptcData;
642
643
        // Make sure character set is UTF-8
644
0
        setIptcTagString("Iptc.Envelope.CharacterSet", QString::fromLatin1("\33%G"), false);
645
646
0
        return true;
647
0
    }
648
0
    catch(Exiv2::Error& e)
649
0
    {
650
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc Keywords into image using Exiv2 "), e);
651
0
    }
652
0
    catch(...)
653
0
    {
654
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
655
0
    }
656
657
0
    return false;
658
0
}
659
660
QStringList KExiv2::getIptcSubjects() const
661
0
{
662
0
    try
663
0
    {
664
0
        if (!d->iptcMetadata().empty())
665
0
        {
666
0
            QStringList subjects;
667
0
            Exiv2::IptcData iptcData(d->iptcMetadata());
668
669
0
            for (Exiv2::IptcData::iterator it = iptcData.begin(); it != iptcData.end(); ++it)
670
0
            {
671
0
                QString key = QString::fromLocal8Bit(it->key().c_str());
672
673
0
                if (key == QString::fromLatin1("Iptc.Application2.Subject"))
674
0
                {
675
0
                    QString val(QString::fromLatin1(it->toString().c_str()));
676
0
                    subjects.append(val);
677
0
                }
678
0
            }
679
680
0
            return subjects;
681
0
        }
682
0
    }
683
0
    catch(Exiv2::Error& e)
684
0
    {
685
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Iptc Subjects from image using Exiv2 "), e);
686
0
    }
687
0
    catch(...)
688
0
    {
689
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
690
0
    }
691
692
0
    return QStringList();
693
0
}
694
695
bool KExiv2::setIptcSubjects(const QStringList& oldSubjects, const QStringList& newSubjects,
696
                             bool setProgramName) const
697
0
{
698
0
    if (!setProgramId(setProgramName))
699
0
        return false;
700
701
0
    try
702
0
    {
703
0
        QStringList oldDef = oldSubjects;
704
0
        QStringList newDef = newSubjects;
705
706
        // Remove all old subjects.
707
0
        Exiv2::IptcData iptcData(d->iptcMetadata());
708
0
        Exiv2::IptcData::iterator it = iptcData.begin();
709
710
0
        while(it != iptcData.end())
711
0
        {
712
0
            QString key = QString::fromLocal8Bit(it->key().c_str());
713
0
            QString val = QString::fromUtf8(it->toString().c_str());
714
715
0
            if (key == QString::fromLatin1("Iptc.Application2.Subject") && oldDef.contains(val))
716
0
                it = iptcData.erase(it);
717
0
            else
718
0
                ++it;
719
0
        };
720
721
        // Add new subjects. Note that Keywords Iptc tag is limited to 236 char but can be redondant.
722
723
0
        Exiv2::IptcKey iptcTag("Iptc.Application2.Subject");
724
725
0
        for (QStringList::iterator it = newDef.begin(); it != newDef.end(); ++it)
726
0
        {
727
0
            QString key = *it;
728
0
            key.truncate(236);
729
730
0
#if EXIV2_TEST_VERSION(0,28,0)
731
0
            Exiv2::Value::UniquePtr val = Exiv2::Value::create(Exiv2::string);
732
#else
733
            Exiv2::Value::AutoPtr val = Exiv2::Value::create(Exiv2::string);
734
#endif
735
0
            val->read(key.toUtf8().constData());
736
0
            iptcData.add(iptcTag, val.get());
737
0
        }
738
739
0
        d->iptcMetadata() = iptcData;
740
741
        // Make sure character set is UTF-8
742
0
        setIptcTagString("Iptc.Envelope.CharacterSet", QString::fromLatin1("\33%G"), false);
743
744
0
        return true;
745
0
    }
746
0
    catch(Exiv2::Error& e)
747
0
    {
748
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc Subjects into image using Exiv2 "), e);
749
0
    }
750
0
    catch(...)
751
0
    {
752
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
753
0
    }
754
755
0
    return false;
756
0
}
757
758
QStringList KExiv2::getIptcSubCategories() const
759
0
{
760
0
    try
761
0
    {
762
0
        if (!d->iptcMetadata().empty())
763
0
        {
764
0
            QStringList subCategories;
765
0
            Exiv2::IptcData iptcData(d->iptcMetadata());
766
767
0
            for (Exiv2::IptcData::iterator it = iptcData.begin(); it != iptcData.end(); ++it)
768
0
            {
769
0
                QString key = QString::fromLocal8Bit(it->key().c_str());
770
771
0
                if (key == QString::fromLatin1("Iptc.Application2.SuppCategory"))
772
0
                {
773
0
                    QString val(QString::fromLatin1(it->toString().c_str()));
774
0
                    subCategories.append(val);
775
0
                }
776
0
            }
777
778
0
            return subCategories;
779
0
        }
780
0
    }
781
0
    catch(Exiv2::Error& e)
782
0
    {
783
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Iptc Sub Categories from image using Exiv2 "), e);
784
0
    }
785
0
    catch(...)
786
0
    {
787
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
788
0
    }
789
790
0
    return QStringList();
791
0
}
792
793
bool KExiv2::setIptcSubCategories(const QStringList& oldSubCategories, const QStringList& newSubCategories,
794
                                  bool setProgramName) const
795
0
{
796
0
    if (!setProgramId(setProgramName))
797
0
        return false;
798
799
0
    try
800
0
    {
801
0
        QStringList oldkeys = oldSubCategories;
802
0
        QStringList newkeys = newSubCategories;
803
804
        // Remove all old Sub Categories.
805
0
        Exiv2::IptcData iptcData(d->iptcMetadata());
806
0
        Exiv2::IptcData::iterator it = iptcData.begin();
807
808
0
        while(it != iptcData.end())
809
0
        {
810
0
            QString key = QString::fromLocal8Bit(it->key().c_str());
811
0
            QString val = QString::fromUtf8(it->toString().c_str());
812
813
0
            if (key == QString::fromLatin1("Iptc.Application2.SuppCategory") && oldSubCategories.contains(val))
814
0
                it = iptcData.erase(it);
815
0
            else
816
0
                ++it;
817
0
        };
818
819
        // Add new Sub Categories. Note that SubCategories Iptc tag is limited to 32
820
        // characters but can be redondant.
821
822
0
        Exiv2::IptcKey iptcTag("Iptc.Application2.SuppCategory");
823
824
0
        for (QStringList::iterator it = newkeys.begin(); it != newkeys.end(); ++it)
825
0
        {
826
0
            QString key = *it;
827
0
            key.truncate(32);
828
829
0
#if EXIV2_TEST_VERSION(0,28,0)
830
0
            Exiv2::Value::UniquePtr val = Exiv2::Value::create(Exiv2::string);
831
#else
832
            Exiv2::Value::AutoPtr val = Exiv2::Value::create(Exiv2::string);
833
#endif
834
0
            val->read(key.toUtf8().constData());
835
0
            iptcData.add(iptcTag, val.get());
836
0
        }
837
838
0
        d->iptcMetadata() = iptcData;
839
840
        // Make sure character set is UTF-8
841
0
        setIptcTagString("Iptc.Envelope.CharacterSet", QString::fromLatin1("\33%G"), false);
842
843
0
        return true;
844
0
    }
845
0
    catch(Exiv2::Error& e)
846
0
    {
847
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc Sub Categories into image using Exiv2 "), e);
848
0
    }
849
0
    catch(...)
850
0
    {
851
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
852
0
    }
853
854
0
    return false;
855
0
}
856
857
KExiv2::TagsMap KExiv2::getIptcTagsList() const
858
0
{
859
0
    try
860
0
    {
861
0
        QList<const Exiv2::DataSet*> tags;
862
0
        tags << Exiv2::IptcDataSets::envelopeRecordList()
863
0
             << Exiv2::IptcDataSets::application2RecordList();
864
865
0
        TagsMap tagsMap;
866
867
0
        for (QList<const Exiv2::DataSet*>::iterator it = tags.begin(); it != tags.end(); ++it)
868
0
        {
869
0
            do
870
0
            {
871
0
                QString     key = QLatin1String( Exiv2::IptcKey( (*it)->number_, (*it)->recordId_ ).key().c_str() );
872
0
                QStringList values;
873
0
                values << QString::fromLatin1((*it)->name_) << QString::fromLatin1((*it)->title_) << QString::fromLatin1((*it)->desc_);
874
0
                tagsMap.insert(key, values);
875
0
                ++(*it);
876
0
            }
877
0
            while((*it)->number_ != 0xffff);
878
0
        }
879
880
0
        return tagsMap;
881
0
    }
882
0
    catch(Exiv2::Error& e)
883
0
    {
884
0
        d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Iptc Tags list using Exiv2 "), e);
885
0
    }
886
0
    catch(...)
887
0
    {
888
0
        qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
889
0
    }
890
891
0
    return TagsMap();
892
0
}
893
894
}  // NameSpace KExiv2Iface