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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2006-02-23
0007  * Description : item metadata interface
0008  *
0009  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2006-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0011  * SPDX-FileCopyrightText: 2013      by Veaceslav Munteanu <veaceslav dot munteanu90 at gmail dot com>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #ifndef DIGIKAM_DMETA_DATA_H
0018 #define DIGIKAM_DMETA_DATA_H
0019 
0020 // Qt includes
0021 
0022 #include <QByteArray>
0023 #include <QUrl>
0024 
0025 // Local includes
0026 
0027 #include "digikam_config.h"
0028 #include "digikam_export.h"
0029 #include "metaengine.h"
0030 #include "metaengine_data.h"
0031 #include "metaenginesettingscontainer.h"
0032 #include "metadatainfo.h"
0033 #include "captionvalues.h"
0034 #include "photoinfocontainer.h"
0035 #include "videoinfocontainer.h"
0036 #include "dmetadatasettings.h"
0037 
0038 namespace Digikam
0039 {
0040 
0041 class Template;
0042 class IccProfile;
0043 
0044 // TODO: merge with MetaEngine class.
0045 
0046 class DIGIKAM_EXPORT DMetadata : public MetaEngine
0047 {
0048 
0049 public:
0050 
0051     /**
0052      * Video color model reported by FFMPEG following XMP DM Spec from Adobe.
0053      * These values are stored in DB as Image color model properties (extension of DImg::ColorModel)
0054      */
0055     enum VIDEOCOLORMODEL
0056     {
0057         VIDEOCOLORMODEL_UNKNOWN = 1000,
0058         VIDEOCOLORMODEL_OTHER,
0059         VIDEOCOLORMODEL_SRGB,
0060         VIDEOCOLORMODEL_BT709,
0061         VIDEOCOLORMODEL_BT601
0062     };
0063 
0064 public:
0065 
0066     typedef QMap<QString, QString> CountryCodeMap;
0067 
0068 public:
0069 
0070     DMetadata();
0071     explicit DMetadata(const QString& filePath);
0072     explicit DMetadata(const MetaEngineData& data);
0073     ~DMetadata();
0074 
0075 public: // Settings helpers
0076 
0077     void registerMetadataSettings();
0078     void setSettings(const MetaEngineSettingsContainer& settings);
0079 
0080 public: // File I/O helpers
0081 
0082     /**
0083      * Re-implemented from MetaEngine to use libraw identify, libheif,
0084      * ffmpeg probe, and ImageMAgick identify methods if Exiv2 failed.
0085      * If backend is non null, return the backend used to populate metadata (Exiv2).
0086      * See MetaEngine::Backend enum for details.
0087      */
0088     bool load(const QString& filePath, Backend* backend = nullptr);
0089     bool save(const QString& filePath, bool setVersion = false)                                                         const;
0090     bool applyChanges(bool setVersion = false)                                                                          const;
0091 
0092     /**
0093      * Try to extract metadata using Raw Engine identify method (libraw).
0094      */
0095     bool loadUsingRawEngine(const QString& filePath);
0096 
0097 public: // History helpers
0098 
0099     QString getItemHistory()                                                                                            const;
0100     bool    setItemHistory(const QString& imageHistoryXml)                                                              const;
0101     bool    hasItemHistoryTag()                                                                                         const;
0102 
0103     QString getItemUniqueId()                                                                                           const;
0104     bool    setItemUniqueId(const QString& uuid)                                                                        const;
0105 
0106 public: // Faces helpers
0107 
0108     /**
0109      * Get Images Face Map based on tags stored in Picassa/Metadatagroup
0110      * format.
0111      */
0112     bool getItemFacesMap(QMultiMap<QString, QVariant>& facesPath)                                                       const;
0113 
0114     /**
0115      * Set Images Face Map tags in Picassa/Metadatagroup format.
0116      *
0117      * @param write : if true all faces will be written, else update mode:
0118      *                search if at least a face tag exist and write if true.
0119      */
0120     bool setItemFacesMap(const QMultiMap<QString, QVariant>& facesPath, bool write, const QSize& size = QSize())       const;
0121 
0122     /**
0123      * Remove Images Face Map tags from Picassa/Metadatagroup format.
0124      */
0125     bool removeItemFacesMap()                                                                                           const;
0126 
0127 public: // Tags helpers
0128 
0129     bool getItemTagsPath(QStringList& tagsPath,
0130                          const DMetadataSettingsContainer& settings = DMetadataSettings::instance()->settings())        const;
0131     bool setItemTagsPath(const QStringList& tagsPath,
0132                          const DMetadataSettingsContainer& settings = DMetadataSettings::instance()->settings())        const;
0133 
0134     bool getACDSeeTagsPath(QStringList& tagsPath)                                                                       const;
0135 
0136     bool setACDSeeTagsPath(const QStringList& tagsPath)                                                                 const;
0137 
0138 public: // Comments helpers
0139 
0140     CaptionsMap getItemComments(const DMetadataSettingsContainer& settings = DMetadataSettings::instance()->settings()) const;
0141     bool setItemComments(const CaptionsMap& comments,
0142                          const DMetadataSettingsContainer& settings = DMetadataSettings::instance()->settings())        const;
0143 
0144     CaptionsMap getItemTitles(const DMetadataSettingsContainer& settings = DMetadataSettings::instance()->settings())   const;
0145     bool setItemTitles(const CaptionsMap& title,
0146                        const DMetadataSettingsContainer& settings = DMetadataSettings::instance()->settings())          const;
0147 
0148     static MetaEngine::AltLangMap toAltLangMap(const QVariant& var);
0149 
0150 public: // Labels helpers
0151 
0152     int  getItemRating(const DMetadataSettingsContainer& settings = DMetadataSettings::instance()->settings())          const;
0153     bool setItemRating(int rating,
0154                        const DMetadataSettingsContainer& settings = DMetadataSettings::instance()->settings())          const;
0155 
0156     int  getItemPickLabel()                                                                                             const;
0157     bool setItemPickLabel(int pickId)                                                                                   const;
0158 
0159     int  getItemColorLabel(const DMetadataSettingsContainer& settings = DMetadataSettings::instance()->settings())      const;
0160     bool setItemColorLabel(int colorId,
0161                            const DMetadataSettingsContainer& settings = DMetadataSettings::instance()->settings())      const;
0162 
0163 public: // Template helpers
0164 
0165     bool     setMetadataTemplate(const Template& t)                                                                     const;
0166     Template getMetadataTemplate()                                                                                      const;
0167     bool     removeMetadataTemplate()                                                                                   const;
0168 
0169     /**
0170      * Fills only the copyright values in the template. Use getMetadataTemplate() usually.
0171      * Returns true if valid fields were read.
0172      */
0173     bool getCopyrightInformation(Template& t)                                                                           const;
0174 
0175 public: // EXIF helpers
0176 
0177     /**
0178      * Reads an IccProfile that is described or embedded in the metadata.
0179      * This method does not retrieve profiles embedded in the image but from the Exif metadata,
0180      * e.g. embedded profiles in JPEG images.
0181      * Returns a null profile if no profile is found.
0182      */
0183     IccProfile getIccProfile()                                                                                          const;
0184 
0185     /**
0186      * Sets the IccProfile embedded in the Exif metadata.
0187      */
0188     bool setIccProfile(const IccProfile& profile);
0189 
0190     /**
0191      * Remove the Exif color space identification from the image.
0192      */
0193     bool removeExifColorSpace()                                                                                         const;
0194 
0195     /**
0196      * Returns millisecond time-stamp from Exif tags or 0 if not found.
0197      */
0198     int  getMSecsInfo()                                                                                                 const;
0199 
0200     /**
0201      * Extract milliseconds time-stamp of photo from an Exif tag and store it to 'ms'.
0202      * Returns true if data are extracted.
0203      */
0204     bool mSecTimeStamp(const char* const exifTagName, int& ms)                                                          const;
0205 
0206     bool removeExifTags(const QStringList& tagFilters);
0207 
0208 private:
0209 
0210     QString getExifTagStringFromTagsList(const QStringList& tagsList)                                                   const;
0211 
0212 public: // IPTC helpers
0213 
0214     IptcCoreContactInfo getCreatorContactInfo()                                                                         const;
0215     bool setCreatorContactInfo(const IptcCoreContactInfo& info)                                                         const;
0216 
0217     IptcCoreLocationInfo getIptcCoreLocation()                                                                          const;
0218     bool setIptcCoreLocation(const IptcCoreLocationInfo& location)                                                      const;
0219 
0220     QStringList getIptcCoreSubjects()                                                                                   const;
0221 
0222     bool removeIptcTags(const QStringList& tagFilters);
0223 
0224     /**
0225      * Return a map of ISO-639-1 2 letters country codes with country names.
0226      */
0227     static CountryCodeMap countryCodeMap();
0228 
0229     /**
0230      * Return a map of ISO-639-2 3 letters country codes with country names.
0231      */
0232     static CountryCodeMap countryCodeMap2();
0233 
0234 private:
0235 
0236     bool setIptcTag(const QString& text,
0237                     int maxLength,
0238                     const char* const debugLabel,
0239                     const char* const tagKey)                                                                           const;
0240 
0241     QVariant fromIptcEmulateList(const char* const iptcTagName)                                                         const;
0242     QVariant fromIptcEmulateLangAlt(const char* const iptcTagName)                                                      const;
0243 
0244 public: // XMP helpers
0245 
0246     /**
0247      * Set an Xmp tag content using a list of strings defined by the 'entriesToAdd' parameter.
0248      * The existing entries are preserved. The method will compare
0249      * all new with all already existing entries to prevent duplicates in the image.
0250      * Return true if the entries have been added to metadata.
0251      */
0252     bool addToXmpTagStringBag(const char* const xmpTagName, const QStringList& entriesToAdd)                            const;
0253 
0254     /**
0255      * Remove those Xmp tag entries that are listed in entriesToRemove from the entries in metadata.
0256      * Return true if tag entries are no longer contained in metadata.
0257      * All other entries are preserved.
0258      */
0259     bool removeFromXmpTagStringBag(const char* const xmpTagName, const QStringList& entriesToRemove)                    const;
0260 
0261     /**
0262      * Return a strings list of Xmp keywords from image. Return an empty list if no keyword are set.
0263      */
0264     QStringList getXmpKeywords()                                                                                        const;
0265 
0266     /**
0267      * Set Xmp keywords using a list of strings defined by 'newKeywords' parameter.
0268      * The existing keywords from image are preserved. The method will compare
0269      * all new keywords with all already existing keywords to prevent duplicate entries in image.
0270      * Return true if keywords have been changed in metadata.
0271      */
0272     bool setXmpKeywords(const QStringList& newKeywords)                                                                 const;
0273 
0274     /**
0275      * Remove those Xmp keywords that are listed in keywordsToRemove from the keywords in metadata.
0276      * Return true if keywords are no longer contained in metadata.
0277      */
0278     bool removeXmpKeywords(const QStringList& keywordsToRemove);
0279 
0280     /**
0281      * Return a strings list of Xmp subjects from image. Return an empty list if no subject are set.
0282      */
0283     QStringList getXmpSubjects()                                                                                        const;
0284 
0285     /**
0286      * Set Xmp subjects using a list of strings defined by 'newSubjects' parameter.
0287      * The existing subjects from image are preserved. The method will compare
0288      * all new subject with all already existing subject to prevent duplicate entries in image.
0289      * Return true if subjects have been changed in metadata.
0290      */
0291     bool setXmpSubjects(const QStringList& newSubjects)                                                                 const;
0292 
0293     /**
0294      * Remove those Xmp subjects that are listed in subjectsToRemove from the subjects in metadata.
0295      * Return true if subjects are no longer contained in metadata.
0296      */
0297     bool removeXmpSubjects(const QStringList& subjectsToRemove);
0298 
0299     /**
0300      * Return a strings list of Xmp sub-categories from image. Return an empty list if no sub-category
0301      * are set.
0302      */
0303     QStringList getXmpSubCategories()                                                                                   const;
0304 
0305     /**
0306      * Set Xmp sub-categories using a list of strings defined by 'newSubCategories' parameter.
0307      * The existing sub-categories from image are preserved. The method will compare
0308      * all new sub-categories with all already existing sub-categories to prevent duplicate entries in image.
0309      *  Return true if sub-categories have been changed in metadata.
0310      */
0311     bool setXmpSubCategories(const QStringList& newSubCategories)                                                       const;
0312 
0313     /**
0314      * Remove those Xmp sub-categories that are listed in categoriesToRemove from the sub-categories in metadata.
0315      * Return true if subjects are no longer contained in metadata.
0316      */
0317     bool removeXmpSubCategories(const QStringList& categoriesToRemove);
0318 
0319     bool removeXmpTags(const QStringList& tagFilters);
0320 
0321 private:
0322 
0323     QVariant fromXmpList(const char* const xmpTagName)                                                                  const;
0324     QVariant fromXmpLangAlt(const char* const xmpTagName)                                                               const;
0325 
0326 public: // Video helpers
0327 
0328     /**
0329      * Try to extract metadata using FFMpeg probe method (libav).
0330      */
0331     bool loadUsingFFmpeg(const QString& filePath);
0332 
0333     /**
0334      * Returns video metadata from Xmp tags.
0335      */
0336     VideoInfoContainer getVideoInformation()                                                                            const;
0337 
0338     /**
0339      * Helper method to translate enum values to user presentable strings
0340      */
0341     static QString videoColorModelToString(VIDEOCOLORMODEL videoColorModel);
0342 
0343 public: // Photo helpers
0344 
0345     /**
0346      * Return a string with Lens mounted on the front of camera.
0347      * There no standard Exif tag for Lens information.
0348      * Camera makernotes and Xmp tags are parsed.
0349      * Take a care : lens information are not standardized and string content is not homogeneous between
0350      * camera model/maker.
0351      */
0352     QString getLensDescription()                                                                                        const;
0353 
0354     /**
0355      * Return a string with Camera serial number.
0356      */
0357     QString getCameraSerialNumber()                                                                                     const;
0358 
0359     PhotoInfoContainer getPhotographInformation()                                                                       const;
0360 
0361     static double apexApertureToFNumber(double aperture);
0362     static double apexShutterSpeedToExposureTime(double shutterSpeed);
0363 
0364 public: // Generic helpers
0365 
0366     /**
0367      * Returns the requested metadata field as a QVariant. See metadatainfo.h for a specification
0368      * of the format of the QVariant.
0369      */
0370     QVariant     getMetadataField(MetadataInfo::Field field)                                                            const;
0371     QVariantList getMetadataFields(const MetadataFields& fields)                                                        const;
0372 
0373     /**
0374      * Convert a QVariant value of the specified field to a user-presentable, i18n'ed string.
0375      * The QVariant must be of the type as specified in metadatainfo.h and as obtained by getMetadataField.
0376      */
0377     static QString     valueToString (const QVariant& value, MetadataInfo::Field field);
0378     static QStringList valuesToString(const QVariantList& list, const MetadataFields& fields);
0379 
0380     /**
0381      * Returns a map of possible enum values and their user-presentable, i18n'ed representation.
0382      * Valid fields are those which are described as "enum from" or "bit mask from" in metadatainfo.h.
0383      */
0384     static QMap<int, QString> possibleValuesForEnumField(MetadataInfo::Field field);
0385 
0386 private:
0387 
0388     QVariant fromExifOrXmp(const char* const exifTagName, const char* const xmpTagName)                                 const;
0389     QVariant fromIptcOrXmp(const char* const iptcTagName, const char* const xmpTagName)                                 const;
0390     QVariant fromExifOrXmpList(const QStringList& tagList)                                                              const;
0391     bool hasValidField(const QVariantList& list)                                                                        const;
0392     QVariant toStringListVariant(const QStringList& list)                                                               const;
0393 
0394 #ifdef HAVE_HEIF
0395 
0396 private:
0397 
0398     /**
0399      * Libheif helper methods.
0400      */
0401     bool loadUsingLibheif(const QString& filePath);
0402 
0403 #endif
0404 
0405 private:
0406 
0407     /**
0408      * ImageMagick helper methods.
0409      */
0410     bool loadUsingImageMagick(const QString& filePath);
0411 
0412 private:
0413 
0414     /**
0415      * ExifTool helper methods.
0416      */
0417     bool loadUsingExifTool(const QString& filePath, bool merge = false);
0418     bool saveUsingExifTool(const QString& filePath) const;
0419 };
0420 
0421 } // namespace Digikam
0422 
0423 #endif // DIGIKAM_DMETA_DATA_H