File indexing completed on 2025-01-19 03:56:04

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2021-02-18
0007  * Description : Qt5 and Qt6 interface for exiftool.
0008  *               Based on ZExifTool Qt interface published at 18 Feb 2021
0009  *               https://github.com/philvl/ZExifTool
0010  *
0011  * SPDX-FileCopyrightText: 2021-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0012  * SPDX-FileCopyrightText: 2021 by Philippe Vianney Liaud <philvl dot dev at gmail dot com>
0013  *
0014  * SPDX-License-Identifier: GPL-2.0-or-later
0015  *
0016  * ============================================================ */
0017 
0018 #ifndef DIGIKAM_EXIFTOOL_PROCESS_H
0019 #define DIGIKAM_EXIFTOOL_PROCESS_H
0020 
0021 // Qt includes
0022 
0023 #include <QString>
0024 #include <QProcess>
0025 #include <QPointer>
0026 
0027 // Local includes
0028 
0029 #include "digikam_export.h"
0030 
0031 namespace Digikam
0032 {
0033 class ExifToolParser;
0034 
0035 class DIGIKAM_EXPORT ExifToolProcess : public QProcess
0036 {
0037     Q_OBJECT
0038 
0039 public:
0040 
0041     /**
0042      * ExifTool actions to process.
0043      */
0044     enum Action
0045     {
0046         LOAD_METADATA       = 0,                    ///< Load all metadata from a file with ExifTool.
0047         LOAD_CHUNKS,                                ///< Load Exif, Iptc, and Xmp chunks from a file as byte-array for MetaEngine.
0048         APPLY_CHANGES,                              ///< Apply tag changes in a file with ExifTool.
0049         APPLY_CHANGES_EXV,                          ///< Apply tag changes in a file with ExifTool using an EXV container.
0050         APPLY_METADATA_FILE,                        ///< Apply a metadata file to a file with ExifTool.
0051         READ_FORMATS,                               ///< Return the list of readable ExifTool file formats.
0052         WRITE_FORMATS,                              ///< Return the list of writable ExifTool file formats.
0053         TRANSLATIONS_LIST,                          ///< List of ExifTool languages available for translations.
0054         TAGS_DATABASE,                              ///< List of ExifTool tags from database.
0055         VERSION_STRING,                             ///< Return the ExifTool version as string.
0056         COPY_TAGS,                                  ///< Copy tags from one file to another one. See CopyTagsSource enum for details.
0057         TRANS_TAGS,                                 ///< Translate tags in file. See TranslateTagsOps enum for details.
0058         NO_ACTION                                   ///< Last value from this list. Do nothing.
0059     };
0060 
0061     /**
0062      * Possible copying tags operations to OR combine with COPY_TAGS action.
0063      */
0064     enum CopyTagsSource
0065     {
0066         COPY_EXIF           = 0x01,                 ///< Copy all Exif Tags from source file.
0067         COPY_MAKERNOTES     = 0x02,                 ///< Copy all Makernotes tags from source file.
0068         COPY_IPTC           = 0x04,                 ///< Copy all Iptc tags from source file.
0069         COPY_XMP            = 0x08,                 ///< Copy all Xmp tags from source file.
0070         COPY_ICC            = 0x10,                 ///< Copy ICC profile from source file.
0071         COPY_ALL            = 0x20,                 ///< Copy all tags from source file.
0072         COPY_NONE           = 0x40                  ///< No copy operation.
0073     };
0074 
0075     /**
0076      * Possible writing tags mode to OR combine with COPY_TAGS action.
0077      */
0078     enum WritingTagsMode
0079     {
0080         WRITE_EXISTING_TAGS = 0x01,                 ///< Overwrite existing tags.
0081         CREATE_NEW_TAGS     = 0x02,                 ///< Create new tags.
0082         CREATE_NEW_GROUPS   = 0x04,                 ///< Create new groups if necessary.
0083         ALL_MODES           = WRITE_EXISTING_TAGS |
0084                               CREATE_NEW_TAGS     |
0085                               CREATE_NEW_GROUPS
0086     };
0087 
0088     /**
0089      * Possible translating tags operations to OR combine with COPY_TAGS action.
0090      */
0091     enum TranslateTagsOps
0092     {
0093         TRANS_ALL_XMP       = 0x01,                 ///< Translate all existing Tags from source file to Xmp.
0094         TRANS_ALL_IPTC      = 0x02,                 ///< Translate all existing Tags from source file to Iptc.
0095         TRANS_ALL_EXIF      = 0x04                  ///< Translate all existing Tags from source file to Exif.
0096     };
0097 
0098     /**
0099      * Command result state.
0100      */
0101     enum ResultStatus
0102     {
0103         COMMAND_RESULT      = 0,
0104         FINISH_RESULT,
0105         ERROR_RESULT
0106     };
0107 
0108 public:
0109 
0110     class Result
0111     {
0112     public:
0113 
0114         Result()
0115           : waitError (false),
0116             cmdStatus (ExifToolProcess::COMMAND_RESULT),
0117             cmdAction (ExifToolProcess::NO_ACTION),
0118             cmdNumber (0),
0119             elapsed   (0)
0120         {
0121         }
0122 
0123         bool       waitError;
0124         int        cmdStatus;
0125         int        cmdAction;
0126         int        cmdNumber;
0127         int        elapsed;
0128         QByteArray output;
0129     };
0130 
0131 public:
0132 
0133     /**
0134      * Constructs a ExifToolProcess.
0135      */
0136     explicit ExifToolProcess();
0137 
0138     /**
0139      * Destructs the ExifToolProcess object, i.e., killing the process.
0140      * Note that this function will not return until the process is terminated.
0141      */
0142     ~ExifToolProcess();
0143 
0144     /**
0145      * @brief internalPtr - singleton implementation
0146      */
0147     static QPointer<ExifToolProcess> internalPtr;
0148     static ExifToolProcess*          instance();
0149     static bool                      isCreated();
0150 
0151     /**
0152      * Setup connections, apply Settings and start ExifTool process.
0153      * This function cannot be called from another thread.
0154      */
0155     void initExifTool();
0156 
0157 public:
0158 
0159     /**
0160      * Change the ExifTool path configuration.
0161      * This function can be called from another thread.
0162      */
0163     void setExifToolProgram(const QString& etExePath);
0164 
0165     QString getExifToolProgram()                             const;
0166 
0167 public:
0168 
0169     /**
0170      * Returns true if ExifToolProcess is available (process state == Running)
0171      */
0172     bool                    exifToolAvailable()              const;
0173 
0174     /**
0175      * Returns true if a command is running.
0176      */
0177     bool                    exifToolIsBusy()                 const;
0178 
0179     /**
0180      * Returns the type of error that occurred last.
0181      */
0182     QProcess::ProcessError  exifToolError()                  const;
0183 
0184     /**
0185      * Returns an error message.
0186      */
0187     QString                 exifToolErrorString()            const;
0188 
0189     /**
0190      * Returns the ExifToolProcess result.
0191      */
0192     ExifToolProcess::Result getExifToolResult(int cmdId)     const;
0193 
0194     /**
0195      * WatCondition for the ExifToolParser class.
0196      * Returns the ExifToolProcess result.
0197      */
0198     ExifToolProcess::Result waitForExifToolResult(int cmdId) const;
0199 
0200     /**
0201      * Send a command to exiftool process.
0202      * This function can be called from another thread.
0203      * Return 0: ExitTool not running, write channel is closed or args is empty.
0204      */
0205     int command(const QByteArrayList& args, Action ac);
0206 
0207 Q_SIGNALS:
0208 
0209     void signalExifToolResult(int cmdId);
0210 
0211 private:
0212 
0213     /**
0214      * Starts exiftool in a new process.
0215      */
0216     bool startExifTool();
0217 
0218     /**
0219      * Restart exiftool in a new process.
0220      */
0221     void restartExifTool();
0222 
0223     /**
0224      * Attempts to terminate the process.
0225      */
0226     void terminateExifTool();
0227 
0228     /**
0229      * Kills the current process, causing it to exit immediately.
0230      * On Windows, kill() uses TerminateProcess, and on Unix and macOS,
0231      * the SIGKILL signal is sent to the process.
0232      */
0233     void killExifTool();
0234 
0235     QString exifToolBin()                                    const;
0236 
0237     bool checkExifToolProgram()                              const;
0238 
0239     void changeExifToolProgram(const QString& etExePath);
0240 
0241 Q_SIGNALS:
0242 
0243     void signalExecNextCmd();
0244     void signalChangeProgram(const QString& etExePath);
0245 
0246 private Q_SLOTS:
0247 
0248     void slotStarted();
0249     void slotApplySettingsAndStart();
0250     void slotReadyReadStandardError();
0251     void slotReadyReadStandardOutput();
0252     void slotChangeProgram(const QString& etExePath);
0253     void slotErrorOccurred(QProcess::ProcessError error);
0254     void slotFinished(int exitCode, QProcess::ExitStatus exitStatus);
0255 
0256 private:
0257 
0258     // Disable
0259     explicit ExifToolProcess(QObject*) = delete;
0260 
0261 private:
0262 
0263     class Private;
0264     Private* const d;
0265 };
0266 
0267 } // namespace Digikam
0268 
0269 #endif // DIGIKAM_EXIFTOOL_PROCESS_H