File indexing completed on 2025-04-27 03:58:08

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2005-12-17
0007  * Description : image file IO threaded interface.
0008  *
0009  * SPDX-FileCopyrightText: 2005-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0010  * SPDX-FileCopyrightText: 2005-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #ifndef DIGIKAM_LOAD_SAVE_THREAD_H
0017 #define DIGIKAM_LOAD_SAVE_THREAD_H
0018 
0019 // Qt includes
0020 
0021 #include <QThread>
0022 #include <QMutex>
0023 #include <QList>
0024 #include <QDateTime>
0025 #include <QWaitCondition>
0026 #include <QEvent>
0027 
0028 // Local includes
0029 
0030 #include "dimg.h"
0031 #include "digikam_export.h"
0032 #include "dynamicthread.h"
0033 #include "loadingdescription.h"
0034 
0035 namespace Digikam
0036 {
0037 
0038 class DMetadata;
0039 class LoadSaveTask;
0040 
0041 class DIGIKAM_EXPORT LoadSaveNotifier
0042 {
0043 public:
0044 
0045     LoadSaveNotifier();
0046     virtual ~LoadSaveNotifier();
0047 
0048     virtual void imageStartedLoading(const LoadingDescription& loadingDescription)                  = 0;
0049     virtual void loadingProgress(const LoadingDescription& loadingDescription, float progress)      = 0;
0050     virtual void imageLoaded(const LoadingDescription& loadingDescription, const DImg& img)         = 0;
0051     virtual void moreCompleteLoadingAvailable(const LoadingDescription& oldLoadingDescription,
0052                                               const LoadingDescription& newLoadingDescription)      = 0;
0053     virtual void imageStartedSaving(const QString& filePath)                                        = 0;
0054     virtual void savingProgress(const QString& filePath, float progress)                            = 0;
0055     virtual void imageSaved(const QString& filePath, bool success)                                  = 0;
0056     virtual void thumbnailLoaded(const LoadingDescription& loadingDescription, const QImage& img)   = 0;
0057 
0058 private:
0059 
0060     Q_DISABLE_COPY(LoadSaveNotifier)
0061 };
0062 
0063 // -------------------------------------------------------------------------------------------------------
0064 
0065 class DIGIKAM_EXPORT LoadSaveFileInfoProvider
0066 {
0067 public:
0068 
0069     LoadSaveFileInfoProvider();
0070     virtual ~LoadSaveFileInfoProvider();
0071 
0072     /**
0073      * Gives a hint at the orientation of the image.
0074      * This can be used to supersede the Exif information in the file.
0075      * Will not be used if DMetadata::ORIENTATION_UNSPECIFIED (default value)
0076      */
0077     virtual int   orientationHint(const QString& path)  = 0;
0078 
0079     /**
0080      * Gives a hint at the size of the image.
0081      * This can be used to supersede the Exif information in the file.
0082      */
0083     virtual QSize dimensionsHint(const QString& path)   = 0;
0084 
0085 private:
0086 
0087     Q_DISABLE_COPY(LoadSaveFileInfoProvider)
0088 };
0089 
0090 // -------------------------------------------------------------------------------------------------------
0091 
0092 class DIGIKAM_EXPORT LoadSaveThread : public DynamicThread,
0093                                       public LoadSaveNotifier
0094 {
0095     Q_OBJECT
0096 
0097 public:
0098 
0099     enum NotificationPolicy
0100     {
0101         /**
0102          * Always send notification, unless the last event is still in the event queue
0103          */
0104         NotificationPolicyDirect,
0105         /**
0106          * Always wait for a certain amount of time after the last event sent.
0107          * In particular, the first event will be sent only after waiting for this time span.
0108          * (Or no event will be sent, when the loading has finished before)
0109          * This is the default.
0110          */
0111         NotificationPolicyTimeLimited
0112     };
0113 
0114     /**
0115      * used by SharedLoadSaveThread only
0116      */
0117     enum AccessMode
0118     {
0119         /**
0120          * image will only be used for reading
0121          */
0122         AccessModeRead,
0123         /**
0124          * image data will possibly be changed
0125          */
0126         AccessModeReadWrite
0127     };
0128 
0129 public:
0130 
0131     explicit LoadSaveThread(QObject* const parent = nullptr);
0132 
0133     /**
0134      * Destructor:
0135      * The thread will execute all pending tasks and wait for this upon destruction
0136      */
0137     ~LoadSaveThread() override;
0138 
0139     /**
0140      * Append a task to load the given file to the task list
0141      */
0142     void load(const LoadingDescription& description);
0143 
0144     /**
0145      * Append a task to save the image to the task list
0146      */
0147     void save(const DImg& image, const QString& filePath, const QString& format);
0148 
0149     void setNotificationPolicy(NotificationPolicy notificationPolicy);
0150 
0151 public:
0152 
0153     static void setInfoProvider(LoadSaveFileInfoProvider* const infoProvider);
0154     static LoadSaveFileInfoProvider* infoProvider();
0155 
0156     /**
0157      * Retrieves the Exif orientation, either from the info provider if available,
0158      * or from the metadata
0159      */
0160     static int exifOrientation(const QString& filePath,
0161                                const DMetadata& metadata,
0162                                bool isRaw,
0163                                bool fromRawEmbeddedPreview);
0164 
0165 Q_SIGNALS:
0166 
0167     /**
0168      * All signals are delivered to the thread from where the LoadSaveThread object
0169      * has been created. This thread must use its event loop to get the signals.
0170      * You must connect to these signals with Qt::AutoConnection (default) or Qt::QueuedConnection.
0171      */
0172 
0173     /**
0174      * This signal is emitted when the loading process begins.
0175      */
0176     void signalImageStartedLoading(const LoadingDescription& loadingDescription);
0177 
0178     /**
0179      * This signal is emitted whenever new progress info is available
0180      * and the notification policy allows emitting the signal.
0181      * No progress info will be sent for preloaded images (ManagedLoadSaveThread).
0182      */
0183     void signalLoadingProgress(const LoadingDescription& loadingDescription, float progress);
0184 
0185     /**
0186      * This signal is emitted when the loading process has finished.
0187      * If the process failed, img is null.
0188      */
0189     void signalImageLoaded(const LoadingDescription& loadingDescription, const DImg& img);
0190 
0191     /**
0192      * This signal is emitted if
0193      *  - you are doing shared loading (SharedLoadSaveThread)
0194      *  - you started a loading operation with a LoadingDescription for
0195      *    a reduced version of the image
0196      *  - another thread started a loading operation for a more complete version
0197      * You may want to cancel the current operation and start with the given loadingDescription
0198      */
0199     void signalMoreCompleteLoadingAvailable(const LoadingDescription& oldLoadingDescription,
0200                                             const LoadingDescription& newLoadingDescription);
0201 
0202     void signalImageStartedSaving(const QString& filePath);
0203     void signalSavingProgress(const QString& filePath, float progress);
0204     void signalImageSaved(const QString& filePath, bool success);
0205 
0206     void signalThumbnailLoaded(const LoadingDescription& loadingDescription, const QImage& img);
0207 
0208 public:
0209 
0210     void imageStartedLoading(const LoadingDescription& loadingDescription)                override;
0211     void loadingProgress(const LoadingDescription& loadingDescription, float progress)    override;
0212     void imageLoaded(const LoadingDescription& loadingDescription, const DImg& img)       override;
0213     void moreCompleteLoadingAvailable(const LoadingDescription& oldLoadingDescription,
0214                                       const LoadingDescription& newLoadingDescription)    override;
0215     void imageStartedSaving(const QString& filePath)                                      override;
0216     void savingProgress(const QString& filePath, float progress)                          override;
0217     void imageSaved(const QString& filePath, bool success)                                override;
0218     void thumbnailLoaded(const LoadingDescription& loadingDescription, const QImage& img) override;
0219 
0220     virtual bool querySendNotifyEvent() const;
0221     virtual void taskHasFinished();
0222 
0223 protected:
0224 
0225     void run()                                                                            override;
0226 
0227     void notificationReceived();
0228 
0229 protected:
0230 
0231     QMutex               m_mutex;
0232 
0233     QList<LoadSaveTask*> m_todo;
0234 
0235     LoadSaveTask*        m_currentTask;
0236 
0237     NotificationPolicy   m_notificationPolicy;
0238 
0239 private:
0240 
0241     // Disable
0242     LoadSaveThread(const LoadSaveThread&)            = delete;
0243     LoadSaveThread& operator=(const LoadSaveThread&) = delete;
0244 
0245 private:
0246 
0247     class Private;
0248     Private* const d;
0249 };
0250 
0251 } // namespace Digikam
0252 
0253 #endif // DIGIKAM_LOAD_SAVE_THREAD_H