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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2024-02-11
0007  * Description : apply metadata batch tool with ExifTool.
0008  *
0009  * SPDX-FileCopyrightText: 2024 by Maik Qualmann <metzpinguin at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "applymetadata.h"
0016 
0017 // Qt includes
0018 
0019 #include <QDir>
0020 #include <QFile>
0021 #include <QLabel>
0022 #include <QWidget>
0023 #include <QFileInfo>
0024 #include <QGridLayout>
0025 #include <QTemporaryDir>
0026 #include <QScopedPointer>
0027 
0028 // KDE includes
0029 
0030 #include <klocalizedstring.h>
0031 
0032 // Local includes
0033 
0034 #include "dimg.h"
0035 #include "dmetadata.h"
0036 #include "dfileselector.h"
0037 #include "exiftoolparser.h"
0038 #include "dfileoperations.h"
0039 
0040 namespace DigikamBqmApplyMetadataPlugin
0041 {
0042 
0043 class Q_DECL_HIDDEN ApplyMetadata::Private
0044 {
0045 public:
0046 
0047     Private() = default;
0048 
0049 public:
0050 
0051     DFileSelector* fileSelector   = nullptr;
0052     QLabel*        descFileLabel  = nullptr;
0053 
0054     bool           changeSettings = false;
0055 };
0056 
0057 ApplyMetadata::ApplyMetadata(QObject* const parent)
0058     : BatchTool(QLatin1String("ApplyMetadata"), MetadataTool, parent),
0059       d        (new Private)
0060 {
0061 }
0062 
0063 ApplyMetadata::~ApplyMetadata()
0064 {
0065     delete d;
0066 }
0067 
0068 BatchTool* ApplyMetadata::clone(QObject* const parent) const
0069 {
0070     return new ApplyMetadata(parent);
0071 }
0072 
0073 void ApplyMetadata::registerSettingsWidget()
0074 {
0075     QWidget* const panel    = new QWidget;
0076     QGridLayout* const grid = new QGridLayout(panel);
0077 
0078     d->descFileLabel        = new QLabel(i18n("Select an image or JSON file supported by ExifTool "
0079                                               "to apply the file metadata to the images."), panel);
0080     d->descFileLabel->setWordWrap(true);
0081     d->fileSelector         = new DFileSelector(panel);
0082     d->fileSelector->setFileDlgMode(QFileDialog::ExistingFile);
0083 
0084     grid->addWidget(d->descFileLabel, 0, 0, 1, 1);
0085     grid->addWidget(d->fileSelector,  1, 0, 1, 1);
0086     grid->setRowStretch(2, 10);
0087 
0088     m_settingsWidget = panel;
0089 
0090     connect(d->fileSelector, SIGNAL(signalUrlSelected(QUrl)),
0091             this, SLOT(slotSettingsChanged()));
0092 
0093     BatchTool::registerSettingsWidget();
0094 }
0095 
0096 BatchToolSettings ApplyMetadata::defaultSettings()
0097 {
0098     BatchToolSettings settings;
0099 
0100     settings.insert(QLatin1String("MetadataFile"), QString());
0101 
0102     return settings;
0103 }
0104 
0105 void ApplyMetadata::slotAssignSettings2Widget()
0106 {
0107     d->changeSettings = false;
0108 
0109     d->fileSelector->setFileDlgPath(settings()[QLatin1String("MetadataFile")].toString());
0110 
0111     d->changeSettings = true;
0112 }
0113 
0114 void ApplyMetadata::slotSettingsChanged()
0115 {
0116     if (d->changeSettings)
0117     {
0118         BatchToolSettings settings;
0119 
0120         settings.insert(QLatin1String("MetadataFile"), d->fileSelector->fileDlgPath());
0121 
0122         BatchTool::slotSettingsChanged(settings);
0123     }
0124 }
0125 
0126 bool ApplyMetadata::toolOperations()
0127 {
0128     bool ret = true;
0129 
0130     if (image().isNull())
0131     {
0132         QFile::remove(outputUrl().toLocalFile());
0133         ret = DFileOperations::copyFile(inputUrl().toLocalFile(), outputUrl().toLocalFile());
0134     }
0135     else
0136     {
0137         ret = savefromDImg();
0138     }
0139 
0140     QFileInfo metaInfo(settings()[QLatin1String("MetadataFile")].toString());
0141 
0142     if (!ret || !metaInfo.exists())
0143     {
0144         setErrorDescription(i18nc("@info", "Apply Metadata: No image or JSON file selected."));
0145         return false;
0146     }
0147 
0148     QScopedPointer<ExifToolParser> const parser(new ExifToolParser(this));
0149 
0150     if (!parser->exifToolAvailable())
0151     {
0152         setErrorDescription(i18nc("@info", "Apply Metadata: ExifTool is not available."));
0153         return false;
0154     }
0155 
0156     if (metaInfo.suffix().toUpper() == QLatin1String("JSON"))
0157     {
0158         QString dirTemplate = QDir::tempPath() + QLatin1String("/bqm-apply-metadata-XXXXXX");
0159         QTemporaryDir tempDir(dirTemplate);
0160 
0161         if (!tempDir.isValid())
0162         {
0163             return false;
0164         }
0165 
0166         QFile jsonFileRead(metaInfo.filePath());
0167 
0168         if (!jsonFileRead.open(QIODevice::ReadOnly))
0169         {
0170             return false;
0171         }
0172 
0173         QString metaFile   = tempDir.path() + QLatin1Char('/') + metaInfo.fileName();
0174         QString jsonSource = QString::fromUtf8("\"SourceFile\": \"%1\",");
0175         QString jsonString = QString::fromUtf8(jsonFileRead.readAll());
0176         jsonFileRead.close();
0177 
0178         if (!jsonString.contains(jsonSource.arg(imageInfo().name(), Qt::CaseInsensitive)))
0179         {
0180             setErrorDescription(i18nc("@info", "Apply Metadata: File name not exist in JSON file."));
0181             return false;
0182         }
0183 
0184         jsonString.replace(jsonSource.arg(imageInfo().name()),
0185                            jsonSource.arg(outputUrl().toLocalFile(), Qt::CaseInsensitive));
0186 
0187         QFile jsonFileWrite(metaFile);
0188 
0189         if (!jsonFileWrite.open(QIODevice::WriteOnly))
0190         {
0191             return false;
0192         }
0193 
0194         jsonFileWrite.write(jsonString.toUtf8());
0195         jsonFileWrite.close();
0196 
0197         ret = parser->applyMetadataFile(outputUrl().toLocalFile(), metaFile);
0198     }
0199     else
0200     {
0201         ret = parser->applyMetadataFile(outputUrl().toLocalFile(), metaInfo.filePath());
0202     }
0203 
0204     if (!ret)
0205     {
0206         setErrorDescription(i18nc("@info", "Apply Metadata: ExifTool reported an error."));
0207         return false;
0208     }
0209 
0210     return true;
0211 }
0212 
0213 } // namespace DigikamBqmApplyMetadataPlugin
0214 
0215 #include "moc_applymetadata.cpp"