File indexing completed on 2025-01-05 03:53:10

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2012-03-15
0007  * Description : a tool to create panorama by fusion of several images.
0008  *
0009  * SPDX-FileCopyrightText: 2012-2016 by Benjamin Girault <benjamin dot girault at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "preprocesstask.h"
0016 
0017 // Qt includes
0018 
0019 #include <QFileInfo>
0020 #include <QScopedPointer>
0021 
0022 // KDE includes
0023 
0024 #include <klocalizedstring.h>
0025 #include <ksharedconfig.h>
0026 #include <kconfiggroup.h>
0027 
0028 // Local includes
0029 
0030 #include "dbinarysearch.h"
0031 #include "digikam_debug.h"
0032 #include "drawdecoder.h"
0033 #include "dimg.h"
0034 #include "dimgloaderobserver.h"
0035 #include "drawdecoderwidget.h"
0036 #include "drawdecoding.h"
0037 
0038 namespace DigikamGenericPanoramaPlugin
0039 {
0040 
0041 class PanoObserver;
0042 
0043 class Q_DECL_HIDDEN PreProcessTask::Private
0044 {
0045 public:
0046 
0047     // cppcheck-suppress constParameter
0048     explicit Private(PanoramaPreprocessedUrls& urls,
0049                      const QUrl& url)
0050         : fileUrl        (url),
0051           preProcessedUrl(urls),
0052           observer       (nullptr)
0053     {
0054     }
0055 
0056     const QUrl                fileUrl;
0057     PanoramaPreprocessedUrls& preProcessedUrl;
0058     PanoObserver*             observer;
0059 };
0060 
0061 class Q_DECL_HIDDEN PanoObserver : public DImgLoaderObserver
0062 {
0063 public:
0064 
0065     explicit PanoObserver(PreProcessTask* const p)
0066         : DImgLoaderObserver(),
0067           parent            (p)
0068     {
0069     }
0070 
0071     ~PanoObserver() override
0072     {
0073     }
0074 
0075     bool continueQuery() override
0076     {
0077         return (!parent->isAbortedFlag);
0078     }
0079 
0080 private:
0081 
0082     PreProcessTask* const parent;
0083 };
0084 
0085 PreProcessTask::PreProcessTask(const QString& workDirPath,
0086                                int id,
0087                                PanoramaPreprocessedUrls& targetUrls,
0088                                const QUrl& sourceUrl)
0089     : PanoTask(PANO_PREPROCESS_INPUT, workDirPath),
0090       id(id),
0091       d (new Private(targetUrls, sourceUrl))
0092 {
0093     d->observer = new PanoObserver(this);
0094 }
0095 
0096 PreProcessTask::~PreProcessTask()
0097 {
0098 }
0099 
0100 void PreProcessTask::requestAbort()
0101 {
0102     PanoTask::requestAbort();
0103 }
0104 
0105 void PreProcessTask::run(ThreadWeaver::JobPointer, ThreadWeaver::Thread*)
0106 {
0107     // check if its a RAW file.
0108 
0109     if (DRawDecoder::isRawFile(d->fileUrl))
0110     {
0111         d->preProcessedUrl.preprocessedUrl = tmpDir;
0112 
0113         if (!convertRaw())
0114         {
0115             successFlag = false;
0116 
0117             return;
0118         }
0119     }
0120     else
0121     {
0122         // NOTE: in this case, preprocessed Url is the original file Url.
0123 
0124         d->preProcessedUrl.preprocessedUrl = d->fileUrl;
0125     }
0126 
0127     d->preProcessedUrl.previewUrl = tmpDir;
0128 
0129     if (!computePreview(d->preProcessedUrl.preprocessedUrl))
0130     {
0131         successFlag = false;
0132 
0133         return;
0134     }
0135 
0136     successFlag = true;
0137 }
0138 
0139 bool PreProcessTask::computePreview(const QUrl& inUrl)
0140 {
0141     QUrl& outUrl = d->preProcessedUrl.previewUrl;
0142 
0143     QFileInfo fi(inUrl.toLocalFile());
0144     outUrl.setPath(outUrl.path() + fi.completeBaseName().replace(QLatin1Char('.'), QLatin1String("_"))
0145                                  + QLatin1String("-preview.jpg"));
0146 
0147     DImg img;
0148 
0149     if (img.load(inUrl.toLocalFile()))
0150     {
0151         DImg preview = img.smoothScale(1280, 1024, Qt::KeepAspectRatio);
0152         bool saved   = preview.save(outUrl.toLocalFile(), DImg::JPEG);
0153 
0154         // save exif information also to preview image for auto rotation
0155 
0156         if (saved)
0157         {
0158             QScopedPointer<DMetadata> meta(new DMetadata);
0159 
0160             if (meta->load(inUrl.toLocalFile()))
0161             {
0162                 MetaEngine::ImageOrientation orientation = meta->getItemOrientation();
0163 
0164                 if (meta->load(outUrl.toLocalFile()))
0165                 {
0166                     meta->setItemOrientation(orientation);
0167                     meta->setItemDimensions(QSize(preview.width(), preview.height()));
0168                     meta->applyChanges(true);
0169                 }
0170             }
0171         }
0172 
0173         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Preview Image url: " << outUrl << ", saved: " << saved;
0174 
0175         return saved;
0176     }
0177     else
0178     {
0179         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Error during preview generation of: " << inUrl;
0180         errString = i18n("Input image cannot be loaded for preview generation.");
0181     }
0182 
0183     return false;
0184 }
0185 
0186 bool PreProcessTask::convertRaw()
0187 {
0188     const QUrl& inUrl           = d->fileUrl;
0189     QUrl& outUrl                = d->preProcessedUrl.preprocessedUrl;
0190     DImg img;
0191 
0192     DRawDecoding settings;
0193     KSharedConfig::Ptr config   = KSharedConfig::openConfig();
0194     KConfigGroup group          = config->group(QLatin1String("ImageViewer Settings"));
0195     DRawDecoderWidget::readSettings(settings.rawPrm, group);
0196 
0197     if (img.load(inUrl.toLocalFile(), d->observer, settings))
0198     {
0199         QFileInfo fi(inUrl.toLocalFile());
0200         QDir outDir(outUrl.toLocalFile());
0201         outDir.cdUp();
0202         QString path = outDir.path() + QLatin1Char('/');
0203         outUrl.setPath(path + fi.completeBaseName().replace(QLatin1Char('.'), QLatin1String("_"))
0204                             + QLatin1String(".tif"));
0205 
0206         if (!img.save(outUrl.toLocalFile(), QLatin1String("TIF")))
0207         {
0208             errString = i18n("Tiff image creation failed.");
0209 
0210             return false;
0211         }
0212 
0213         QScopedPointer<DMetadata> meta(new DMetadata);
0214 
0215         if (meta->load(outUrl.toLocalFile()))
0216         {
0217             DMetadata::MetaDataMap m = meta->getExifTagsDataList(QStringList() << QLatin1String("Photo"));
0218 
0219             if (!m.isEmpty())
0220             {
0221                 for (DMetadata::MetaDataMap::iterator it = m.begin() ; it != m.end() ; ++it)
0222                 {
0223                     meta->removeExifTag(it.key().toLatin1().constData());
0224                 }
0225             }
0226 
0227             meta->setItemDimensions(img.size());
0228             meta->setExifTagString("Exif.Image.DocumentName", inUrl.fileName());
0229             meta->setXmpTagString("Xmp.tiff.Make",  meta->getExifTagString("Exif.Image.Make"));
0230             meta->setXmpTagString("Xmp.tiff.Model", meta->getExifTagString("Exif.Image.Model"));
0231             meta->setItemOrientation(DMetadata::ORIENTATION_NORMAL);
0232             meta->applyChanges(true);
0233         }
0234     }
0235     else
0236     {
0237         errString = i18n("Raw file conversion failed.");
0238         return false;
0239     }
0240 
0241     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Convert RAW output url: " << outUrl;
0242 
0243     return true;
0244 }
0245 
0246 } // namespace DigikamGenericPanoramaPlugin