1 /** ===========================================================
2 * @file
3 *
4 * This file is a part of KDE project
5 *
6 *
7 * @date 2009-11-21
8 * @brief kipi host test application
9 *
10 * @author Copyright (C) 2009-2010 by Michael G. Hansen
11 * <a href="mailto:mike at mghansen dot de">mike at mghansen dot de</a>
12 * @author Copyright (C) 2011-2018 by Gilles Caulier
13 * <a href="mailto:caulier dot gilles at gmail dot com">caulier dot gilles at gmail dot com</a>
14 *
15 * This program is free software; you can redistribute it
16 * and/or modify it under the terms of the GNU General
17 * Public License as published by the Free Software Foundation;
18 * either version 2, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * ============================================================ */
26
27 #include "kipiinterface.h"
28
29 // Qt includes
30
31 #include <QTextStream>
32 #include <QDebug>
33 #include <QIcon>
34 #include <QFileInfo>
35
36 // Libkipi includes
37
38 #include "libkipi_version.h"
39 #include "imagecollection.h"
40
41 // KF includes
42
43 #ifdef HAVE_KEXIV2
44 # include <kexiv2/kexiv2.h>
45 #endif
46
47 // Local includes
48
49 #include "kipiimageinfoshared.h"
50 #include "kipiimagecollectionselector.h"
51 #include "kipiuploadwidget.h"
52 #include "kipiimagecollectionshared.h"
53 #include "kipiwriteimage.h"
54
55 namespace KXMLKipiCmd
56 {
57
KipiInterface(QObject * const parent,const QString & name)58 KipiInterface::KipiInterface(QObject* const parent, const QString& name)
59 : Interface(parent, name),
60 m_selectedImages(),
61 m_selectedAlbums(),
62 m_albums()
63 {
64 }
65
~KipiInterface()66 KipiInterface::~KipiInterface()
67 {
68 }
69
currentAlbum()70 ImageCollection KipiInterface::currentAlbum()
71 {
72 qDebug() << "Called by plugins";
73
74 QUrl currentAlbumUrl;
75
76 if (!m_selectedAlbums.isEmpty())
77 {
78 currentAlbumUrl = m_selectedAlbums.at(0);
79 }
80
81 return (ImageCollection(new KipiImageCollectionShared(currentAlbumUrl)));
82 }
83
currentSelection()84 ImageCollection KipiInterface::currentSelection()
85 {
86 qDebug() << "Called by plugins";
87
88 return (ImageCollection(new KipiImageCollectionShared(m_selectedImages)));
89 }
90
allAlbums()91 QList<ImageCollection> KipiInterface::allAlbums()
92 {
93 QList<ImageCollection> listAllAlbums;
94
95 for (QList<QUrl>::const_iterator it = m_albums.constBegin(); it!=m_albums.constEnd(); ++it)
96 {
97 listAllAlbums.append(ImageCollection(new KipiImageCollectionShared(*it)));
98 }
99
100 // make sure albums which have been specified as selectedalbums are also in the allAlbums list:
101 for (QList<QUrl>::const_iterator it = m_selectedAlbums.constBegin(); it!=m_selectedAlbums.constEnd(); ++it)
102 {
103 if (!m_albums.contains(*it))
104 {
105 listAllAlbums.append(ImageCollection(new KipiImageCollectionShared(*it)));
106 }
107 }
108
109 return listAllAlbums;
110 }
111
info(const QUrl & url)112 ImageInfo KipiInterface::info(const QUrl& url)
113 {
114 qDebug() << QString::fromLatin1( "Plugin wants information about image \"%1\"").arg( url.url() );
115
116 return (ImageInfo(new KipiImageInfoShared(this, url)));
117 }
118
addImage(const QUrl & url,QString & errmsg)119 bool KipiInterface::addImage(const QUrl& url, QString& errmsg)
120 {
121 Q_UNUSED(errmsg);
122 qDebug() << QString::fromLatin1( "Plugin added an image: \"%1\"").arg( url.url() );
123
124 return true;
125 }
126
delImage(const QUrl & url)127 void KipiInterface::delImage(const QUrl& url)
128 {
129 qDebug() << QString::fromLatin1( "Plugin deleted an image: \"%1\"").arg( url.url() );
130 }
131
refreshImages(const QList<QUrl> & urls)132 void KipiInterface::refreshImages(const QList<QUrl>& urls)
133 {
134 qDebug() << QString::fromLatin1( "Plugin asks to refresh %1 images:").arg( urls.size() );
135
136 for (QList<QUrl>::ConstIterator it = urls.constBegin(); it!=urls.constEnd(); ++it)
137 {
138 qDebug() << QString::fromLatin1(" ") + (*it).url();
139 }
140 }
141
features() const142 int KipiInterface::features() const
143 {
144 qDebug() << "Called by plugins";
145
146 return ImagesHasTime
147 #ifdef HAVE_KEXIV2
148 | HostSupportsMetadataProcessing
149 #endif
150
151 ;
152 }
153
imageCollectionSelector(QWidget * parent)154 ImageCollectionSelector* KipiInterface::imageCollectionSelector(QWidget* parent)
155 {
156 qDebug() << "Called by plugins";
157
158 return (new KipiImageCollectionSelector(this, parent));
159 }
160
uploadWidget(QWidget * parent)161 UploadWidget* KipiInterface::uploadWidget(QWidget* parent)
162 {
163 qDebug() << "Called by plugins";
164
165 return (new KipiUploadWidget(this, parent));
166 }
167
addSelectedImages(const QList<QUrl> & images)168 void KipiInterface::addSelectedImages(const QList<QUrl>& images)
169 {
170 m_selectedImages.append(images);
171 }
172
addSelectedImage(const QUrl & image)173 void KipiInterface::addSelectedImage(const QUrl& image)
174 {
175 m_selectedImages.append(image);
176 }
177
addAlbums(const QList<QUrl> & albums)178 void KipiInterface::addAlbums(const QList<QUrl>& albums)
179 {
180 for (QList<QUrl>::const_iterator it = albums.constBegin(); it!=albums.constEnd(); ++it)
181 {
182 addAlbum(*it);
183 }
184 }
185
addAlbum(const QUrl & album)186 void KipiInterface::addAlbum(const QUrl& album)
187 {
188 m_albums.append(album);
189
190 // TODO: recurse through sub-directories?
191 }
192
addSelectedAlbums(const QList<QUrl> & albums)193 void KipiInterface::addSelectedAlbums(const QList<QUrl>& albums)
194 {
195 for (QList<QUrl>::const_iterator it = albums.constBegin(); it!=albums.constEnd(); ++it)
196 {
197 addSelectedAlbum(*it);
198 }
199 }
200
addSelectedAlbum(const QUrl & album)201 void KipiInterface::addSelectedAlbum(const QUrl& album)
202 {
203 m_selectedAlbums.append(album);
204
205 // TODO: recurse through sub-directories?
206 }
207
hostSetting(const QString & settingName)208 QVariant KipiInterface::hostSetting(const QString& settingName)
209 {
210 Q_UNUSED(settingName);
211 return QVariant();
212 }
213
thumbnails(const QList<QUrl> & list,int)214 void KipiInterface::thumbnails(const QList<QUrl>& list, int)
215 {
216 foreach(const QUrl& url, list)
217 {
218 QIcon icon(url.url());
219 emit gotThumbnail(url, icon.pixmap(256));
220 }
221 }
222
saveImage(const QUrl & url,const QString & format,const QByteArray & data,uint width,uint height,bool sixteenBit,bool hasAlpha,bool * cancel)223 bool KipiInterface::saveImage(const QUrl& url, const QString& format,
224 const QByteArray& data, uint width, uint height,
225 bool sixteenBit, bool hasAlpha, bool* cancel)
226 {
227 KIPIWriteImage writer;
228 writer.setImageData(data, width, height, sixteenBit, hasAlpha);
229 writer.setCancel(cancel);
230
231 if (format.toUpper() == QLatin1String("JPG") ||
232 format.toUpper() == QLatin1String("JPEG"))
233 {
234 return writer.write2JPEG(url.toLocalFile());
235 }
236
237 if (format.toUpper() == QLatin1String("TIF") ||
238 format.toUpper() == QLatin1String("TIFF"))
239 {
240 return writer.write2TIFF(url.toLocalFile());
241 }
242
243 if (format.toUpper() == QLatin1String("PNG"))
244 {
245 return writer.write2PNG(url.toLocalFile());
246 }
247
248 if (format.toUpper() == QLatin1String("PPM"))
249 {
250 return writer.write2PPM(url.toLocalFile());
251 }
252
253 return false;
254 }
255
256 // ---------------------------------------------------------------------------------------
257
258 #ifdef HAVE_KEXIV2
259
260 class KipiMetadataProcessor : public KIPI::MetadataProcessor
261 {
262 public:
263
KipiMetadataProcessor()264 KipiMetadataProcessor() {};
~KipiMetadataProcessor()265 ~KipiMetadataProcessor() override {};
266
load(const QUrl & url)267 bool load(const QUrl& url) override
268 {
269 return m_meta.load(url.toLocalFile());
270 }
271
save(const QUrl & url,bool writeToFileOnly)272 bool save(const QUrl& url, bool writeToFileOnly) override
273 {
274 if (writeToFileOnly)
275 m_meta.setMetadataWritingMode((int) KExiv2Iface::KExiv2::WRITETOIMAGEONLY);
276
277 return m_meta.save(url.toLocalFile());
278 }
279
applyChanges()280 bool applyChanges() override
281 {
282 return m_meta.applyChanges();
283 }
284
getPixelSize()285 QSize getPixelSize() override
286 {
287 return m_meta.getPixelSize();
288 }
289
setImageProgramId(const QString & program,const QString & version)290 bool setImageProgramId(const QString& program, const QString& version) override
291 {
292 return m_meta.setImageProgramId(program, version);
293 }
294
getImageDimensions()295 QSize getImageDimensions() override
296 {
297 return m_meta.getImageDimensions();
298 }
299
setImageDimensions(const QSize & size)300 bool setImageDimensions(const QSize& size) override
301 {
302 return m_meta.setImageDimensions(size);
303 }
304
getImageOrientation()305 int getImageOrientation() override
306 {
307 return m_meta.getImageOrientation();
308 }
309
setImageOrientation(int orientation)310 bool setImageOrientation(int orientation) override
311 {
312 return m_meta.setImageOrientation((KExiv2Iface::KExiv2::ImageOrientation)orientation);
313 }
314
rotateExifQImage(QImage & img,int orientation)315 bool rotateExifQImage(QImage& img, int orientation) override
316 {
317 return m_meta.rotateExifQImage(img, (KExiv2Iface::KExiv2::ImageOrientation)orientation);
318 }
319
getImageDateTime()320 QDateTime getImageDateTime() override
321 {
322 return m_meta.getImageDateTime();
323 }
324
setImageDateTime(const QDateTime & dt)325 bool setImageDateTime(const QDateTime& dt) override
326 {
327 return m_meta.setImageDateTime(dt);
328 }
329
getImagePreview(QImage & img)330 bool getImagePreview(QImage& img) override
331 {
332 return m_meta.getImagePreview(img);
333 }
334
setImagePreview(const QImage & img)335 bool setImagePreview(const QImage& img) override
336 {
337 return m_meta.setImagePreview(img);
338 }
339
hasExif()340 bool hasExif() override
341 {
342 return m_meta.hasExif();
343 }
344
hasIptc()345 bool hasIptc() override
346 {
347 return m_meta.hasIptc();
348 }
349
hasXmp()350 bool hasXmp() override
351 {
352 return m_meta.hasXmp();
353 }
354
getExif()355 QByteArray getExif() override
356 {
357 return m_meta.getExifEncoded();
358 }
359
getIptc()360 QByteArray getIptc() override
361 {
362 return m_meta.getIptc();
363 }
364
getXmp()365 QByteArray getXmp() override
366 {
367 return m_meta.getXmp();
368 }
369
setExif(const QByteArray & data)370 bool setExif(const QByteArray& data) override
371 {
372 return m_meta.setExif(data);
373 }
374
setIptc(const QByteArray & data)375 bool setIptc(const QByteArray& data) override
376 {
377 return m_meta.setIptc(data);
378 }
379
setXmp(const QByteArray & data)380 bool setXmp(const QByteArray& data) override
381 {
382 return m_meta.setXmp(data);
383 }
384
registerXmpNameSpace(const QString & uri,const QString & prefix)385 bool registerXmpNameSpace(const QString& uri, const QString& prefix) override
386 {
387 return m_meta.registerXmpNameSpace(uri, prefix);
388 }
389
supportXmp()390 bool supportXmp() override
391 {
392 return m_meta.supportXmp();
393 }
394
canWriteXmp(const QUrl & url)395 bool canWriteXmp(const QUrl& url) override
396 {
397 return m_meta.canWriteXmp(url.toLocalFile());
398 }
399
removeExifTags(const QStringList & tagFilters)400 bool removeExifTags(const QStringList& tagFilters) override
401 {
402 KExiv2Iface::KExiv2::MetaDataMap m = m_meta.getExifTagsDataList(tagFilters);
403
404 if (m.isEmpty())
405 return false;
406
407 for (KExiv2Iface::KExiv2::MetaDataMap::iterator it = m.begin(); it != m.end(); ++it)
408 {
409 m_meta.removeExifTag(it.key().toLatin1().constData());
410 }
411
412 return true;
413 }
414
removeIptcTags(const QStringList & tagFilters)415 bool removeIptcTags(const QStringList& tagFilters) override
416 {
417 KExiv2Iface::KExiv2::MetaDataMap m = m_meta.getIptcTagsDataList(tagFilters);
418
419 if (m.isEmpty())
420 return false;
421
422 for (KExiv2Iface::KExiv2::MetaDataMap::iterator it = m.begin(); it != m.end(); ++it)
423 {
424 m_meta.removeIptcTag(it.key().toLatin1().constData());
425 }
426
427 return true;
428 }
429
removeXmpTags(const QStringList & tagFilters)430 bool removeXmpTags(const QStringList& tagFilters) override
431 {
432 KExiv2Iface::KExiv2::MetaDataMap m = m_meta.getXmpTagsDataList(tagFilters);
433
434 if (m.isEmpty())
435 return false;
436
437 for (KExiv2Iface::KExiv2::MetaDataMap::iterator it = m.begin(); it != m.end(); ++it)
438 {
439 m_meta.removeXmpTag(it.key().toLatin1().constData());
440 }
441
442 return true;
443 }
444
getGPSInfo(double & alt,double & lat,double & lon)445 bool getGPSInfo(double& alt, double& lat, double& lon) override
446 {
447 return m_meta.getGPSInfo(alt, lat, lon);
448 }
449
setGPSInfo(const double alt,const double lat,const double lon)450 bool setGPSInfo(const double alt, const double lat, const double lon) override
451 {
452 return m_meta.setGPSInfo(alt, lat, lon);
453 }
454
removeGPSInfo()455 bool removeGPSInfo() override
456 {
457 return m_meta.removeGPSInfo();
458 }
459
getExifTagString(const QString & tag)460 QString getExifTagString(const QString& tag) override
461 {
462 return m_meta.getExifTagString(tag.toLatin1().constData());
463 }
464
setExifTagString(const QString & tag,const QString & val)465 bool setExifTagString(const QString& tag, const QString& val) override
466 {
467 return m_meta.setExifTagString(tag.toLatin1().constData(), val);
468 }
469
getExifTagRational(const QString & tag,long int & num,long int & den)470 bool getExifTagRational(const QString& tag, long int& num, long int& den) override
471 {
472 return m_meta.getExifTagRational(tag.toLatin1().constData(), num, den);
473 }
474
setExifTagRational(const QString & tag,long int num,long int den)475 bool setExifTagRational(const QString& tag, long int num, long int den) override
476 {
477 return m_meta.setExifTagRational(tag.toLatin1().constData(), num, den);
478 }
479
getXmpTagString(const QString & tag)480 QString getXmpTagString(const QString& tag) override
481 {
482 return m_meta.getXmpTagString(tag.toLatin1().constData());
483 }
484
setXmpTagString(const QString & tag,const QString & val)485 bool setXmpTagString(const QString& tag, const QString& val) override
486 {
487 return m_meta.setXmpTagString(tag.toLatin1().constData(), val);
488 }
489
getXmpKeywords()490 QStringList getXmpKeywords() override
491 {
492 return m_meta.getXmpKeywords();
493 }
494
setXmpKeywords(const QStringList & keywords)495 bool setXmpKeywords(const QStringList& keywords) override
496 {
497 return m_meta.setXmpKeywords(keywords);
498 }
499
getXmpTagVariant(const QString & tag)500 QVariant getXmpTagVariant(const QString& tag) override
501 {
502 return m_meta.getXmpTagVariant(tag.toLatin1().constData());
503 }
504
505 private:
506
507 KExiv2Iface::KExiv2 m_meta;
508 };
509
createMetadataProcessor() const510 MetadataProcessor* KipiInterface::createMetadataProcessor() const
511 {
512 return (new KipiMetadataProcessor);
513 }
514
515 #else // HAVE_KEXIV2
516
createMetadataProcessor() const517 MetadataProcessor* KipiInterface::createMetadataProcessor() const
518 {
519 qDebug() << "This interface was not compiled with libkexiv2 to support Metadata processing";
520 return 0;
521 }
522
523 #endif // HAVE_KEXIV2
524
525 // ---------------------------------------------------------------------------------------
526
createReadWriteLock(const QUrl &) const527 FileReadWriteLock* KipiInterface::createReadWriteLock(const QUrl&) const
528 {
529 return nullptr; // TODO
530 }
531
532 } // namespace KXMLKipiCmd
533