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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2020-11-28
0007  * Description : ExifTool process stream parser.
0008  *
0009  * SPDX-FileCopyrightText: 2020-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 #ifndef DIGIKAM_EXIFTOOL_PARSER_H
0016 #define DIGIKAM_EXIFTOOL_PARSER_H
0017 
0018 // Qt Core
0019 
0020 #include <QHash>
0021 #include <QObject>
0022 #include <QString>
0023 #include <QVariant>
0024 #include <QProcess>
0025 #include <QFileInfo>
0026 #include <QByteArray>
0027 
0028 // Local includes
0029 
0030 #include "digikam_export.h"
0031 #include "exiftoolprocess.h"
0032 #include "metaengine.h"
0033 
0034 namespace Digikam
0035 {
0036 
0037 class DIGIKAM_EXPORT ExifToolParser : public QObject
0038 {
0039     Q_OBJECT
0040 
0041 public:
0042 
0043     /**
0044      * A map used to store ExifTool data shared with ExifToolProcess class:
0045      *
0046      * With load() method, the container is used to get a map of
0047      * ExifTool tag name as key and tags properties as values:
0048      * key    = ExifTool Tag name            (QString - ExifTool Group 0.1.2.4.6)
0049      *                                       See -G Exiftool option (https://exiftool.org/exiftool_pod.html#Input-output-text-formatting).
0050      * values = ExifTool Tag value           (QString).
0051      *          ExifTool Tag type            (QString).
0052      *          ExifTool Tag description     (QString).
0053      *          ExifTool Tag numerical value (QString) - available if any .
0054      *
0055      * With loadChunk() method, the container is used to get
0056      * a EXV chunk as value:
0057      * key   = "EXV"                         (QString).
0058      * value = the Exiv2 metadata container  (QByteArray).
0059      *
0060      * With applyChanges() method, the container is used as argument to
0061      * store tupple of ExifTool tag name as key and tag value:
0062      * key   = ExifTool tag name             (QString).
0063      * value = ExifTool Tag value            (QString).
0064      *
0065      * With readableFormats() method, the container is used to get
0066      * a list of upper-case file format extensions supported by ExifTool for reading.
0067      * key   = "READ_FORMAT"                 (QString).
0068      * value = list of pairs (ext,desc)      (QStringList)
0069      *
0070      * With writableFormats() method, the container is used to get
0071      * a list of upper-case file format extensions supported by ExifTool for writing.
0072      * key   = "WRITE_FORMAT"                (QString).
0073      * value = list of pairs (ext,desc)      (QStringList).
0074      *
0075      * With translationsList() method, the container is used to get
0076      * a list of ExifTool languages available for translations.
0077      * key   = "TRANSLATIONS_LIST"           (QString).
0078      * value = list of languages as strings
0079      *         (aka fr, en, de, es, etc.)    (QStringList).
0080      *
0081      * With tagsDatabase() method, the container is used as argument to
0082      * store tupple of ExifTool tag name as key and tag description:
0083      * key    = ExifTool tag name            (QString).
0084      * values = ExifTool Tag description     (QString).
0085      *          ExifTool Tag type            (QString).
0086      *          ExifTool Tag writable        (QString).
0087      */
0088     typedef QHash<QString, QVariantList> ExifToolData;
0089 
0090 public:
0091 
0092     //---------------------------------------------------------------------------------------------
0093     /// Constructor, Destructor, and Configuration Accessors. See exiftoolparser.cpp for details.
0094     //@{
0095 
0096     explicit ExifToolParser(QObject* const parent, bool async = false);
0097     ~ExifToolParser();
0098 
0099     void setExifToolProgram(const QString& path);
0100 
0101     QString      currentPath()        const;
0102     ExifToolData currentData()        const;
0103     QString      currentErrorString() const;
0104 
0105     /**
0106      * Check the ExifTool program availability.
0107      */
0108     bool exifToolAvailable()          const;
0109 
0110     //@}
0111 
0112 public:
0113 
0114     //---------------------------------------------------------------------------------------------
0115     /// ExifTool Command Methods. See exiftoolparser_command.cpp for details.
0116     //@{
0117 
0118     /**
0119      * Load all metadata with ExifTool from a file.
0120      * Use currentData() to get the ExifTool map.
0121      */
0122     bool load(const QString& path);
0123 
0124     /**
0125      * Load Exif, Iptc, and Xmp chunk as Exiv2 EXV byte-array from a file.
0126      * Use currentData() to get the container.
0127      */
0128     bool loadChunk(const QString& path, bool copyToAll = false);
0129 
0130     /**
0131      * Apply tag changes to a target file using ExifTool with a list of tag properties.
0132      * Tags can already exists in target file or new ones can be created.
0133      * To remove a tag, pass an empty string as value.
0134      * @param path is the target files to change.
0135      * @param newTags is the list of tag properties.
0136      */
0137     bool applyChanges(const QString& path, const ExifToolData& newTags);
0138 
0139     /**
0140      * Apply tag changes to a target file using ExifTool with a EXV container.
0141      * Tags can already exists in target file or new ones can be created.
0142      * @param path is the target files to change.
0143      * @param exvTempFile is the list of changes embedded in EXV container.
0144      * @param hasExif if the EXV container has Exif metadata restore MarkerNotes.
0145      */
0146     bool applyChanges(const QString& path,
0147                       const QString& exvTempFile,
0148                       bool hasExif = true, bool hasXmp = true, bool hasCSet = false);
0149 
0150     /**
0151      * Apply a file with metadata to the target file.
0152      * @param path is the target file to change.
0153      * @param meta is the metadata file.
0154      */
0155     bool applyMetadataFile(const QString& path, const QString& meta);
0156 
0157     /**
0158      * Return a list of readable file format extensions.
0159      * Use currentData() to get the container as QStringList.
0160      */
0161     bool readableFormats();
0162 
0163     /**
0164      * Return a list of writable file format extensions.
0165      * Use currentData() to get the container as QStringList.
0166      */
0167     bool writableFormats();
0168 
0169     /**
0170      * Return a list of available translations.
0171      * Use currentData() to get the container as QStringList.
0172      */
0173     bool translationsList();
0174 
0175     /**
0176      * Return a list of all tags from ExifTool database.
0177      * Use currentData() to get the container.
0178      * Warning: This method get whole ExifTool database in XML format and take age.
0179      */
0180     bool tagsDatabase();
0181 
0182     /**
0183      * Return the current version of ExifTool.
0184      * Use currentData() to get the container as QString.
0185      */
0186     bool version();
0187 
0188     /**
0189      * Copy group of tags from one source file to a destination file, following copy operations defined by 'copyOps'.
0190      * @param copyOps is a OR combination of ExifToolProcess::CopyTagsSource values.
0191      * @param transOps is a OR combination of ExifToolProcess::TranslateTagsOps values.
0192      * @param writeModes is a OR combaniation of ExifToolProcess::WritingTagsMode values.
0193      * @param dst must be a writable file format supported by ExifTool.
0194      */
0195     bool copyTags(const QString& src,
0196                   const QString& dst,
0197                   unsigned char copyOps,
0198                   unsigned char writeModes = ExifToolProcess::ALL_MODES);
0199 
0200     /**
0201      * Translate group of tags in file.
0202      * @param transOps is a OR combination of ExifToolProcess::TranslateTagsOps values.
0203      */
0204     bool translateTags(const QString& path, unsigned char transOps);
0205 
0206     //@}
0207 
0208 public:
0209 
0210     //---------------------------------------------------------------------------------------------
0211     /// ExifTool Output Management Methods. See exiftoolparser_output.cpp for details
0212     //@{
0213 
0214     void cmdCompleted(const ExifToolProcess::Result& result);
0215 
0216     void errorOccurred(const ExifToolProcess::Result& result,
0217                        QProcess::ProcessError error,
0218                        const QString& description);
0219 
0220     void finished();
0221 
0222 public Q_SLOTS:
0223 
0224     void slotExifToolResult(int cmdId);
0225 
0226     //@}
0227 
0228 Q_SIGNALS:
0229 
0230     void signalExifToolDataAvailable();
0231     void signalExifToolAsyncData(const ExifToolParser::ExifToolData& map);
0232 
0233 public:
0234 
0235     /**
0236      * Unit-test method to check ExifTool stream parsing.
0237      */
0238     void setOutputStream(int cmdAction,
0239                          const QByteArray& cmdOutputChannel,
0240                          const QByteArray& cmdErrorChannel);
0241 
0242     /**
0243      * Helper conversion method to translate unordered tags database hash-table to ordered map.
0244      */
0245     static MetaEngine::TagsMap tagsDbToOrderedMap(const ExifToolData& tagsDb);
0246 
0247 private:
0248 
0249     void printExifToolOutput(const QByteArray& stdOut);
0250 
0251     //@}
0252 
0253 private:
0254 
0255     class Private;
0256     Private* const d;
0257 };
0258 
0259 } // namespace Digikam
0260 
0261 #endif // DIGIKAM_EXIFTOOL_PARSER_H