File indexing completed on 2025-01-19 03:50:58

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2009-03-04
0007  * Description : a tool to adjust date time stamp of images
0008  *
0009  * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "timeadjust.h"
0016 
0017 // Qt includes
0018 
0019 #include <QLabel>
0020 #include <QWidget>
0021 #include <QFile>
0022 #include <QScopedPointer>
0023 
0024 // KDE includes
0025 
0026 #include <klocalizedstring.h>
0027 
0028 // Local includes
0029 
0030 #include "dimg.h"
0031 #include "dmetadata.h"
0032 #include "dlayoutbox.h"
0033 #include "dfileoperations.h"
0034 
0035 namespace DigikamBqmTimeAdjustPlugin
0036 {
0037 
0038 TimeAdjust::TimeAdjust(QObject* const parent)
0039     : BatchTool(QLatin1String("TimeAdjust"), MetadataTool, parent),
0040       m_taWidget      (nullptr),
0041       m_changeSettings(true)
0042 {
0043     setToolTitle(i18n("Time Adjust"));
0044     setToolDescription(i18n("Adjust Date Time Stamp of Image"));
0045     setToolIconName(QLatin1String("appointment-new"));
0046 }
0047 
0048 TimeAdjust::~TimeAdjust()
0049 {
0050 }
0051 
0052 BatchTool* TimeAdjust::clone(QObject* const parent) const
0053 {
0054     return new TimeAdjust(parent);
0055 }
0056 
0057 void TimeAdjust::registerSettingsWidget()
0058 {
0059     DVBox* const vbox = new DVBox;
0060     m_taWidget        = new TimeAdjustSettings(vbox);
0061     m_settingsWidget  = vbox;
0062 
0063     connect(m_taWidget, SIGNAL(signalSettingsChanged()),
0064             this, SLOT(slotSettingsChanged()));
0065 
0066     BatchTool::registerSettingsWidget();
0067 }
0068 
0069 BatchToolSettings TimeAdjust::defaultSettings()
0070 {
0071     BatchToolSettings settings;
0072     TimeAdjustContainer prm;
0073 
0074     settings.insert(QLatin1String("Custom Date"),                   prm.customDate);
0075     settings.insert(QLatin1String("Custom Time"),                   prm.customTime);
0076 
0077     settings.insert(QLatin1String("Adjustment Type"),               prm.adjustmentType);
0078     settings.insert(QLatin1String("Adjustment Days"),               prm.adjustmentDays);
0079     settings.insert(QLatin1String("Adjustment Time"),               prm.adjustmentTime);
0080 
0081     settings.insert(QLatin1String("Update Only If Available Time"), prm.updIfAvailable);
0082     settings.insert(QLatin1String("Update File Modification Time"), prm.updFileModDate);
0083     settings.insert(QLatin1String("Update EXIF Modification Time"), prm.updEXIFModDate);
0084     settings.insert(QLatin1String("Update EXIF Original Time"),     prm.updEXIFOriDate);
0085     settings.insert(QLatin1String("Update EXIF Digitization Time"), prm.updEXIFDigDate);
0086     settings.insert(QLatin1String("Update EXIF Thumbnail Time"),    prm.updEXIFThmDate);
0087     settings.insert(QLatin1String("Update IPTC Time"),              prm.updIPTCDate);
0088     settings.insert(QLatin1String("Update XMP Video Time"),         prm.updXMPVideo);
0089     settings.insert(QLatin1String("Update XMP Creation Time"),      prm.updXMPDate);
0090 
0091     settings.insert(QLatin1String("Use Timestamp Type"),            prm.dateSource);
0092     settings.insert(QLatin1String("Meta Timestamp Type"),           prm.metadataSource);
0093     settings.insert(QLatin1String("File Timestamp Type"),           prm.fileDateSource);
0094 
0095     return settings;
0096 }
0097 
0098 void TimeAdjust::slotAssignSettings2Widget()
0099 {
0100     m_changeSettings   = false;
0101 
0102     TimeAdjustContainer prm;
0103 
0104     prm.customDate     = settings()[QLatin1String("Custom Date")].toDateTime();
0105     prm.customTime     = settings()[QLatin1String("Custom Time")].toDateTime();
0106 
0107     prm.adjustmentType = settings()[QLatin1String("Adjustment Type")].toInt();
0108     prm.adjustmentDays = settings()[QLatin1String("Adjustment Days")].toInt();
0109     prm.adjustmentTime = settings()[QLatin1String("Adjustment Time")].toDateTime();
0110 
0111     prm.updIfAvailable = settings()[QLatin1String("Update Only If Available Time")].toBool();
0112     prm.updFileModDate = settings()[QLatin1String("Update File Modification Time")].toBool();
0113     prm.updEXIFModDate = settings()[QLatin1String("Update EXIF Modification Time")].toBool();
0114     prm.updEXIFOriDate = settings()[QLatin1String("Update EXIF Original Time")].toBool();
0115     prm.updEXIFDigDate = settings()[QLatin1String("Update EXIF Digitization Time")].toBool();
0116     prm.updEXIFThmDate = settings()[QLatin1String("Update EXIF Thumbnail Time")].toBool();
0117     prm.updIPTCDate    = settings()[QLatin1String("Update IPTC Time")].toBool();
0118     prm.updXMPVideo    = settings()[QLatin1String("Update XMP Video Time")].toBool();
0119     prm.updXMPDate     = settings()[QLatin1String("Update XMP Creation Time")].toBool();
0120 
0121     prm.dateSource     = settings()[QLatin1String("Use Timestamp Type")].toInt();
0122     prm.metadataSource = settings()[QLatin1String("Meta Timestamp Type")].toInt();
0123     prm.fileDateSource = settings()[QLatin1String("File Timestamp Type")].toInt();
0124 
0125     m_taWidget->setSettings(prm);
0126 
0127     m_changeSettings   = true;
0128 }
0129 
0130 void TimeAdjust::slotSettingsChanged()
0131 {
0132     if (m_changeSettings)
0133     {
0134         TimeAdjustContainer prm = m_taWidget->settings();
0135         BatchToolSettings settings;
0136 
0137         settings.insert(QLatin1String("Custom Date"),                   prm.customDate);
0138         settings.insert(QLatin1String("Custom Time"),                   prm.customTime);
0139 
0140         settings.insert(QLatin1String("Adjustment Type"),               prm.adjustmentType);
0141         settings.insert(QLatin1String("Adjustment Days"),               prm.adjustmentDays);
0142         settings.insert(QLatin1String("Adjustment Time"),               prm.adjustmentTime);
0143 
0144         settings.insert(QLatin1String("Update Only If Available Time"), prm.updIfAvailable);
0145         settings.insert(QLatin1String("Update File Modification Time"), prm.updFileModDate);
0146         settings.insert(QLatin1String("Update EXIF Modification Time"), prm.updEXIFModDate);
0147         settings.insert(QLatin1String("Update EXIF Original Time"),     prm.updEXIFOriDate);
0148         settings.insert(QLatin1String("Update EXIF Digitization Time"), prm.updEXIFDigDate);
0149         settings.insert(QLatin1String("Update EXIF Thumbnail Time"),    prm.updEXIFThmDate);
0150         settings.insert(QLatin1String("Update IPTC Time"),              prm.updIPTCDate);
0151         settings.insert(QLatin1String("Update XMP Video Time"),         prm.updXMPVideo);
0152         settings.insert(QLatin1String("Update XMP Creation Time"),      prm.updXMPDate);
0153 
0154         settings.insert(QLatin1String("Use Timestamp Type"),            prm.dateSource);
0155         settings.insert(QLatin1String("Meta Timestamp Type"),           prm.metadataSource);
0156         settings.insert(QLatin1String("File Timestamp Type"),           prm.fileDateSource);
0157 
0158         BatchTool::slotSettingsChanged(settings);
0159     }
0160 }
0161 
0162 bool TimeAdjust::toolOperations()
0163 {
0164     bool metaLoadState = true;
0165     QScopedPointer<DMetadata> meta(new DMetadata);
0166 
0167     if (image().isNull())
0168     {
0169         metaLoadState = meta->load(inputUrl().toLocalFile());
0170     }
0171     else
0172     {
0173         meta->setData(image().getMetadata());
0174     }
0175 
0176     TimeAdjustContainer prm;
0177 
0178     bool metadataChanged               = false;
0179 
0180     prm.customDate                     = settings()[QLatin1String("Custom Date")].toDateTime();
0181     prm.customTime                     = settings()[QLatin1String("Custom Time")].toDateTime();
0182 
0183     prm.adjustmentType                 = settings()[QLatin1String("Adjustment Type")].toInt();
0184     prm.adjustmentDays                 = settings()[QLatin1String("Adjustment Days")].toInt();
0185     prm.adjustmentTime                 = settings()[QLatin1String("Adjustment Time")].toDateTime();
0186 
0187     prm.updIfAvailable                 = settings()[QLatin1String("Update Only If Available Time")].toBool();
0188     prm.updFileModDate                 = settings()[QLatin1String("Update File Modification Time")].toBool();
0189     prm.updEXIFModDate                 = settings()[QLatin1String("Update EXIF Modification Time")].toBool();
0190     prm.updEXIFOriDate                 = settings()[QLatin1String("Update EXIF Original Time")].toBool();
0191     prm.updEXIFDigDate                 = settings()[QLatin1String("Update EXIF Digitization Time")].toBool();
0192     prm.updEXIFThmDate                 = settings()[QLatin1String("Update EXIF Thumbnail Time")].toBool();
0193     prm.updIPTCDate                    = settings()[QLatin1String("Update IPTC Time")].toBool();
0194     prm.updXMPVideo                    = settings()[QLatin1String("Update XMP Video Time")].toBool();
0195     prm.updXMPDate                     = settings()[QLatin1String("Update XMP Creation Time")].toBool();
0196 
0197     prm.dateSource                     = settings()[QLatin1String("Use Timestamp Type")].toInt();
0198     prm.metadataSource                 = settings()[QLatin1String("Meta Timestamp Type")].toInt();
0199     prm.fileDateSource                 = settings()[QLatin1String("File Timestamp Type")].toInt();
0200 
0201     QString exifDateTimeFormat         = QLatin1String("yyyy:MM:dd hh:mm:ss");
0202     QString xmpDateTimeFormat          = QLatin1String("yyyy-MM-ddThh:mm:ss");
0203 
0204     const QMap<QString, bool>& tagsMap = prm.getDateTimeTagsMap();
0205     QMap<QString, bool>::const_iterator it;
0206 
0207     QDateTime orgDateTime;
0208 
0209     switch (prm.dateSource)
0210     {
0211         case TimeAdjustContainer::METADATADATE:
0212         {
0213             switch (prm.metadataSource)
0214             {
0215                 case TimeAdjustContainer::EXIFIPTCXMP:
0216                 {
0217                     orgDateTime = meta->getItemDateTime();
0218                     break;
0219                 }
0220 
0221                 case TimeAdjustContainer::EXIFCREATED:
0222                 {
0223                     orgDateTime = QDateTime::fromString(meta->getExifTagString("Exif.Image.DateTime"),
0224                                                         exifDateTimeFormat);
0225                     break;
0226                 }
0227 
0228                 case TimeAdjustContainer::EXIFORIGINAL:
0229                 {
0230                     orgDateTime = QDateTime::fromString(meta->getExifTagString("Exif.Photo.DateTimeOriginal"),
0231                                                         exifDateTimeFormat);
0232                     break;
0233                 }
0234 
0235                 case TimeAdjustContainer::EXIFDIGITIZED:
0236                 {
0237                     orgDateTime = QDateTime::fromString(meta->getExifTagString("Exif.Photo.DateTimeDigitized"),
0238                                                         exifDateTimeFormat);
0239                     break;
0240                 }
0241 
0242                 case TimeAdjustContainer::IPTCCREATED:
0243                 {
0244                     orgDateTime = QDateTime(QDate::fromString(meta->getIptcTagString("Iptc.Application2.DateCreated"),
0245                                                               Qt::ISODate),
0246                                             QTime::fromString(meta->getIptcTagString("Iptc.Application2.TimeCreated"),
0247                                                               Qt::ISODate));
0248                     break;
0249                 }
0250 
0251                 case TimeAdjustContainer::XMPCREATED:
0252                 {
0253                     orgDateTime = QDateTime::fromString(meta->getXmpTagString("Xmp.xmp.CreateDate"),
0254                                                         xmpDateTimeFormat);
0255                     break;
0256                 }
0257 
0258                 case TimeAdjustContainer::FUZZYCREATED:
0259                 {
0260                     orgDateTime = prm.getDateTimeFromString(meta->getExifTagString("Exif.Image.DateTime"));
0261                     break;
0262                 }
0263 
0264                 case TimeAdjustContainer::FUZZYORIGINAL:
0265                 {
0266                     orgDateTime = prm.getDateTimeFromString(meta->getExifTagString("Exif.Photo.DateTimeOriginal"));
0267                     break;
0268                 }
0269 
0270                 case TimeAdjustContainer::FUZZYDIGITIZED:
0271                 {
0272                     orgDateTime = prm.getDateTimeFromString(meta->getExifTagString("Exif.Photo.DateTimeDigitized"));
0273                     break;
0274                 }
0275 
0276                 default:
0277                 {
0278                     // orgDateTime stays invalid
0279                     break;
0280                 }
0281             };
0282 
0283             break;
0284         }
0285 
0286         case TimeAdjustContainer::CUSTOMDATE:
0287         {
0288             orgDateTime = QDateTime(prm.customDate.date(), prm.customTime.time());
0289             break;
0290         }
0291 
0292         case TimeAdjustContainer::FILENAME:
0293         {
0294             orgDateTime = prm.getDateTimeFromString(inputUrl().fileName());
0295             break;
0296         }
0297 
0298         case TimeAdjustContainer::FILEDATE:
0299         {
0300             orgDateTime = imageInfo().modDateTime();
0301             break;
0302         }
0303 
0304         default: // TimeAdjustContainer::APPDATE
0305         {
0306             orgDateTime = imageInfo().dateTime();
0307             break;
0308         }
0309     }
0310 
0311     if (!metaLoadState && (prm.dateSource != TimeAdjustContainer::CUSTOMDATE))
0312     {
0313         orgDateTime = imageInfo().modDateTime();
0314     }
0315 
0316     QDateTime dt = prm.calculateAdjustedDate(orgDateTime);
0317 
0318     if (!dt.isValid())
0319     {
0320         return false;
0321     }
0322 
0323     if (metaLoadState)
0324     {
0325         for (it = tagsMap.constBegin() ; it != tagsMap.constEnd() ; ++it)
0326         {
0327             if (!it.value())
0328             {
0329                 continue;
0330             }
0331 
0332             if      (it.key().startsWith(QLatin1String("Exif.")))
0333             {
0334                 if (!prm.updIfAvailable ||
0335                     !meta->getExifTagString(it.key().toLatin1().constData()).isEmpty())
0336                 {
0337                     meta->setExifTagString(it.key().toLatin1().constData(),
0338                                            dt.toString(exifDateTimeFormat));
0339 
0340                     metadataChanged = true;
0341                 }
0342             }
0343             else if (it.key().startsWith(QLatin1String("Iptc.")))
0344             {
0345                 if (!prm.updIfAvailable ||
0346                     !meta->getIptcTagString(it.key().toLatin1().constData()).isEmpty())
0347                 {
0348                     if      (it.key().contains(QLatin1String("Date")))
0349                     {
0350                         meta->setIptcTagString(it.key().toLatin1().constData(),
0351                                                dt.date().toString(Qt::ISODate));
0352 
0353                         metadataChanged = true;
0354                     }
0355                     else if (it.key().contains(QLatin1String("Time")))
0356                     {
0357                         meta->setIptcTagString(it.key().toLatin1().constData(),
0358                                                dt.time().toString(Qt::ISODate));
0359 
0360                         metadataChanged = true;
0361                     }
0362                 }
0363             }
0364             else if (it.key().startsWith(QLatin1String("Xmp.")) && meta->supportXmp())
0365             {
0366                 if (!prm.updIfAvailable ||
0367                     !meta->getXmpTagString(it.key().toLatin1().constData()).isEmpty())
0368                 {
0369                     meta->setXmpTagString(it.key().toLatin1().constData(),
0370                                           dt.toString(xmpDateTimeFormat));
0371 
0372                     metadataChanged = true;
0373                 }
0374             }
0375         }
0376     }
0377 
0378     bool ret = true;
0379 
0380     if (image().isNull())
0381     {
0382         QFile::remove(outputUrl().toLocalFile());
0383         ret = DFileOperations::copyFile(inputUrl().toLocalFile(), outputUrl().toLocalFile());
0384 
0385         if (ret && metadataChanged && metaLoadState)
0386         {
0387             ret = meta->save(outputUrl().toLocalFile());
0388         }
0389     }
0390     else
0391     {
0392         if (metadataChanged)
0393         {
0394             image().setMetadata(meta->data());
0395         }
0396 
0397         ret = savefromDImg();
0398     }
0399 
0400     if (ret && prm.updFileModDate)
0401     {
0402         ret = DFileOperations::setModificationTime(outputUrl().toLocalFile(), dt);
0403     }
0404 
0405     return ret;
0406 }
0407 
0408 } // namespace DigikamBqmTimeAdjustPlugin
0409 
0410 #include "moc_timeadjust.cpp"